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()?.to_str())
 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        if !user_requested
 7156            && (!self.should_show_edit_predictions()
 7157                || !self.is_focused(window)
 7158                || buffer.read(cx).is_empty())
 7159        {
 7160            self.discard_edit_prediction(false, cx);
 7161            return None;
 7162        }
 7163
 7164        self.update_visible_edit_prediction(window, cx);
 7165        provider.refresh(
 7166            self.project.clone(),
 7167            buffer,
 7168            cursor_buffer_position,
 7169            debounce,
 7170            cx,
 7171        );
 7172        Some(())
 7173    }
 7174
 7175    fn show_edit_predictions_in_menu(&self) -> bool {
 7176        match self.edit_prediction_settings {
 7177            EditPredictionSettings::Disabled => false,
 7178            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7179        }
 7180    }
 7181
 7182    pub fn edit_predictions_enabled(&self) -> bool {
 7183        match self.edit_prediction_settings {
 7184            EditPredictionSettings::Disabled => false,
 7185            EditPredictionSettings::Enabled { .. } => true,
 7186        }
 7187    }
 7188
 7189    fn edit_prediction_requires_modifier(&self) -> bool {
 7190        match self.edit_prediction_settings {
 7191            EditPredictionSettings::Disabled => false,
 7192            EditPredictionSettings::Enabled {
 7193                preview_requires_modifier,
 7194                ..
 7195            } => preview_requires_modifier,
 7196        }
 7197    }
 7198
 7199    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7200        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7201            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7202            self.discard_edit_prediction(false, cx);
 7203        } else {
 7204            let selection = self.selections.newest_anchor();
 7205            let cursor = selection.head();
 7206
 7207            if let Some((buffer, cursor_buffer_position)) =
 7208                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7209            {
 7210                self.edit_prediction_settings =
 7211                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7212            }
 7213        }
 7214    }
 7215
 7216    fn edit_prediction_settings_at_position(
 7217        &self,
 7218        buffer: &Entity<Buffer>,
 7219        buffer_position: language::Anchor,
 7220        cx: &App,
 7221    ) -> EditPredictionSettings {
 7222        if !self.mode.is_full()
 7223            || !self.show_edit_predictions_override.unwrap_or(true)
 7224            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7225        {
 7226            return EditPredictionSettings::Disabled;
 7227        }
 7228
 7229        let buffer = buffer.read(cx);
 7230
 7231        let file = buffer.file();
 7232
 7233        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7234            return EditPredictionSettings::Disabled;
 7235        };
 7236
 7237        let by_provider = matches!(
 7238            self.menu_edit_predictions_policy,
 7239            MenuEditPredictionsPolicy::ByProvider
 7240        );
 7241
 7242        let show_in_menu = by_provider
 7243            && self
 7244                .edit_prediction_provider
 7245                .as_ref()
 7246                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7247
 7248        let preview_requires_modifier =
 7249            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7250
 7251        EditPredictionSettings::Enabled {
 7252            show_in_menu,
 7253            preview_requires_modifier,
 7254        }
 7255    }
 7256
 7257    fn should_show_edit_predictions(&self) -> bool {
 7258        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7259    }
 7260
 7261    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7262        matches!(
 7263            self.edit_prediction_preview,
 7264            EditPredictionPreview::Active { .. }
 7265        )
 7266    }
 7267
 7268    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7269        let cursor = self.selections.newest_anchor().head();
 7270        if let Some((buffer, cursor_position)) =
 7271            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7272        {
 7273            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7274        } else {
 7275            false
 7276        }
 7277    }
 7278
 7279    pub fn supports_minimap(&self, cx: &App) -> bool {
 7280        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7281    }
 7282
 7283    fn edit_predictions_enabled_in_buffer(
 7284        &self,
 7285        buffer: &Entity<Buffer>,
 7286        buffer_position: language::Anchor,
 7287        cx: &App,
 7288    ) -> bool {
 7289        maybe!({
 7290            if self.read_only(cx) {
 7291                return Some(false);
 7292            }
 7293            let provider = self.edit_prediction_provider()?;
 7294            if !provider.is_enabled(buffer, buffer_position, cx) {
 7295                return Some(false);
 7296            }
 7297            let buffer = buffer.read(cx);
 7298            let Some(file) = buffer.file() else {
 7299                return Some(true);
 7300            };
 7301            let settings = all_language_settings(Some(file), cx);
 7302            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7303        })
 7304        .unwrap_or(false)
 7305    }
 7306
 7307    fn cycle_edit_prediction(
 7308        &mut self,
 7309        direction: Direction,
 7310        window: &mut Window,
 7311        cx: &mut Context<Self>,
 7312    ) -> Option<()> {
 7313        let provider = self.edit_prediction_provider()?;
 7314        let cursor = self.selections.newest_anchor().head();
 7315        let (buffer, cursor_buffer_position) =
 7316            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7317        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7318            return None;
 7319        }
 7320
 7321        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7322        self.update_visible_edit_prediction(window, cx);
 7323
 7324        Some(())
 7325    }
 7326
 7327    pub fn show_edit_prediction(
 7328        &mut self,
 7329        _: &ShowEditPrediction,
 7330        window: &mut Window,
 7331        cx: &mut Context<Self>,
 7332    ) {
 7333        if !self.has_active_edit_prediction() {
 7334            self.refresh_edit_prediction(false, true, window, cx);
 7335            return;
 7336        }
 7337
 7338        self.update_visible_edit_prediction(window, cx);
 7339    }
 7340
 7341    pub fn display_cursor_names(
 7342        &mut self,
 7343        _: &DisplayCursorNames,
 7344        window: &mut Window,
 7345        cx: &mut Context<Self>,
 7346    ) {
 7347        self.show_cursor_names(window, cx);
 7348    }
 7349
 7350    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7351        self.show_cursor_names = true;
 7352        cx.notify();
 7353        cx.spawn_in(window, async move |this, cx| {
 7354            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7355            this.update(cx, |this, cx| {
 7356                this.show_cursor_names = false;
 7357                cx.notify()
 7358            })
 7359            .ok()
 7360        })
 7361        .detach();
 7362    }
 7363
 7364    pub fn next_edit_prediction(
 7365        &mut self,
 7366        _: &NextEditPrediction,
 7367        window: &mut Window,
 7368        cx: &mut Context<Self>,
 7369    ) {
 7370        if self.has_active_edit_prediction() {
 7371            self.cycle_edit_prediction(Direction::Next, window, cx);
 7372        } else {
 7373            let is_copilot_disabled = self
 7374                .refresh_edit_prediction(false, true, window, cx)
 7375                .is_none();
 7376            if is_copilot_disabled {
 7377                cx.propagate();
 7378            }
 7379        }
 7380    }
 7381
 7382    pub fn previous_edit_prediction(
 7383        &mut self,
 7384        _: &PreviousEditPrediction,
 7385        window: &mut Window,
 7386        cx: &mut Context<Self>,
 7387    ) {
 7388        if self.has_active_edit_prediction() {
 7389            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7390        } else {
 7391            let is_copilot_disabled = self
 7392                .refresh_edit_prediction(false, true, window, cx)
 7393                .is_none();
 7394            if is_copilot_disabled {
 7395                cx.propagate();
 7396            }
 7397        }
 7398    }
 7399
 7400    pub fn accept_edit_prediction(
 7401        &mut self,
 7402        _: &AcceptEditPrediction,
 7403        window: &mut Window,
 7404        cx: &mut Context<Self>,
 7405    ) {
 7406        if self.show_edit_predictions_in_menu() {
 7407            self.hide_context_menu(window, cx);
 7408        }
 7409
 7410        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7411            return;
 7412        };
 7413
 7414        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7415
 7416        match &active_edit_prediction.completion {
 7417            EditPrediction::Move { target, .. } => {
 7418                let target = *target;
 7419
 7420                if let Some(position_map) = &self.last_position_map {
 7421                    if position_map
 7422                        .visible_row_range
 7423                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7424                        || !self.edit_prediction_requires_modifier()
 7425                    {
 7426                        self.unfold_ranges(&[target..target], true, false, cx);
 7427                        // Note that this is also done in vim's handler of the Tab action.
 7428                        self.change_selections(
 7429                            SelectionEffects::scroll(Autoscroll::newest()),
 7430                            window,
 7431                            cx,
 7432                            |selections| {
 7433                                selections.select_anchor_ranges([target..target]);
 7434                            },
 7435                        );
 7436                        self.clear_row_highlights::<EditPredictionPreview>();
 7437
 7438                        self.edit_prediction_preview
 7439                            .set_previous_scroll_position(None);
 7440                    } else {
 7441                        self.edit_prediction_preview
 7442                            .set_previous_scroll_position(Some(
 7443                                position_map.snapshot.scroll_anchor,
 7444                            ));
 7445
 7446                        self.highlight_rows::<EditPredictionPreview>(
 7447                            target..target,
 7448                            cx.theme().colors().editor_highlighted_line_background,
 7449                            RowHighlightOptions {
 7450                                autoscroll: true,
 7451                                ..Default::default()
 7452                            },
 7453                            cx,
 7454                        );
 7455                        self.request_autoscroll(Autoscroll::fit(), cx);
 7456                    }
 7457                }
 7458            }
 7459            EditPrediction::Edit { edits, .. } => {
 7460                if let Some(provider) = self.edit_prediction_provider() {
 7461                    provider.accept(cx);
 7462                }
 7463
 7464                // Store the transaction ID and selections before applying the edit
 7465                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7466
 7467                let snapshot = self.buffer.read(cx).snapshot(cx);
 7468                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7469
 7470                self.buffer.update(cx, |buffer, cx| {
 7471                    buffer.edit(edits.iter().cloned(), None, cx)
 7472                });
 7473
 7474                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7475                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7476                });
 7477
 7478                let selections = self.selections.disjoint_anchors_arc();
 7479                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7480                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7481                    if has_new_transaction {
 7482                        self.selection_history
 7483                            .insert_transaction(transaction_id_now, selections);
 7484                    }
 7485                }
 7486
 7487                self.update_visible_edit_prediction(window, cx);
 7488                if self.active_edit_prediction.is_none() {
 7489                    self.refresh_edit_prediction(true, true, window, cx);
 7490                }
 7491
 7492                cx.notify();
 7493            }
 7494        }
 7495
 7496        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7497    }
 7498
 7499    pub fn accept_partial_edit_prediction(
 7500        &mut self,
 7501        _: &AcceptPartialEditPrediction,
 7502        window: &mut Window,
 7503        cx: &mut Context<Self>,
 7504    ) {
 7505        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7506            return;
 7507        };
 7508        if self.selections.count() != 1 {
 7509            return;
 7510        }
 7511
 7512        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7513
 7514        match &active_edit_prediction.completion {
 7515            EditPrediction::Move { target, .. } => {
 7516                let target = *target;
 7517                self.change_selections(
 7518                    SelectionEffects::scroll(Autoscroll::newest()),
 7519                    window,
 7520                    cx,
 7521                    |selections| {
 7522                        selections.select_anchor_ranges([target..target]);
 7523                    },
 7524                );
 7525            }
 7526            EditPrediction::Edit { edits, .. } => {
 7527                // Find an insertion that starts at the cursor position.
 7528                let snapshot = self.buffer.read(cx).snapshot(cx);
 7529                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7530                let insertion = edits.iter().find_map(|(range, text)| {
 7531                    let range = range.to_offset(&snapshot);
 7532                    if range.is_empty() && range.start == cursor_offset {
 7533                        Some(text)
 7534                    } else {
 7535                        None
 7536                    }
 7537                });
 7538
 7539                if let Some(text) = insertion {
 7540                    let mut partial_completion = text
 7541                        .chars()
 7542                        .by_ref()
 7543                        .take_while(|c| c.is_alphabetic())
 7544                        .collect::<String>();
 7545                    if partial_completion.is_empty() {
 7546                        partial_completion = text
 7547                            .chars()
 7548                            .by_ref()
 7549                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7550                            .collect::<String>();
 7551                    }
 7552
 7553                    cx.emit(EditorEvent::InputHandled {
 7554                        utf16_range_to_replace: None,
 7555                        text: partial_completion.clone().into(),
 7556                    });
 7557
 7558                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7559
 7560                    self.refresh_edit_prediction(true, true, window, cx);
 7561                    cx.notify();
 7562                } else {
 7563                    self.accept_edit_prediction(&Default::default(), window, cx);
 7564                }
 7565            }
 7566        }
 7567    }
 7568
 7569    fn discard_edit_prediction(
 7570        &mut self,
 7571        should_report_edit_prediction_event: bool,
 7572        cx: &mut Context<Self>,
 7573    ) -> bool {
 7574        if should_report_edit_prediction_event {
 7575            let completion_id = self
 7576                .active_edit_prediction
 7577                .as_ref()
 7578                .and_then(|active_completion| active_completion.completion_id.clone());
 7579
 7580            self.report_edit_prediction_event(completion_id, false, cx);
 7581        }
 7582
 7583        if let Some(provider) = self.edit_prediction_provider() {
 7584            provider.discard(cx);
 7585        }
 7586
 7587        self.take_active_edit_prediction(cx)
 7588    }
 7589
 7590    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7591        let Some(provider) = self.edit_prediction_provider() else {
 7592            return;
 7593        };
 7594
 7595        let Some((_, buffer, _)) = self
 7596            .buffer
 7597            .read(cx)
 7598            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7599        else {
 7600            return;
 7601        };
 7602
 7603        let extension = buffer
 7604            .read(cx)
 7605            .file()
 7606            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7607
 7608        let event_type = match accepted {
 7609            true => "Edit Prediction Accepted",
 7610            false => "Edit Prediction Discarded",
 7611        };
 7612        telemetry::event!(
 7613            event_type,
 7614            provider = provider.name(),
 7615            prediction_id = id,
 7616            suggestion_accepted = accepted,
 7617            file_extension = extension,
 7618        );
 7619    }
 7620
 7621    pub fn has_active_edit_prediction(&self) -> bool {
 7622        self.active_edit_prediction.is_some()
 7623    }
 7624
 7625    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7626        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7627            return false;
 7628        };
 7629
 7630        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7631        self.clear_highlights::<EditPredictionHighlight>(cx);
 7632        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7633        true
 7634    }
 7635
 7636    /// Returns true when we're displaying the edit prediction popover below the cursor
 7637    /// like we are not previewing and the LSP autocomplete menu is visible
 7638    /// or we are in `when_holding_modifier` mode.
 7639    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7640        if self.edit_prediction_preview_is_active()
 7641            || !self.show_edit_predictions_in_menu()
 7642            || !self.edit_predictions_enabled()
 7643        {
 7644            return false;
 7645        }
 7646
 7647        if self.has_visible_completions_menu() {
 7648            return true;
 7649        }
 7650
 7651        has_completion && self.edit_prediction_requires_modifier()
 7652    }
 7653
 7654    fn handle_modifiers_changed(
 7655        &mut self,
 7656        modifiers: Modifiers,
 7657        position_map: &PositionMap,
 7658        window: &mut Window,
 7659        cx: &mut Context<Self>,
 7660    ) {
 7661        if self.show_edit_predictions_in_menu() {
 7662            self.update_edit_prediction_preview(&modifiers, window, cx);
 7663        }
 7664
 7665        self.update_selection_mode(&modifiers, position_map, window, cx);
 7666
 7667        let mouse_position = window.mouse_position();
 7668        if !position_map.text_hitbox.is_hovered(window) {
 7669            return;
 7670        }
 7671
 7672        self.update_hovered_link(
 7673            position_map.point_for_position(mouse_position),
 7674            &position_map.snapshot,
 7675            modifiers,
 7676            window,
 7677            cx,
 7678        )
 7679    }
 7680
 7681    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7682        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7683        if invert {
 7684            match multi_cursor_setting {
 7685                MultiCursorModifier::Alt => modifiers.alt,
 7686                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7687            }
 7688        } else {
 7689            match multi_cursor_setting {
 7690                MultiCursorModifier::Alt => modifiers.secondary(),
 7691                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7692            }
 7693        }
 7694    }
 7695
 7696    fn columnar_selection_mode(
 7697        modifiers: &Modifiers,
 7698        cx: &mut Context<Self>,
 7699    ) -> Option<ColumnarMode> {
 7700        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7701            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7702                Some(ColumnarMode::FromMouse)
 7703            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7704                Some(ColumnarMode::FromSelection)
 7705            } else {
 7706                None
 7707            }
 7708        } else {
 7709            None
 7710        }
 7711    }
 7712
 7713    fn update_selection_mode(
 7714        &mut self,
 7715        modifiers: &Modifiers,
 7716        position_map: &PositionMap,
 7717        window: &mut Window,
 7718        cx: &mut Context<Self>,
 7719    ) {
 7720        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7721            return;
 7722        };
 7723        if self.selections.pending_anchor().is_none() {
 7724            return;
 7725        }
 7726
 7727        let mouse_position = window.mouse_position();
 7728        let point_for_position = position_map.point_for_position(mouse_position);
 7729        let position = point_for_position.previous_valid;
 7730
 7731        self.select(
 7732            SelectPhase::BeginColumnar {
 7733                position,
 7734                reset: false,
 7735                mode,
 7736                goal_column: point_for_position.exact_unclipped.column(),
 7737            },
 7738            window,
 7739            cx,
 7740        );
 7741    }
 7742
 7743    fn update_edit_prediction_preview(
 7744        &mut self,
 7745        modifiers: &Modifiers,
 7746        window: &mut Window,
 7747        cx: &mut Context<Self>,
 7748    ) {
 7749        let mut modifiers_held = false;
 7750        if let Some(accept_keystroke) = self
 7751            .accept_edit_prediction_keybind(false, window, cx)
 7752            .keystroke()
 7753        {
 7754            modifiers_held = modifiers_held
 7755                || (accept_keystroke.modifiers() == modifiers
 7756                    && accept_keystroke.modifiers().modified());
 7757        };
 7758        if let Some(accept_partial_keystroke) = self
 7759            .accept_edit_prediction_keybind(true, window, cx)
 7760            .keystroke()
 7761        {
 7762            modifiers_held = modifiers_held
 7763                || (accept_partial_keystroke.modifiers() == modifiers
 7764                    && accept_partial_keystroke.modifiers().modified());
 7765        }
 7766
 7767        if modifiers_held {
 7768            if matches!(
 7769                self.edit_prediction_preview,
 7770                EditPredictionPreview::Inactive { .. }
 7771            ) {
 7772                self.edit_prediction_preview = EditPredictionPreview::Active {
 7773                    previous_scroll_position: None,
 7774                    since: Instant::now(),
 7775                };
 7776
 7777                self.update_visible_edit_prediction(window, cx);
 7778                cx.notify();
 7779            }
 7780        } else if let EditPredictionPreview::Active {
 7781            previous_scroll_position,
 7782            since,
 7783        } = self.edit_prediction_preview
 7784        {
 7785            if let (Some(previous_scroll_position), Some(position_map)) =
 7786                (previous_scroll_position, self.last_position_map.as_ref())
 7787            {
 7788                self.set_scroll_position(
 7789                    previous_scroll_position
 7790                        .scroll_position(&position_map.snapshot.display_snapshot),
 7791                    window,
 7792                    cx,
 7793                );
 7794            }
 7795
 7796            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7797                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7798            };
 7799            self.clear_row_highlights::<EditPredictionPreview>();
 7800            self.update_visible_edit_prediction(window, cx);
 7801            cx.notify();
 7802        }
 7803    }
 7804
 7805    fn update_visible_edit_prediction(
 7806        &mut self,
 7807        _window: &mut Window,
 7808        cx: &mut Context<Self>,
 7809    ) -> Option<()> {
 7810        if DisableAiSettings::get_global(cx).disable_ai {
 7811            return None;
 7812        }
 7813
 7814        if self.ime_transaction.is_some() {
 7815            self.discard_edit_prediction(false, cx);
 7816            return None;
 7817        }
 7818
 7819        let selection = self.selections.newest_anchor();
 7820        let cursor = selection.head();
 7821        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7822        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7823        let excerpt_id = cursor.excerpt_id;
 7824
 7825        let show_in_menu = self.show_edit_predictions_in_menu();
 7826        let completions_menu_has_precedence = !show_in_menu
 7827            && (self.context_menu.borrow().is_some()
 7828                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7829
 7830        if completions_menu_has_precedence
 7831            || !offset_selection.is_empty()
 7832            || self
 7833                .active_edit_prediction
 7834                .as_ref()
 7835                .is_some_and(|completion| {
 7836                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7837                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7838                    !invalidation_range.contains(&offset_selection.head())
 7839                })
 7840        {
 7841            self.discard_edit_prediction(false, cx);
 7842            return None;
 7843        }
 7844
 7845        self.take_active_edit_prediction(cx);
 7846        let Some(provider) = self.edit_prediction_provider() else {
 7847            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7848            return None;
 7849        };
 7850
 7851        let (buffer, cursor_buffer_position) =
 7852            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7853
 7854        self.edit_prediction_settings =
 7855            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7856
 7857        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7858            self.discard_edit_prediction(false, cx);
 7859            return None;
 7860        };
 7861
 7862        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7863
 7864        if self.edit_prediction_indent_conflict {
 7865            let cursor_point = cursor.to_point(&multibuffer);
 7866
 7867            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7868
 7869            if let Some((_, indent)) = indents.iter().next()
 7870                && indent.len == cursor_point.column
 7871            {
 7872                self.edit_prediction_indent_conflict = false;
 7873            }
 7874        }
 7875
 7876        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7877        let edits = edit_prediction
 7878            .edits
 7879            .into_iter()
 7880            .flat_map(|(range, new_text)| {
 7881                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7882                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7883                Some((start..end, new_text))
 7884            })
 7885            .collect::<Vec<_>>();
 7886        if edits.is_empty() {
 7887            return None;
 7888        }
 7889
 7890        let first_edit_start = edits.first().unwrap().0.start;
 7891        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7892        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7893
 7894        let last_edit_end = edits.last().unwrap().0.end;
 7895        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7896        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7897
 7898        let cursor_row = cursor.to_point(&multibuffer).row;
 7899
 7900        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7901
 7902        let mut inlay_ids = Vec::new();
 7903        let invalidation_row_range;
 7904        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7905            Some(cursor_row..edit_end_row)
 7906        } else if cursor_row > edit_end_row {
 7907            Some(edit_start_row..cursor_row)
 7908        } else {
 7909            None
 7910        };
 7911        let supports_jump = self
 7912            .edit_prediction_provider
 7913            .as_ref()
 7914            .map(|provider| provider.provider.supports_jump_to_edit())
 7915            .unwrap_or(true);
 7916
 7917        let is_move = supports_jump
 7918            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7919        let completion = if is_move {
 7920            invalidation_row_range =
 7921                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7922            let target = first_edit_start;
 7923            EditPrediction::Move { target, snapshot }
 7924        } else {
 7925            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7926                && !self.edit_predictions_hidden_for_vim_mode;
 7927
 7928            if show_completions_in_buffer {
 7929                if edits
 7930                    .iter()
 7931                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7932                {
 7933                    let mut inlays = Vec::new();
 7934                    for (range, new_text) in &edits {
 7935                        let inlay = Inlay::edit_prediction(
 7936                            post_inc(&mut self.next_inlay_id),
 7937                            range.start,
 7938                            new_text.as_str(),
 7939                        );
 7940                        inlay_ids.push(inlay.id);
 7941                        inlays.push(inlay);
 7942                    }
 7943
 7944                    self.splice_inlays(&[], inlays, cx);
 7945                } else {
 7946                    let background_color = cx.theme().status().deleted_background;
 7947                    self.highlight_text::<EditPredictionHighlight>(
 7948                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7949                        HighlightStyle {
 7950                            background_color: Some(background_color),
 7951                            ..Default::default()
 7952                        },
 7953                        cx,
 7954                    );
 7955                }
 7956            }
 7957
 7958            invalidation_row_range = edit_start_row..edit_end_row;
 7959
 7960            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7961                if provider.show_tab_accept_marker() {
 7962                    EditDisplayMode::TabAccept
 7963                } else {
 7964                    EditDisplayMode::Inline
 7965                }
 7966            } else {
 7967                EditDisplayMode::DiffPopover
 7968            };
 7969
 7970            EditPrediction::Edit {
 7971                edits,
 7972                edit_preview: edit_prediction.edit_preview,
 7973                display_mode,
 7974                snapshot,
 7975            }
 7976        };
 7977
 7978        let invalidation_range = multibuffer
 7979            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7980            ..multibuffer.anchor_after(Point::new(
 7981                invalidation_row_range.end,
 7982                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7983            ));
 7984
 7985        self.stale_edit_prediction_in_menu = None;
 7986        self.active_edit_prediction = Some(EditPredictionState {
 7987            inlay_ids,
 7988            completion,
 7989            completion_id: edit_prediction.id,
 7990            invalidation_range,
 7991        });
 7992
 7993        cx.notify();
 7994
 7995        Some(())
 7996    }
 7997
 7998    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7999        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8000    }
 8001
 8002    fn clear_tasks(&mut self) {
 8003        self.tasks.clear()
 8004    }
 8005
 8006    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8007        if self.tasks.insert(key, value).is_some() {
 8008            // This case should hopefully be rare, but just in case...
 8009            log::error!(
 8010                "multiple different run targets found on a single line, only the last target will be rendered"
 8011            )
 8012        }
 8013    }
 8014
 8015    /// Get all display points of breakpoints that will be rendered within editor
 8016    ///
 8017    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8018    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8019    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8020    fn active_breakpoints(
 8021        &self,
 8022        range: Range<DisplayRow>,
 8023        window: &mut Window,
 8024        cx: &mut Context<Self>,
 8025    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8026        let mut breakpoint_display_points = HashMap::default();
 8027
 8028        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8029            return breakpoint_display_points;
 8030        };
 8031
 8032        let snapshot = self.snapshot(window, cx);
 8033
 8034        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8035        let Some(project) = self.project() else {
 8036            return breakpoint_display_points;
 8037        };
 8038
 8039        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8040            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8041
 8042        for (buffer_snapshot, range, excerpt_id) in
 8043            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8044        {
 8045            let Some(buffer) = project
 8046                .read(cx)
 8047                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8048            else {
 8049                continue;
 8050            };
 8051            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8052                &buffer,
 8053                Some(
 8054                    buffer_snapshot.anchor_before(range.start)
 8055                        ..buffer_snapshot.anchor_after(range.end),
 8056                ),
 8057                buffer_snapshot,
 8058                cx,
 8059            );
 8060            for (breakpoint, state) in breakpoints {
 8061                let multi_buffer_anchor =
 8062                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8063                let position = multi_buffer_anchor
 8064                    .to_point(multi_buffer_snapshot)
 8065                    .to_display_point(&snapshot);
 8066
 8067                breakpoint_display_points.insert(
 8068                    position.row(),
 8069                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8070                );
 8071            }
 8072        }
 8073
 8074        breakpoint_display_points
 8075    }
 8076
 8077    fn breakpoint_context_menu(
 8078        &self,
 8079        anchor: Anchor,
 8080        window: &mut Window,
 8081        cx: &mut Context<Self>,
 8082    ) -> Entity<ui::ContextMenu> {
 8083        let weak_editor = cx.weak_entity();
 8084        let focus_handle = self.focus_handle(cx);
 8085
 8086        let row = self
 8087            .buffer
 8088            .read(cx)
 8089            .snapshot(cx)
 8090            .summary_for_anchor::<Point>(&anchor)
 8091            .row;
 8092
 8093        let breakpoint = self
 8094            .breakpoint_at_row(row, window, cx)
 8095            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8096
 8097        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8098            "Edit Log Breakpoint"
 8099        } else {
 8100            "Set Log Breakpoint"
 8101        };
 8102
 8103        let condition_breakpoint_msg = if breakpoint
 8104            .as_ref()
 8105            .is_some_and(|bp| bp.1.condition.is_some())
 8106        {
 8107            "Edit Condition Breakpoint"
 8108        } else {
 8109            "Set Condition Breakpoint"
 8110        };
 8111
 8112        let hit_condition_breakpoint_msg = if breakpoint
 8113            .as_ref()
 8114            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8115        {
 8116            "Edit Hit Condition Breakpoint"
 8117        } else {
 8118            "Set Hit Condition Breakpoint"
 8119        };
 8120
 8121        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8122            "Unset Breakpoint"
 8123        } else {
 8124            "Set Breakpoint"
 8125        };
 8126
 8127        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8128
 8129        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8130            BreakpointState::Enabled => Some("Disable"),
 8131            BreakpointState::Disabled => Some("Enable"),
 8132        });
 8133
 8134        let (anchor, breakpoint) =
 8135            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8136
 8137        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8138            menu.on_blur_subscription(Subscription::new(|| {}))
 8139                .context(focus_handle)
 8140                .when(run_to_cursor, |this| {
 8141                    let weak_editor = weak_editor.clone();
 8142                    this.entry("Run to cursor", None, move |window, cx| {
 8143                        weak_editor
 8144                            .update(cx, |editor, cx| {
 8145                                editor.change_selections(
 8146                                    SelectionEffects::no_scroll(),
 8147                                    window,
 8148                                    cx,
 8149                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8150                                );
 8151                            })
 8152                            .ok();
 8153
 8154                        window.dispatch_action(Box::new(RunToCursor), cx);
 8155                    })
 8156                    .separator()
 8157                })
 8158                .when_some(toggle_state_msg, |this, msg| {
 8159                    this.entry(msg, None, {
 8160                        let weak_editor = weak_editor.clone();
 8161                        let breakpoint = breakpoint.clone();
 8162                        move |_window, cx| {
 8163                            weak_editor
 8164                                .update(cx, |this, cx| {
 8165                                    this.edit_breakpoint_at_anchor(
 8166                                        anchor,
 8167                                        breakpoint.as_ref().clone(),
 8168                                        BreakpointEditAction::InvertState,
 8169                                        cx,
 8170                                    );
 8171                                })
 8172                                .log_err();
 8173                        }
 8174                    })
 8175                })
 8176                .entry(set_breakpoint_msg, None, {
 8177                    let weak_editor = weak_editor.clone();
 8178                    let breakpoint = breakpoint.clone();
 8179                    move |_window, cx| {
 8180                        weak_editor
 8181                            .update(cx, |this, cx| {
 8182                                this.edit_breakpoint_at_anchor(
 8183                                    anchor,
 8184                                    breakpoint.as_ref().clone(),
 8185                                    BreakpointEditAction::Toggle,
 8186                                    cx,
 8187                                );
 8188                            })
 8189                            .log_err();
 8190                    }
 8191                })
 8192                .entry(log_breakpoint_msg, None, {
 8193                    let breakpoint = breakpoint.clone();
 8194                    let weak_editor = weak_editor.clone();
 8195                    move |window, cx| {
 8196                        weak_editor
 8197                            .update(cx, |this, cx| {
 8198                                this.add_edit_breakpoint_block(
 8199                                    anchor,
 8200                                    breakpoint.as_ref(),
 8201                                    BreakpointPromptEditAction::Log,
 8202                                    window,
 8203                                    cx,
 8204                                );
 8205                            })
 8206                            .log_err();
 8207                    }
 8208                })
 8209                .entry(condition_breakpoint_msg, None, {
 8210                    let breakpoint = breakpoint.clone();
 8211                    let weak_editor = weak_editor.clone();
 8212                    move |window, cx| {
 8213                        weak_editor
 8214                            .update(cx, |this, cx| {
 8215                                this.add_edit_breakpoint_block(
 8216                                    anchor,
 8217                                    breakpoint.as_ref(),
 8218                                    BreakpointPromptEditAction::Condition,
 8219                                    window,
 8220                                    cx,
 8221                                );
 8222                            })
 8223                            .log_err();
 8224                    }
 8225                })
 8226                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8227                    weak_editor
 8228                        .update(cx, |this, cx| {
 8229                            this.add_edit_breakpoint_block(
 8230                                anchor,
 8231                                breakpoint.as_ref(),
 8232                                BreakpointPromptEditAction::HitCondition,
 8233                                window,
 8234                                cx,
 8235                            );
 8236                        })
 8237                        .log_err();
 8238                })
 8239        })
 8240    }
 8241
 8242    fn render_breakpoint(
 8243        &self,
 8244        position: Anchor,
 8245        row: DisplayRow,
 8246        breakpoint: &Breakpoint,
 8247        state: Option<BreakpointSessionState>,
 8248        cx: &mut Context<Self>,
 8249    ) -> IconButton {
 8250        let is_rejected = state.is_some_and(|s| !s.verified);
 8251        // Is it a breakpoint that shows up when hovering over gutter?
 8252        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8253            (false, false),
 8254            |PhantomBreakpointIndicator {
 8255                 is_active,
 8256                 display_row,
 8257                 collides_with_existing_breakpoint,
 8258             }| {
 8259                (
 8260                    is_active && display_row == row,
 8261                    collides_with_existing_breakpoint,
 8262                )
 8263            },
 8264        );
 8265
 8266        let (color, icon) = {
 8267            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8268                (false, false) => ui::IconName::DebugBreakpoint,
 8269                (true, false) => ui::IconName::DebugLogBreakpoint,
 8270                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8271                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8272            };
 8273
 8274            let color = if is_phantom {
 8275                Color::Hint
 8276            } else if is_rejected {
 8277                Color::Disabled
 8278            } else {
 8279                Color::Debugger
 8280            };
 8281
 8282            (color, icon)
 8283        };
 8284
 8285        let breakpoint = Arc::from(breakpoint.clone());
 8286
 8287        let alt_as_text = gpui::Keystroke {
 8288            modifiers: Modifiers::secondary_key(),
 8289            ..Default::default()
 8290        };
 8291        let primary_action_text = if breakpoint.is_disabled() {
 8292            "Enable breakpoint"
 8293        } else if is_phantom && !collides_with_existing {
 8294            "Set breakpoint"
 8295        } else {
 8296            "Unset breakpoint"
 8297        };
 8298        let focus_handle = self.focus_handle.clone();
 8299
 8300        let meta = if is_rejected {
 8301            SharedString::from("No executable code is associated with this line.")
 8302        } else if collides_with_existing && !breakpoint.is_disabled() {
 8303            SharedString::from(format!(
 8304                "{alt_as_text}-click to disable,\nright-click for more options."
 8305            ))
 8306        } else {
 8307            SharedString::from("Right-click for more options.")
 8308        };
 8309        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8310            .icon_size(IconSize::XSmall)
 8311            .size(ui::ButtonSize::None)
 8312            .when(is_rejected, |this| {
 8313                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8314            })
 8315            .icon_color(color)
 8316            .style(ButtonStyle::Transparent)
 8317            .on_click(cx.listener({
 8318                move |editor, event: &ClickEvent, window, cx| {
 8319                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8320                        BreakpointEditAction::InvertState
 8321                    } else {
 8322                        BreakpointEditAction::Toggle
 8323                    };
 8324
 8325                    window.focus(&editor.focus_handle(cx));
 8326                    editor.edit_breakpoint_at_anchor(
 8327                        position,
 8328                        breakpoint.as_ref().clone(),
 8329                        edit_action,
 8330                        cx,
 8331                    );
 8332                }
 8333            }))
 8334            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8335                editor.set_breakpoint_context_menu(
 8336                    row,
 8337                    Some(position),
 8338                    event.position(),
 8339                    window,
 8340                    cx,
 8341                );
 8342            }))
 8343            .tooltip(move |window, cx| {
 8344                Tooltip::with_meta_in(
 8345                    primary_action_text,
 8346                    Some(&ToggleBreakpoint),
 8347                    meta.clone(),
 8348                    &focus_handle,
 8349                    window,
 8350                    cx,
 8351                )
 8352            })
 8353    }
 8354
 8355    fn build_tasks_context(
 8356        project: &Entity<Project>,
 8357        buffer: &Entity<Buffer>,
 8358        buffer_row: u32,
 8359        tasks: &Arc<RunnableTasks>,
 8360        cx: &mut Context<Self>,
 8361    ) -> Task<Option<task::TaskContext>> {
 8362        let position = Point::new(buffer_row, tasks.column);
 8363        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8364        let location = Location {
 8365            buffer: buffer.clone(),
 8366            range: range_start..range_start,
 8367        };
 8368        // Fill in the environmental variables from the tree-sitter captures
 8369        let mut captured_task_variables = TaskVariables::default();
 8370        for (capture_name, value) in tasks.extra_variables.clone() {
 8371            captured_task_variables.insert(
 8372                task::VariableName::Custom(capture_name.into()),
 8373                value.clone(),
 8374            );
 8375        }
 8376        project.update(cx, |project, cx| {
 8377            project.task_store().update(cx, |task_store, cx| {
 8378                task_store.task_context_for_location(captured_task_variables, location, cx)
 8379            })
 8380        })
 8381    }
 8382
 8383    pub fn spawn_nearest_task(
 8384        &mut self,
 8385        action: &SpawnNearestTask,
 8386        window: &mut Window,
 8387        cx: &mut Context<Self>,
 8388    ) {
 8389        let Some((workspace, _)) = self.workspace.clone() else {
 8390            return;
 8391        };
 8392        let Some(project) = self.project.clone() else {
 8393            return;
 8394        };
 8395
 8396        // Try to find a closest, enclosing node using tree-sitter that has a task
 8397        let Some((buffer, buffer_row, tasks)) = self
 8398            .find_enclosing_node_task(cx)
 8399            // Or find the task that's closest in row-distance.
 8400            .or_else(|| self.find_closest_task(cx))
 8401        else {
 8402            return;
 8403        };
 8404
 8405        let reveal_strategy = action.reveal;
 8406        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8407        cx.spawn_in(window, async move |_, cx| {
 8408            let context = task_context.await?;
 8409            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8410
 8411            let resolved = &mut resolved_task.resolved;
 8412            resolved.reveal = reveal_strategy;
 8413
 8414            workspace
 8415                .update_in(cx, |workspace, window, cx| {
 8416                    workspace.schedule_resolved_task(
 8417                        task_source_kind,
 8418                        resolved_task,
 8419                        false,
 8420                        window,
 8421                        cx,
 8422                    );
 8423                })
 8424                .ok()
 8425        })
 8426        .detach();
 8427    }
 8428
 8429    fn find_closest_task(
 8430        &mut self,
 8431        cx: &mut Context<Self>,
 8432    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8433        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8434
 8435        let ((buffer_id, row), tasks) = self
 8436            .tasks
 8437            .iter()
 8438            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8439
 8440        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8441        let tasks = Arc::new(tasks.to_owned());
 8442        Some((buffer, *row, tasks))
 8443    }
 8444
 8445    fn find_enclosing_node_task(
 8446        &mut self,
 8447        cx: &mut Context<Self>,
 8448    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8449        let snapshot = self.buffer.read(cx).snapshot(cx);
 8450        let offset = self.selections.newest::<usize>(cx).head();
 8451        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8452        let buffer_id = excerpt.buffer().remote_id();
 8453
 8454        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8455        let mut cursor = layer.node().walk();
 8456
 8457        while cursor.goto_first_child_for_byte(offset).is_some() {
 8458            if cursor.node().end_byte() == offset {
 8459                cursor.goto_next_sibling();
 8460            }
 8461        }
 8462
 8463        // Ascend to the smallest ancestor that contains the range and has a task.
 8464        loop {
 8465            let node = cursor.node();
 8466            let node_range = node.byte_range();
 8467            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8468
 8469            // Check if this node contains our offset
 8470            if node_range.start <= offset && node_range.end >= offset {
 8471                // If it contains offset, check for task
 8472                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8473                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8474                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8475                }
 8476            }
 8477
 8478            if !cursor.goto_parent() {
 8479                break;
 8480            }
 8481        }
 8482        None
 8483    }
 8484
 8485    fn render_run_indicator(
 8486        &self,
 8487        _style: &EditorStyle,
 8488        is_active: bool,
 8489        row: DisplayRow,
 8490        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8491        cx: &mut Context<Self>,
 8492    ) -> IconButton {
 8493        let color = Color::Muted;
 8494        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8495
 8496        IconButton::new(
 8497            ("run_indicator", row.0 as usize),
 8498            ui::IconName::PlayOutlined,
 8499        )
 8500        .shape(ui::IconButtonShape::Square)
 8501        .icon_size(IconSize::XSmall)
 8502        .icon_color(color)
 8503        .toggle_state(is_active)
 8504        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8505            let quick_launch = match e {
 8506                ClickEvent::Keyboard(_) => true,
 8507                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8508            };
 8509
 8510            window.focus(&editor.focus_handle(cx));
 8511            editor.toggle_code_actions(
 8512                &ToggleCodeActions {
 8513                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8514                    quick_launch,
 8515                },
 8516                window,
 8517                cx,
 8518            );
 8519        }))
 8520        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8521            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8522        }))
 8523    }
 8524
 8525    pub fn context_menu_visible(&self) -> bool {
 8526        !self.edit_prediction_preview_is_active()
 8527            && self
 8528                .context_menu
 8529                .borrow()
 8530                .as_ref()
 8531                .is_some_and(|menu| menu.visible())
 8532    }
 8533
 8534    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8535        self.context_menu
 8536            .borrow()
 8537            .as_ref()
 8538            .map(|menu| menu.origin())
 8539    }
 8540
 8541    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8542        self.context_menu_options = Some(options);
 8543    }
 8544
 8545    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8546    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8547
 8548    fn render_edit_prediction_popover(
 8549        &mut self,
 8550        text_bounds: &Bounds<Pixels>,
 8551        content_origin: gpui::Point<Pixels>,
 8552        right_margin: Pixels,
 8553        editor_snapshot: &EditorSnapshot,
 8554        visible_row_range: Range<DisplayRow>,
 8555        scroll_top: f32,
 8556        scroll_bottom: f32,
 8557        line_layouts: &[LineWithInvisibles],
 8558        line_height: Pixels,
 8559        scroll_pixel_position: gpui::Point<Pixels>,
 8560        newest_selection_head: Option<DisplayPoint>,
 8561        editor_width: Pixels,
 8562        style: &EditorStyle,
 8563        window: &mut Window,
 8564        cx: &mut App,
 8565    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8566        if self.mode().is_minimap() {
 8567            return None;
 8568        }
 8569        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8570
 8571        if self.edit_prediction_visible_in_cursor_popover(true) {
 8572            return None;
 8573        }
 8574
 8575        match &active_edit_prediction.completion {
 8576            EditPrediction::Move { target, .. } => {
 8577                let target_display_point = target.to_display_point(editor_snapshot);
 8578
 8579                if self.edit_prediction_requires_modifier() {
 8580                    if !self.edit_prediction_preview_is_active() {
 8581                        return None;
 8582                    }
 8583
 8584                    self.render_edit_prediction_modifier_jump_popover(
 8585                        text_bounds,
 8586                        content_origin,
 8587                        visible_row_range,
 8588                        line_layouts,
 8589                        line_height,
 8590                        scroll_pixel_position,
 8591                        newest_selection_head,
 8592                        target_display_point,
 8593                        window,
 8594                        cx,
 8595                    )
 8596                } else {
 8597                    self.render_edit_prediction_eager_jump_popover(
 8598                        text_bounds,
 8599                        content_origin,
 8600                        editor_snapshot,
 8601                        visible_row_range,
 8602                        scroll_top,
 8603                        scroll_bottom,
 8604                        line_height,
 8605                        scroll_pixel_position,
 8606                        target_display_point,
 8607                        editor_width,
 8608                        window,
 8609                        cx,
 8610                    )
 8611                }
 8612            }
 8613            EditPrediction::Edit {
 8614                display_mode: EditDisplayMode::Inline,
 8615                ..
 8616            } => None,
 8617            EditPrediction::Edit {
 8618                display_mode: EditDisplayMode::TabAccept,
 8619                edits,
 8620                ..
 8621            } => {
 8622                let range = &edits.first()?.0;
 8623                let target_display_point = range.end.to_display_point(editor_snapshot);
 8624
 8625                self.render_edit_prediction_end_of_line_popover(
 8626                    "Accept",
 8627                    editor_snapshot,
 8628                    visible_row_range,
 8629                    target_display_point,
 8630                    line_height,
 8631                    scroll_pixel_position,
 8632                    content_origin,
 8633                    editor_width,
 8634                    window,
 8635                    cx,
 8636                )
 8637            }
 8638            EditPrediction::Edit {
 8639                edits,
 8640                edit_preview,
 8641                display_mode: EditDisplayMode::DiffPopover,
 8642                snapshot,
 8643            } => self.render_edit_prediction_diff_popover(
 8644                text_bounds,
 8645                content_origin,
 8646                right_margin,
 8647                editor_snapshot,
 8648                visible_row_range,
 8649                line_layouts,
 8650                line_height,
 8651                scroll_pixel_position,
 8652                newest_selection_head,
 8653                editor_width,
 8654                style,
 8655                edits,
 8656                edit_preview,
 8657                snapshot,
 8658                window,
 8659                cx,
 8660            ),
 8661        }
 8662    }
 8663
 8664    fn render_edit_prediction_modifier_jump_popover(
 8665        &mut self,
 8666        text_bounds: &Bounds<Pixels>,
 8667        content_origin: gpui::Point<Pixels>,
 8668        visible_row_range: Range<DisplayRow>,
 8669        line_layouts: &[LineWithInvisibles],
 8670        line_height: Pixels,
 8671        scroll_pixel_position: gpui::Point<Pixels>,
 8672        newest_selection_head: Option<DisplayPoint>,
 8673        target_display_point: DisplayPoint,
 8674        window: &mut Window,
 8675        cx: &mut App,
 8676    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8677        let scrolled_content_origin =
 8678            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8679
 8680        const SCROLL_PADDING_Y: Pixels = px(12.);
 8681
 8682        if target_display_point.row() < visible_row_range.start {
 8683            return self.render_edit_prediction_scroll_popover(
 8684                |_| SCROLL_PADDING_Y,
 8685                IconName::ArrowUp,
 8686                visible_row_range,
 8687                line_layouts,
 8688                newest_selection_head,
 8689                scrolled_content_origin,
 8690                window,
 8691                cx,
 8692            );
 8693        } else if target_display_point.row() >= visible_row_range.end {
 8694            return self.render_edit_prediction_scroll_popover(
 8695                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8696                IconName::ArrowDown,
 8697                visible_row_range,
 8698                line_layouts,
 8699                newest_selection_head,
 8700                scrolled_content_origin,
 8701                window,
 8702                cx,
 8703            );
 8704        }
 8705
 8706        const POLE_WIDTH: Pixels = px(2.);
 8707
 8708        let line_layout =
 8709            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8710        let target_column = target_display_point.column() as usize;
 8711
 8712        let target_x = line_layout.x_for_index(target_column);
 8713        let target_y =
 8714            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8715
 8716        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8717
 8718        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8719        border_color.l += 0.001;
 8720
 8721        let mut element = v_flex()
 8722            .items_end()
 8723            .when(flag_on_right, |el| el.items_start())
 8724            .child(if flag_on_right {
 8725                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8726                    .rounded_bl(px(0.))
 8727                    .rounded_tl(px(0.))
 8728                    .border_l_2()
 8729                    .border_color(border_color)
 8730            } else {
 8731                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8732                    .rounded_br(px(0.))
 8733                    .rounded_tr(px(0.))
 8734                    .border_r_2()
 8735                    .border_color(border_color)
 8736            })
 8737            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8738            .into_any();
 8739
 8740        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8741
 8742        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8743            - point(
 8744                if flag_on_right {
 8745                    POLE_WIDTH
 8746                } else {
 8747                    size.width - POLE_WIDTH
 8748                },
 8749                size.height - line_height,
 8750            );
 8751
 8752        origin.x = origin.x.max(content_origin.x);
 8753
 8754        element.prepaint_at(origin, window, cx);
 8755
 8756        Some((element, origin))
 8757    }
 8758
 8759    fn render_edit_prediction_scroll_popover(
 8760        &mut self,
 8761        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8762        scroll_icon: IconName,
 8763        visible_row_range: Range<DisplayRow>,
 8764        line_layouts: &[LineWithInvisibles],
 8765        newest_selection_head: Option<DisplayPoint>,
 8766        scrolled_content_origin: gpui::Point<Pixels>,
 8767        window: &mut Window,
 8768        cx: &mut App,
 8769    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8770        let mut element = self
 8771            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8772            .into_any();
 8773
 8774        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8775
 8776        let cursor = newest_selection_head?;
 8777        let cursor_row_layout =
 8778            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8779        let cursor_column = cursor.column() as usize;
 8780
 8781        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8782
 8783        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8784
 8785        element.prepaint_at(origin, window, cx);
 8786        Some((element, origin))
 8787    }
 8788
 8789    fn render_edit_prediction_eager_jump_popover(
 8790        &mut self,
 8791        text_bounds: &Bounds<Pixels>,
 8792        content_origin: gpui::Point<Pixels>,
 8793        editor_snapshot: &EditorSnapshot,
 8794        visible_row_range: Range<DisplayRow>,
 8795        scroll_top: f32,
 8796        scroll_bottom: f32,
 8797        line_height: Pixels,
 8798        scroll_pixel_position: gpui::Point<Pixels>,
 8799        target_display_point: DisplayPoint,
 8800        editor_width: Pixels,
 8801        window: &mut Window,
 8802        cx: &mut App,
 8803    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8804        if target_display_point.row().as_f32() < scroll_top {
 8805            let mut element = self
 8806                .render_edit_prediction_line_popover(
 8807                    "Jump to Edit",
 8808                    Some(IconName::ArrowUp),
 8809                    window,
 8810                    cx,
 8811                )?
 8812                .into_any();
 8813
 8814            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8815            let offset = point(
 8816                (text_bounds.size.width - size.width) / 2.,
 8817                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8818            );
 8819
 8820            let origin = text_bounds.origin + offset;
 8821            element.prepaint_at(origin, window, cx);
 8822            Some((element, origin))
 8823        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8824            let mut element = self
 8825                .render_edit_prediction_line_popover(
 8826                    "Jump to Edit",
 8827                    Some(IconName::ArrowDown),
 8828                    window,
 8829                    cx,
 8830                )?
 8831                .into_any();
 8832
 8833            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8834            let offset = point(
 8835                (text_bounds.size.width - size.width) / 2.,
 8836                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8837            );
 8838
 8839            let origin = text_bounds.origin + offset;
 8840            element.prepaint_at(origin, window, cx);
 8841            Some((element, origin))
 8842        } else {
 8843            self.render_edit_prediction_end_of_line_popover(
 8844                "Jump to Edit",
 8845                editor_snapshot,
 8846                visible_row_range,
 8847                target_display_point,
 8848                line_height,
 8849                scroll_pixel_position,
 8850                content_origin,
 8851                editor_width,
 8852                window,
 8853                cx,
 8854            )
 8855        }
 8856    }
 8857
 8858    fn render_edit_prediction_end_of_line_popover(
 8859        self: &mut Editor,
 8860        label: &'static str,
 8861        editor_snapshot: &EditorSnapshot,
 8862        visible_row_range: Range<DisplayRow>,
 8863        target_display_point: DisplayPoint,
 8864        line_height: Pixels,
 8865        scroll_pixel_position: gpui::Point<Pixels>,
 8866        content_origin: gpui::Point<Pixels>,
 8867        editor_width: Pixels,
 8868        window: &mut Window,
 8869        cx: &mut App,
 8870    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8871        let target_line_end = DisplayPoint::new(
 8872            target_display_point.row(),
 8873            editor_snapshot.line_len(target_display_point.row()),
 8874        );
 8875
 8876        let mut element = self
 8877            .render_edit_prediction_line_popover(label, None, window, cx)?
 8878            .into_any();
 8879
 8880        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8881
 8882        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8883
 8884        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8885        let mut origin = start_point
 8886            + line_origin
 8887            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8888        origin.x = origin.x.max(content_origin.x);
 8889
 8890        let max_x = content_origin.x + editor_width - size.width;
 8891
 8892        if origin.x > max_x {
 8893            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8894
 8895            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8896                origin.y += offset;
 8897                IconName::ArrowUp
 8898            } else {
 8899                origin.y -= offset;
 8900                IconName::ArrowDown
 8901            };
 8902
 8903            element = self
 8904                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8905                .into_any();
 8906
 8907            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8908
 8909            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8910        }
 8911
 8912        element.prepaint_at(origin, window, cx);
 8913        Some((element, origin))
 8914    }
 8915
 8916    fn render_edit_prediction_diff_popover(
 8917        self: &Editor,
 8918        text_bounds: &Bounds<Pixels>,
 8919        content_origin: gpui::Point<Pixels>,
 8920        right_margin: Pixels,
 8921        editor_snapshot: &EditorSnapshot,
 8922        visible_row_range: Range<DisplayRow>,
 8923        line_layouts: &[LineWithInvisibles],
 8924        line_height: Pixels,
 8925        scroll_pixel_position: gpui::Point<Pixels>,
 8926        newest_selection_head: Option<DisplayPoint>,
 8927        editor_width: Pixels,
 8928        style: &EditorStyle,
 8929        edits: &Vec<(Range<Anchor>, String)>,
 8930        edit_preview: &Option<language::EditPreview>,
 8931        snapshot: &language::BufferSnapshot,
 8932        window: &mut Window,
 8933        cx: &mut App,
 8934    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8935        let edit_start = edits
 8936            .first()
 8937            .unwrap()
 8938            .0
 8939            .start
 8940            .to_display_point(editor_snapshot);
 8941        let edit_end = edits
 8942            .last()
 8943            .unwrap()
 8944            .0
 8945            .end
 8946            .to_display_point(editor_snapshot);
 8947
 8948        let is_visible = visible_row_range.contains(&edit_start.row())
 8949            || visible_row_range.contains(&edit_end.row());
 8950        if !is_visible {
 8951            return None;
 8952        }
 8953
 8954        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8955            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8956        } else {
 8957            // Fallback for providers without edit_preview
 8958            crate::edit_prediction_fallback_text(edits, cx)
 8959        };
 8960
 8961        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8962        let line_count = highlighted_edits.text.lines().count();
 8963
 8964        const BORDER_WIDTH: Pixels = px(1.);
 8965
 8966        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8967        let has_keybind = keybind.is_some();
 8968
 8969        let mut element = h_flex()
 8970            .items_start()
 8971            .child(
 8972                h_flex()
 8973                    .bg(cx.theme().colors().editor_background)
 8974                    .border(BORDER_WIDTH)
 8975                    .shadow_xs()
 8976                    .border_color(cx.theme().colors().border)
 8977                    .rounded_l_lg()
 8978                    .when(line_count > 1, |el| el.rounded_br_lg())
 8979                    .pr_1()
 8980                    .child(styled_text),
 8981            )
 8982            .child(
 8983                h_flex()
 8984                    .h(line_height + BORDER_WIDTH * 2.)
 8985                    .px_1p5()
 8986                    .gap_1()
 8987                    // Workaround: For some reason, there's a gap if we don't do this
 8988                    .ml(-BORDER_WIDTH)
 8989                    .shadow(vec![gpui::BoxShadow {
 8990                        color: gpui::black().opacity(0.05),
 8991                        offset: point(px(1.), px(1.)),
 8992                        blur_radius: px(2.),
 8993                        spread_radius: px(0.),
 8994                    }])
 8995                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8996                    .border(BORDER_WIDTH)
 8997                    .border_color(cx.theme().colors().border)
 8998                    .rounded_r_lg()
 8999                    .id("edit_prediction_diff_popover_keybind")
 9000                    .when(!has_keybind, |el| {
 9001                        let status_colors = cx.theme().status();
 9002
 9003                        el.bg(status_colors.error_background)
 9004                            .border_color(status_colors.error.opacity(0.6))
 9005                            .child(Icon::new(IconName::Info).color(Color::Error))
 9006                            .cursor_default()
 9007                            .hoverable_tooltip(move |_window, cx| {
 9008                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9009                            })
 9010                    })
 9011                    .children(keybind),
 9012            )
 9013            .into_any();
 9014
 9015        let longest_row =
 9016            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9017        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9018            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9019        } else {
 9020            layout_line(
 9021                longest_row,
 9022                editor_snapshot,
 9023                style,
 9024                editor_width,
 9025                |_| false,
 9026                window,
 9027                cx,
 9028            )
 9029            .width
 9030        };
 9031
 9032        let viewport_bounds =
 9033            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9034                right: -right_margin,
 9035                ..Default::default()
 9036            });
 9037
 9038        let x_after_longest =
 9039            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9040                - scroll_pixel_position.x;
 9041
 9042        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9043
 9044        // Fully visible if it can be displayed within the window (allow overlapping other
 9045        // panes). However, this is only allowed if the popover starts within text_bounds.
 9046        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9047            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9048
 9049        let mut origin = if can_position_to_the_right {
 9050            point(
 9051                x_after_longest,
 9052                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9053                    - scroll_pixel_position.y,
 9054            )
 9055        } else {
 9056            let cursor_row = newest_selection_head.map(|head| head.row());
 9057            let above_edit = edit_start
 9058                .row()
 9059                .0
 9060                .checked_sub(line_count as u32)
 9061                .map(DisplayRow);
 9062            let below_edit = Some(edit_end.row() + 1);
 9063            let above_cursor =
 9064                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9065            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9066
 9067            // Place the edit popover adjacent to the edit if there is a location
 9068            // available that is onscreen and does not obscure the cursor. Otherwise,
 9069            // place it adjacent to the cursor.
 9070            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9071                .into_iter()
 9072                .flatten()
 9073                .find(|&start_row| {
 9074                    let end_row = start_row + line_count as u32;
 9075                    visible_row_range.contains(&start_row)
 9076                        && visible_row_range.contains(&end_row)
 9077                        && cursor_row
 9078                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9079                })?;
 9080
 9081            content_origin
 9082                + point(
 9083                    -scroll_pixel_position.x,
 9084                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9085                )
 9086        };
 9087
 9088        origin.x -= BORDER_WIDTH;
 9089
 9090        window.defer_draw(element, origin, 1);
 9091
 9092        // Do not return an element, since it will already be drawn due to defer_draw.
 9093        None
 9094    }
 9095
 9096    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9097        px(30.)
 9098    }
 9099
 9100    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9101        if self.read_only(cx) {
 9102            cx.theme().players().read_only()
 9103        } else {
 9104            self.style.as_ref().unwrap().local_player
 9105        }
 9106    }
 9107
 9108    fn render_edit_prediction_accept_keybind(
 9109        &self,
 9110        window: &mut Window,
 9111        cx: &App,
 9112    ) -> Option<AnyElement> {
 9113        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9114        let accept_keystroke = accept_binding.keystroke()?;
 9115
 9116        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9117
 9118        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9119            Color::Accent
 9120        } else {
 9121            Color::Muted
 9122        };
 9123
 9124        h_flex()
 9125            .px_0p5()
 9126            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9127            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9128            .text_size(TextSize::XSmall.rems(cx))
 9129            .child(h_flex().children(ui::render_modifiers(
 9130                accept_keystroke.modifiers(),
 9131                PlatformStyle::platform(),
 9132                Some(modifiers_color),
 9133                Some(IconSize::XSmall.rems().into()),
 9134                true,
 9135            )))
 9136            .when(is_platform_style_mac, |parent| {
 9137                parent.child(accept_keystroke.key().to_string())
 9138            })
 9139            .when(!is_platform_style_mac, |parent| {
 9140                parent.child(
 9141                    Key::new(
 9142                        util::capitalize(accept_keystroke.key()),
 9143                        Some(Color::Default),
 9144                    )
 9145                    .size(Some(IconSize::XSmall.rems().into())),
 9146                )
 9147            })
 9148            .into_any()
 9149            .into()
 9150    }
 9151
 9152    fn render_edit_prediction_line_popover(
 9153        &self,
 9154        label: impl Into<SharedString>,
 9155        icon: Option<IconName>,
 9156        window: &mut Window,
 9157        cx: &App,
 9158    ) -> Option<Stateful<Div>> {
 9159        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9160
 9161        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9162        let has_keybind = keybind.is_some();
 9163
 9164        let result = h_flex()
 9165            .id("ep-line-popover")
 9166            .py_0p5()
 9167            .pl_1()
 9168            .pr(padding_right)
 9169            .gap_1()
 9170            .rounded_md()
 9171            .border_1()
 9172            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9173            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9174            .shadow_xs()
 9175            .when(!has_keybind, |el| {
 9176                let status_colors = cx.theme().status();
 9177
 9178                el.bg(status_colors.error_background)
 9179                    .border_color(status_colors.error.opacity(0.6))
 9180                    .pl_2()
 9181                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9182                    .cursor_default()
 9183                    .hoverable_tooltip(move |_window, cx| {
 9184                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9185                    })
 9186            })
 9187            .children(keybind)
 9188            .child(
 9189                Label::new(label)
 9190                    .size(LabelSize::Small)
 9191                    .when(!has_keybind, |el| {
 9192                        el.color(cx.theme().status().error.into()).strikethrough()
 9193                    }),
 9194            )
 9195            .when(!has_keybind, |el| {
 9196                el.child(
 9197                    h_flex().ml_1().child(
 9198                        Icon::new(IconName::Info)
 9199                            .size(IconSize::Small)
 9200                            .color(cx.theme().status().error.into()),
 9201                    ),
 9202                )
 9203            })
 9204            .when_some(icon, |element, icon| {
 9205                element.child(
 9206                    div()
 9207                        .mt(px(1.5))
 9208                        .child(Icon::new(icon).size(IconSize::Small)),
 9209                )
 9210            });
 9211
 9212        Some(result)
 9213    }
 9214
 9215    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9216        let accent_color = cx.theme().colors().text_accent;
 9217        let editor_bg_color = cx.theme().colors().editor_background;
 9218        editor_bg_color.blend(accent_color.opacity(0.1))
 9219    }
 9220
 9221    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9222        let accent_color = cx.theme().colors().text_accent;
 9223        let editor_bg_color = cx.theme().colors().editor_background;
 9224        editor_bg_color.blend(accent_color.opacity(0.6))
 9225    }
 9226    fn get_prediction_provider_icon_name(
 9227        provider: &Option<RegisteredEditPredictionProvider>,
 9228    ) -> IconName {
 9229        match provider {
 9230            Some(provider) => match provider.provider.name() {
 9231                "copilot" => IconName::Copilot,
 9232                "supermaven" => IconName::Supermaven,
 9233                _ => IconName::ZedPredict,
 9234            },
 9235            None => IconName::ZedPredict,
 9236        }
 9237    }
 9238
 9239    fn render_edit_prediction_cursor_popover(
 9240        &self,
 9241        min_width: Pixels,
 9242        max_width: Pixels,
 9243        cursor_point: Point,
 9244        style: &EditorStyle,
 9245        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9246        _window: &Window,
 9247        cx: &mut Context<Editor>,
 9248    ) -> Option<AnyElement> {
 9249        let provider = self.edit_prediction_provider.as_ref()?;
 9250        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9251
 9252        let is_refreshing = provider.provider.is_refreshing(cx);
 9253
 9254        fn pending_completion_container(icon: IconName) -> Div {
 9255            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9256        }
 9257
 9258        let completion = match &self.active_edit_prediction {
 9259            Some(prediction) => {
 9260                if !self.has_visible_completions_menu() {
 9261                    const RADIUS: Pixels = px(6.);
 9262                    const BORDER_WIDTH: Pixels = px(1.);
 9263
 9264                    return Some(
 9265                        h_flex()
 9266                            .elevation_2(cx)
 9267                            .border(BORDER_WIDTH)
 9268                            .border_color(cx.theme().colors().border)
 9269                            .when(accept_keystroke.is_none(), |el| {
 9270                                el.border_color(cx.theme().status().error)
 9271                            })
 9272                            .rounded(RADIUS)
 9273                            .rounded_tl(px(0.))
 9274                            .overflow_hidden()
 9275                            .child(div().px_1p5().child(match &prediction.completion {
 9276                                EditPrediction::Move { target, snapshot } => {
 9277                                    use text::ToPoint as _;
 9278                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9279                                    {
 9280                                        Icon::new(IconName::ZedPredictDown)
 9281                                    } else {
 9282                                        Icon::new(IconName::ZedPredictUp)
 9283                                    }
 9284                                }
 9285                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9286                            }))
 9287                            .child(
 9288                                h_flex()
 9289                                    .gap_1()
 9290                                    .py_1()
 9291                                    .px_2()
 9292                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9293                                    .border_l_1()
 9294                                    .border_color(cx.theme().colors().border)
 9295                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9296                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9297                                        el.child(
 9298                                            Label::new("Hold")
 9299                                                .size(LabelSize::Small)
 9300                                                .when(accept_keystroke.is_none(), |el| {
 9301                                                    el.strikethrough()
 9302                                                })
 9303                                                .line_height_style(LineHeightStyle::UiLabel),
 9304                                        )
 9305                                    })
 9306                                    .id("edit_prediction_cursor_popover_keybind")
 9307                                    .when(accept_keystroke.is_none(), |el| {
 9308                                        let status_colors = cx.theme().status();
 9309
 9310                                        el.bg(status_colors.error_background)
 9311                                            .border_color(status_colors.error.opacity(0.6))
 9312                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9313                                            .cursor_default()
 9314                                            .hoverable_tooltip(move |_window, cx| {
 9315                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9316                                                    .into()
 9317                                            })
 9318                                    })
 9319                                    .when_some(
 9320                                        accept_keystroke.as_ref(),
 9321                                        |el, accept_keystroke| {
 9322                                            el.child(h_flex().children(ui::render_modifiers(
 9323                                                accept_keystroke.modifiers(),
 9324                                                PlatformStyle::platform(),
 9325                                                Some(Color::Default),
 9326                                                Some(IconSize::XSmall.rems().into()),
 9327                                                false,
 9328                                            )))
 9329                                        },
 9330                                    ),
 9331                            )
 9332                            .into_any(),
 9333                    );
 9334                }
 9335
 9336                self.render_edit_prediction_cursor_popover_preview(
 9337                    prediction,
 9338                    cursor_point,
 9339                    style,
 9340                    cx,
 9341                )?
 9342            }
 9343
 9344            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9345                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9346                    stale_completion,
 9347                    cursor_point,
 9348                    style,
 9349                    cx,
 9350                )?,
 9351
 9352                None => pending_completion_container(provider_icon)
 9353                    .child(Label::new("...").size(LabelSize::Small)),
 9354            },
 9355
 9356            None => pending_completion_container(provider_icon)
 9357                .child(Label::new("...").size(LabelSize::Small)),
 9358        };
 9359
 9360        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9361            completion
 9362                .with_animation(
 9363                    "loading-completion",
 9364                    Animation::new(Duration::from_secs(2))
 9365                        .repeat()
 9366                        .with_easing(pulsating_between(0.4, 0.8)),
 9367                    |label, delta| label.opacity(delta),
 9368                )
 9369                .into_any_element()
 9370        } else {
 9371            completion.into_any_element()
 9372        };
 9373
 9374        let has_completion = self.active_edit_prediction.is_some();
 9375
 9376        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9377        Some(
 9378            h_flex()
 9379                .min_w(min_width)
 9380                .max_w(max_width)
 9381                .flex_1()
 9382                .elevation_2(cx)
 9383                .border_color(cx.theme().colors().border)
 9384                .child(
 9385                    div()
 9386                        .flex_1()
 9387                        .py_1()
 9388                        .px_2()
 9389                        .overflow_hidden()
 9390                        .child(completion),
 9391                )
 9392                .when_some(accept_keystroke, |el, accept_keystroke| {
 9393                    if !accept_keystroke.modifiers().modified() {
 9394                        return el;
 9395                    }
 9396
 9397                    el.child(
 9398                        h_flex()
 9399                            .h_full()
 9400                            .border_l_1()
 9401                            .rounded_r_lg()
 9402                            .border_color(cx.theme().colors().border)
 9403                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9404                            .gap_1()
 9405                            .py_1()
 9406                            .px_2()
 9407                            .child(
 9408                                h_flex()
 9409                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9410                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9411                                    .child(h_flex().children(ui::render_modifiers(
 9412                                        accept_keystroke.modifiers(),
 9413                                        PlatformStyle::platform(),
 9414                                        Some(if !has_completion {
 9415                                            Color::Muted
 9416                                        } else {
 9417                                            Color::Default
 9418                                        }),
 9419                                        None,
 9420                                        false,
 9421                                    ))),
 9422                            )
 9423                            .child(Label::new("Preview").into_any_element())
 9424                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9425                    )
 9426                })
 9427                .into_any(),
 9428        )
 9429    }
 9430
 9431    fn render_edit_prediction_cursor_popover_preview(
 9432        &self,
 9433        completion: &EditPredictionState,
 9434        cursor_point: Point,
 9435        style: &EditorStyle,
 9436        cx: &mut Context<Editor>,
 9437    ) -> Option<Div> {
 9438        use text::ToPoint as _;
 9439
 9440        fn render_relative_row_jump(
 9441            prefix: impl Into<String>,
 9442            current_row: u32,
 9443            target_row: u32,
 9444        ) -> Div {
 9445            let (row_diff, arrow) = if target_row < current_row {
 9446                (current_row - target_row, IconName::ArrowUp)
 9447            } else {
 9448                (target_row - current_row, IconName::ArrowDown)
 9449            };
 9450
 9451            h_flex()
 9452                .child(
 9453                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9454                        .color(Color::Muted)
 9455                        .size(LabelSize::Small),
 9456                )
 9457                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9458        }
 9459
 9460        let supports_jump = self
 9461            .edit_prediction_provider
 9462            .as_ref()
 9463            .map(|provider| provider.provider.supports_jump_to_edit())
 9464            .unwrap_or(true);
 9465
 9466        match &completion.completion {
 9467            EditPrediction::Move {
 9468                target, snapshot, ..
 9469            } => {
 9470                if !supports_jump {
 9471                    return None;
 9472                }
 9473
 9474                Some(
 9475                    h_flex()
 9476                        .px_2()
 9477                        .gap_2()
 9478                        .flex_1()
 9479                        .child(
 9480                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9481                                Icon::new(IconName::ZedPredictDown)
 9482                            } else {
 9483                                Icon::new(IconName::ZedPredictUp)
 9484                            },
 9485                        )
 9486                        .child(Label::new("Jump to Edit")),
 9487                )
 9488            }
 9489
 9490            EditPrediction::Edit {
 9491                edits,
 9492                edit_preview,
 9493                snapshot,
 9494                display_mode: _,
 9495            } => {
 9496                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9497
 9498                let (highlighted_edits, has_more_lines) =
 9499                    if let Some(edit_preview) = edit_preview.as_ref() {
 9500                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9501                            .first_line_preview()
 9502                    } else {
 9503                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9504                    };
 9505
 9506                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9507                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9508
 9509                let preview = h_flex()
 9510                    .gap_1()
 9511                    .min_w_16()
 9512                    .child(styled_text)
 9513                    .when(has_more_lines, |parent| parent.child(""));
 9514
 9515                let left = if supports_jump && first_edit_row != cursor_point.row {
 9516                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9517                        .into_any_element()
 9518                } else {
 9519                    let icon_name =
 9520                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9521                    Icon::new(icon_name).into_any_element()
 9522                };
 9523
 9524                Some(
 9525                    h_flex()
 9526                        .h_full()
 9527                        .flex_1()
 9528                        .gap_2()
 9529                        .pr_1()
 9530                        .overflow_x_hidden()
 9531                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9532                        .child(left)
 9533                        .child(preview),
 9534                )
 9535            }
 9536        }
 9537    }
 9538
 9539    pub fn render_context_menu(
 9540        &self,
 9541        style: &EditorStyle,
 9542        max_height_in_lines: u32,
 9543        window: &mut Window,
 9544        cx: &mut Context<Editor>,
 9545    ) -> Option<AnyElement> {
 9546        let menu = self.context_menu.borrow();
 9547        let menu = menu.as_ref()?;
 9548        if !menu.visible() {
 9549            return None;
 9550        };
 9551        Some(menu.render(style, max_height_in_lines, window, cx))
 9552    }
 9553
 9554    fn render_context_menu_aside(
 9555        &mut self,
 9556        max_size: Size<Pixels>,
 9557        window: &mut Window,
 9558        cx: &mut Context<Editor>,
 9559    ) -> Option<AnyElement> {
 9560        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9561            if menu.visible() {
 9562                menu.render_aside(max_size, window, cx)
 9563            } else {
 9564                None
 9565            }
 9566        })
 9567    }
 9568
 9569    fn hide_context_menu(
 9570        &mut self,
 9571        window: &mut Window,
 9572        cx: &mut Context<Self>,
 9573    ) -> Option<CodeContextMenu> {
 9574        cx.notify();
 9575        self.completion_tasks.clear();
 9576        let context_menu = self.context_menu.borrow_mut().take();
 9577        self.stale_edit_prediction_in_menu.take();
 9578        self.update_visible_edit_prediction(window, cx);
 9579        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9580            && let Some(completion_provider) = &self.completion_provider
 9581        {
 9582            completion_provider.selection_changed(None, window, cx);
 9583        }
 9584        context_menu
 9585    }
 9586
 9587    fn show_snippet_choices(
 9588        &mut self,
 9589        choices: &Vec<String>,
 9590        selection: Range<Anchor>,
 9591        cx: &mut Context<Self>,
 9592    ) {
 9593        let Some((_, buffer, _)) = self
 9594            .buffer()
 9595            .read(cx)
 9596            .excerpt_containing(selection.start, cx)
 9597        else {
 9598            return;
 9599        };
 9600        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9601        else {
 9602            return;
 9603        };
 9604        if buffer != end_buffer {
 9605            log::error!("expected anchor range to have matching buffer IDs");
 9606            return;
 9607        }
 9608
 9609        let id = post_inc(&mut self.next_completion_id);
 9610        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9611        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9612            CompletionsMenu::new_snippet_choices(
 9613                id,
 9614                true,
 9615                choices,
 9616                selection,
 9617                buffer,
 9618                snippet_sort_order,
 9619            ),
 9620        ));
 9621    }
 9622
 9623    pub fn insert_snippet(
 9624        &mut self,
 9625        insertion_ranges: &[Range<usize>],
 9626        snippet: Snippet,
 9627        window: &mut Window,
 9628        cx: &mut Context<Self>,
 9629    ) -> Result<()> {
 9630        struct Tabstop<T> {
 9631            is_end_tabstop: bool,
 9632            ranges: Vec<Range<T>>,
 9633            choices: Option<Vec<String>>,
 9634        }
 9635
 9636        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9637            let snippet_text: Arc<str> = snippet.text.clone().into();
 9638            let edits = insertion_ranges
 9639                .iter()
 9640                .cloned()
 9641                .map(|range| (range, snippet_text.clone()));
 9642            let autoindent_mode = AutoindentMode::Block {
 9643                original_indent_columns: Vec::new(),
 9644            };
 9645            buffer.edit(edits, Some(autoindent_mode), cx);
 9646
 9647            let snapshot = &*buffer.read(cx);
 9648            let snippet = &snippet;
 9649            snippet
 9650                .tabstops
 9651                .iter()
 9652                .map(|tabstop| {
 9653                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9654                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9655                    });
 9656                    let mut tabstop_ranges = tabstop
 9657                        .ranges
 9658                        .iter()
 9659                        .flat_map(|tabstop_range| {
 9660                            let mut delta = 0_isize;
 9661                            insertion_ranges.iter().map(move |insertion_range| {
 9662                                let insertion_start = insertion_range.start as isize + delta;
 9663                                delta +=
 9664                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9665
 9666                                let start = ((insertion_start + tabstop_range.start) as usize)
 9667                                    .min(snapshot.len());
 9668                                let end = ((insertion_start + tabstop_range.end) as usize)
 9669                                    .min(snapshot.len());
 9670                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9671                            })
 9672                        })
 9673                        .collect::<Vec<_>>();
 9674                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9675
 9676                    Tabstop {
 9677                        is_end_tabstop,
 9678                        ranges: tabstop_ranges,
 9679                        choices: tabstop.choices.clone(),
 9680                    }
 9681                })
 9682                .collect::<Vec<_>>()
 9683        });
 9684        if let Some(tabstop) = tabstops.first() {
 9685            self.change_selections(Default::default(), window, cx, |s| {
 9686                // Reverse order so that the first range is the newest created selection.
 9687                // Completions will use it and autoscroll will prioritize it.
 9688                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9689            });
 9690
 9691            if let Some(choices) = &tabstop.choices
 9692                && let Some(selection) = tabstop.ranges.first()
 9693            {
 9694                self.show_snippet_choices(choices, selection.clone(), cx)
 9695            }
 9696
 9697            // If we're already at the last tabstop and it's at the end of the snippet,
 9698            // we're done, we don't need to keep the state around.
 9699            if !tabstop.is_end_tabstop {
 9700                let choices = tabstops
 9701                    .iter()
 9702                    .map(|tabstop| tabstop.choices.clone())
 9703                    .collect();
 9704
 9705                let ranges = tabstops
 9706                    .into_iter()
 9707                    .map(|tabstop| tabstop.ranges)
 9708                    .collect::<Vec<_>>();
 9709
 9710                self.snippet_stack.push(SnippetState {
 9711                    active_index: 0,
 9712                    ranges,
 9713                    choices,
 9714                });
 9715            }
 9716
 9717            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9718            if self.autoclose_regions.is_empty() {
 9719                let snapshot = self.buffer.read(cx).snapshot(cx);
 9720                let mut all_selections = self.selections.all::<Point>(cx);
 9721                for selection in &mut all_selections {
 9722                    let selection_head = selection.head();
 9723                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9724                        continue;
 9725                    };
 9726
 9727                    let mut bracket_pair = None;
 9728                    let max_lookup_length = scope
 9729                        .brackets()
 9730                        .map(|(pair, _)| {
 9731                            pair.start
 9732                                .as_str()
 9733                                .chars()
 9734                                .count()
 9735                                .max(pair.end.as_str().chars().count())
 9736                        })
 9737                        .max();
 9738                    if let Some(max_lookup_length) = max_lookup_length {
 9739                        let next_text = snapshot
 9740                            .chars_at(selection_head)
 9741                            .take(max_lookup_length)
 9742                            .collect::<String>();
 9743                        let prev_text = snapshot
 9744                            .reversed_chars_at(selection_head)
 9745                            .take(max_lookup_length)
 9746                            .collect::<String>();
 9747
 9748                        for (pair, enabled) in scope.brackets() {
 9749                            if enabled
 9750                                && pair.close
 9751                                && prev_text.starts_with(pair.start.as_str())
 9752                                && next_text.starts_with(pair.end.as_str())
 9753                            {
 9754                                bracket_pair = Some(pair.clone());
 9755                                break;
 9756                            }
 9757                        }
 9758                    }
 9759
 9760                    if let Some(pair) = bracket_pair {
 9761                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9762                        let autoclose_enabled =
 9763                            self.use_autoclose && snapshot_settings.use_autoclose;
 9764                        if autoclose_enabled {
 9765                            let start = snapshot.anchor_after(selection_head);
 9766                            let end = snapshot.anchor_after(selection_head);
 9767                            self.autoclose_regions.push(AutocloseRegion {
 9768                                selection_id: selection.id,
 9769                                range: start..end,
 9770                                pair,
 9771                            });
 9772                        }
 9773                    }
 9774                }
 9775            }
 9776        }
 9777        Ok(())
 9778    }
 9779
 9780    pub fn move_to_next_snippet_tabstop(
 9781        &mut self,
 9782        window: &mut Window,
 9783        cx: &mut Context<Self>,
 9784    ) -> bool {
 9785        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9786    }
 9787
 9788    pub fn move_to_prev_snippet_tabstop(
 9789        &mut self,
 9790        window: &mut Window,
 9791        cx: &mut Context<Self>,
 9792    ) -> bool {
 9793        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9794    }
 9795
 9796    pub fn move_to_snippet_tabstop(
 9797        &mut self,
 9798        bias: Bias,
 9799        window: &mut Window,
 9800        cx: &mut Context<Self>,
 9801    ) -> bool {
 9802        if let Some(mut snippet) = self.snippet_stack.pop() {
 9803            match bias {
 9804                Bias::Left => {
 9805                    if snippet.active_index > 0 {
 9806                        snippet.active_index -= 1;
 9807                    } else {
 9808                        self.snippet_stack.push(snippet);
 9809                        return false;
 9810                    }
 9811                }
 9812                Bias::Right => {
 9813                    if snippet.active_index + 1 < snippet.ranges.len() {
 9814                        snippet.active_index += 1;
 9815                    } else {
 9816                        self.snippet_stack.push(snippet);
 9817                        return false;
 9818                    }
 9819                }
 9820            }
 9821            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9822                self.change_selections(Default::default(), window, cx, |s| {
 9823                    // Reverse order so that the first range is the newest created selection.
 9824                    // Completions will use it and autoscroll will prioritize it.
 9825                    s.select_ranges(current_ranges.iter().rev().cloned())
 9826                });
 9827
 9828                if let Some(choices) = &snippet.choices[snippet.active_index]
 9829                    && let Some(selection) = current_ranges.first()
 9830                {
 9831                    self.show_snippet_choices(choices, selection.clone(), cx);
 9832                }
 9833
 9834                // If snippet state is not at the last tabstop, push it back on the stack
 9835                if snippet.active_index + 1 < snippet.ranges.len() {
 9836                    self.snippet_stack.push(snippet);
 9837                }
 9838                return true;
 9839            }
 9840        }
 9841
 9842        false
 9843    }
 9844
 9845    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9846        self.transact(window, cx, |this, window, cx| {
 9847            this.select_all(&SelectAll, window, cx);
 9848            this.insert("", window, cx);
 9849        });
 9850    }
 9851
 9852    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9853        if self.read_only(cx) {
 9854            return;
 9855        }
 9856        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9857        self.transact(window, cx, |this, window, cx| {
 9858            this.select_autoclose_pair(window, cx);
 9859            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9860            if !this.linked_edit_ranges.is_empty() {
 9861                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9862                let snapshot = this.buffer.read(cx).snapshot(cx);
 9863
 9864                for selection in selections.iter() {
 9865                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9866                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9867                    if selection_start.buffer_id != selection_end.buffer_id {
 9868                        continue;
 9869                    }
 9870                    if let Some(ranges) =
 9871                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9872                    {
 9873                        for (buffer, entries) in ranges {
 9874                            linked_ranges.entry(buffer).or_default().extend(entries);
 9875                        }
 9876                    }
 9877                }
 9878            }
 9879
 9880            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9881            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9882            for selection in &mut selections {
 9883                if selection.is_empty() {
 9884                    let old_head = selection.head();
 9885                    let mut new_head =
 9886                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9887                            .to_point(&display_map);
 9888                    if let Some((buffer, line_buffer_range)) = display_map
 9889                        .buffer_snapshot
 9890                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9891                    {
 9892                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9893                        let indent_len = match indent_size.kind {
 9894                            IndentKind::Space => {
 9895                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9896                            }
 9897                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9898                        };
 9899                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9900                            let indent_len = indent_len.get();
 9901                            new_head = cmp::min(
 9902                                new_head,
 9903                                MultiBufferPoint::new(
 9904                                    old_head.row,
 9905                                    ((old_head.column - 1) / indent_len) * indent_len,
 9906                                ),
 9907                            );
 9908                        }
 9909                    }
 9910
 9911                    selection.set_head(new_head, SelectionGoal::None);
 9912                }
 9913            }
 9914
 9915            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9916            this.insert("", window, cx);
 9917            let empty_str: Arc<str> = Arc::from("");
 9918            for (buffer, edits) in linked_ranges {
 9919                let snapshot = buffer.read(cx).snapshot();
 9920                use text::ToPoint as TP;
 9921
 9922                let edits = edits
 9923                    .into_iter()
 9924                    .map(|range| {
 9925                        let end_point = TP::to_point(&range.end, &snapshot);
 9926                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9927
 9928                        if end_point == start_point {
 9929                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9930                                .saturating_sub(1);
 9931                            start_point =
 9932                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9933                        };
 9934
 9935                        (start_point..end_point, empty_str.clone())
 9936                    })
 9937                    .sorted_by_key(|(range, _)| range.start)
 9938                    .collect::<Vec<_>>();
 9939                buffer.update(cx, |this, cx| {
 9940                    this.edit(edits, None, cx);
 9941                })
 9942            }
 9943            this.refresh_edit_prediction(true, false, window, cx);
 9944            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9945        });
 9946    }
 9947
 9948    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9949        if self.read_only(cx) {
 9950            return;
 9951        }
 9952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9953        self.transact(window, cx, |this, window, cx| {
 9954            this.change_selections(Default::default(), window, cx, |s| {
 9955                s.move_with(|map, selection| {
 9956                    if selection.is_empty() {
 9957                        let cursor = movement::right(map, selection.head());
 9958                        selection.end = cursor;
 9959                        selection.reversed = true;
 9960                        selection.goal = SelectionGoal::None;
 9961                    }
 9962                })
 9963            });
 9964            this.insert("", window, cx);
 9965            this.refresh_edit_prediction(true, false, window, cx);
 9966        });
 9967    }
 9968
 9969    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9970        if self.mode.is_single_line() {
 9971            cx.propagate();
 9972            return;
 9973        }
 9974
 9975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9976        if self.move_to_prev_snippet_tabstop(window, cx) {
 9977            return;
 9978        }
 9979        self.outdent(&Outdent, window, cx);
 9980    }
 9981
 9982    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9983        if self.mode.is_single_line() {
 9984            cx.propagate();
 9985            return;
 9986        }
 9987
 9988        if self.move_to_next_snippet_tabstop(window, cx) {
 9989            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9990            return;
 9991        }
 9992        if self.read_only(cx) {
 9993            return;
 9994        }
 9995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9996        let mut selections = self.selections.all_adjusted(cx);
 9997        let buffer = self.buffer.read(cx);
 9998        let snapshot = buffer.snapshot(cx);
 9999        let rows_iter = selections.iter().map(|s| s.head().row);
10000        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10001
10002        let has_some_cursor_in_whitespace = selections
10003            .iter()
10004            .filter(|selection| selection.is_empty())
10005            .any(|selection| {
10006                let cursor = selection.head();
10007                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10008                cursor.column < current_indent.len
10009            });
10010
10011        let mut edits = Vec::new();
10012        let mut prev_edited_row = 0;
10013        let mut row_delta = 0;
10014        for selection in &mut selections {
10015            if selection.start.row != prev_edited_row {
10016                row_delta = 0;
10017            }
10018            prev_edited_row = selection.end.row;
10019
10020            // If the selection is non-empty, then increase the indentation of the selected lines.
10021            if !selection.is_empty() {
10022                row_delta =
10023                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10024                continue;
10025            }
10026
10027            let cursor = selection.head();
10028            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10029            if let Some(suggested_indent) =
10030                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10031            {
10032                // Don't do anything if already at suggested indent
10033                // and there is any other cursor which is not
10034                if has_some_cursor_in_whitespace
10035                    && cursor.column == current_indent.len
10036                    && current_indent.len == suggested_indent.len
10037                {
10038                    continue;
10039                }
10040
10041                // Adjust line and move cursor to suggested indent
10042                // if cursor is not at suggested indent
10043                if cursor.column < suggested_indent.len
10044                    && cursor.column <= current_indent.len
10045                    && current_indent.len <= suggested_indent.len
10046                {
10047                    selection.start = Point::new(cursor.row, suggested_indent.len);
10048                    selection.end = selection.start;
10049                    if row_delta == 0 {
10050                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10051                            cursor.row,
10052                            current_indent,
10053                            suggested_indent,
10054                        ));
10055                        row_delta = suggested_indent.len - current_indent.len;
10056                    }
10057                    continue;
10058                }
10059
10060                // If current indent is more than suggested indent
10061                // only move cursor to current indent and skip indent
10062                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10063                    selection.start = Point::new(cursor.row, current_indent.len);
10064                    selection.end = selection.start;
10065                    continue;
10066                }
10067            }
10068
10069            // Otherwise, insert a hard or soft tab.
10070            let settings = buffer.language_settings_at(cursor, cx);
10071            let tab_size = if settings.hard_tabs {
10072                IndentSize::tab()
10073            } else {
10074                let tab_size = settings.tab_size.get();
10075                let indent_remainder = snapshot
10076                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10077                    .flat_map(str::chars)
10078                    .fold(row_delta % tab_size, |counter: u32, c| {
10079                        if c == '\t' {
10080                            0
10081                        } else {
10082                            (counter + 1) % tab_size
10083                        }
10084                    });
10085
10086                let chars_to_next_tab_stop = tab_size - indent_remainder;
10087                IndentSize::spaces(chars_to_next_tab_stop)
10088            };
10089            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10090            selection.end = selection.start;
10091            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10092            row_delta += tab_size.len;
10093        }
10094
10095        self.transact(window, cx, |this, window, cx| {
10096            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10097            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10098            this.refresh_edit_prediction(true, false, window, cx);
10099        });
10100    }
10101
10102    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10103        if self.read_only(cx) {
10104            return;
10105        }
10106        if self.mode.is_single_line() {
10107            cx.propagate();
10108            return;
10109        }
10110
10111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10112        let mut selections = self.selections.all::<Point>(cx);
10113        let mut prev_edited_row = 0;
10114        let mut row_delta = 0;
10115        let mut edits = Vec::new();
10116        let buffer = self.buffer.read(cx);
10117        let snapshot = buffer.snapshot(cx);
10118        for selection in &mut selections {
10119            if selection.start.row != prev_edited_row {
10120                row_delta = 0;
10121            }
10122            prev_edited_row = selection.end.row;
10123
10124            row_delta =
10125                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10126        }
10127
10128        self.transact(window, cx, |this, window, cx| {
10129            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10130            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10131        });
10132    }
10133
10134    fn indent_selection(
10135        buffer: &MultiBuffer,
10136        snapshot: &MultiBufferSnapshot,
10137        selection: &mut Selection<Point>,
10138        edits: &mut Vec<(Range<Point>, String)>,
10139        delta_for_start_row: u32,
10140        cx: &App,
10141    ) -> u32 {
10142        let settings = buffer.language_settings_at(selection.start, cx);
10143        let tab_size = settings.tab_size.get();
10144        let indent_kind = if settings.hard_tabs {
10145            IndentKind::Tab
10146        } else {
10147            IndentKind::Space
10148        };
10149        let mut start_row = selection.start.row;
10150        let mut end_row = selection.end.row + 1;
10151
10152        // If a selection ends at the beginning of a line, don't indent
10153        // that last line.
10154        if selection.end.column == 0 && selection.end.row > selection.start.row {
10155            end_row -= 1;
10156        }
10157
10158        // Avoid re-indenting a row that has already been indented by a
10159        // previous selection, but still update this selection's column
10160        // to reflect that indentation.
10161        if delta_for_start_row > 0 {
10162            start_row += 1;
10163            selection.start.column += delta_for_start_row;
10164            if selection.end.row == selection.start.row {
10165                selection.end.column += delta_for_start_row;
10166            }
10167        }
10168
10169        let mut delta_for_end_row = 0;
10170        let has_multiple_rows = start_row + 1 != end_row;
10171        for row in start_row..end_row {
10172            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10173            let indent_delta = match (current_indent.kind, indent_kind) {
10174                (IndentKind::Space, IndentKind::Space) => {
10175                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10176                    IndentSize::spaces(columns_to_next_tab_stop)
10177                }
10178                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10179                (_, IndentKind::Tab) => IndentSize::tab(),
10180            };
10181
10182            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10183                0
10184            } else {
10185                selection.start.column
10186            };
10187            let row_start = Point::new(row, start);
10188            edits.push((
10189                row_start..row_start,
10190                indent_delta.chars().collect::<String>(),
10191            ));
10192
10193            // Update this selection's endpoints to reflect the indentation.
10194            if row == selection.start.row {
10195                selection.start.column += indent_delta.len;
10196            }
10197            if row == selection.end.row {
10198                selection.end.column += indent_delta.len;
10199                delta_for_end_row = indent_delta.len;
10200            }
10201        }
10202
10203        if selection.start.row == selection.end.row {
10204            delta_for_start_row + delta_for_end_row
10205        } else {
10206            delta_for_end_row
10207        }
10208    }
10209
10210    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10211        if self.read_only(cx) {
10212            return;
10213        }
10214        if self.mode.is_single_line() {
10215            cx.propagate();
10216            return;
10217        }
10218
10219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10220        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10221        let selections = self.selections.all::<Point>(cx);
10222        let mut deletion_ranges = Vec::new();
10223        let mut last_outdent = None;
10224        {
10225            let buffer = self.buffer.read(cx);
10226            let snapshot = buffer.snapshot(cx);
10227            for selection in &selections {
10228                let settings = buffer.language_settings_at(selection.start, cx);
10229                let tab_size = settings.tab_size.get();
10230                let mut rows = selection.spanned_rows(false, &display_map);
10231
10232                // Avoid re-outdenting a row that has already been outdented by a
10233                // previous selection.
10234                if let Some(last_row) = last_outdent
10235                    && last_row == rows.start
10236                {
10237                    rows.start = rows.start.next_row();
10238                }
10239                let has_multiple_rows = rows.len() > 1;
10240                for row in rows.iter_rows() {
10241                    let indent_size = snapshot.indent_size_for_line(row);
10242                    if indent_size.len > 0 {
10243                        let deletion_len = match indent_size.kind {
10244                            IndentKind::Space => {
10245                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10246                                if columns_to_prev_tab_stop == 0 {
10247                                    tab_size
10248                                } else {
10249                                    columns_to_prev_tab_stop
10250                                }
10251                            }
10252                            IndentKind::Tab => 1,
10253                        };
10254                        let start = if has_multiple_rows
10255                            || deletion_len > selection.start.column
10256                            || indent_size.len < selection.start.column
10257                        {
10258                            0
10259                        } else {
10260                            selection.start.column - deletion_len
10261                        };
10262                        deletion_ranges.push(
10263                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10264                        );
10265                        last_outdent = Some(row);
10266                    }
10267                }
10268            }
10269        }
10270
10271        self.transact(window, cx, |this, window, cx| {
10272            this.buffer.update(cx, |buffer, cx| {
10273                let empty_str: Arc<str> = Arc::default();
10274                buffer.edit(
10275                    deletion_ranges
10276                        .into_iter()
10277                        .map(|range| (range, empty_str.clone())),
10278                    None,
10279                    cx,
10280                );
10281            });
10282            let selections = this.selections.all::<usize>(cx);
10283            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10284        });
10285    }
10286
10287    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10288        if self.read_only(cx) {
10289            return;
10290        }
10291        if self.mode.is_single_line() {
10292            cx.propagate();
10293            return;
10294        }
10295
10296        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10297        let selections = self
10298            .selections
10299            .all::<usize>(cx)
10300            .into_iter()
10301            .map(|s| s.range());
10302
10303        self.transact(window, cx, |this, window, cx| {
10304            this.buffer.update(cx, |buffer, cx| {
10305                buffer.autoindent_ranges(selections, cx);
10306            });
10307            let selections = this.selections.all::<usize>(cx);
10308            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10309        });
10310    }
10311
10312    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10314        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10315        let selections = self.selections.all::<Point>(cx);
10316
10317        let mut new_cursors = Vec::new();
10318        let mut edit_ranges = Vec::new();
10319        let mut selections = selections.iter().peekable();
10320        while let Some(selection) = selections.next() {
10321            let mut rows = selection.spanned_rows(false, &display_map);
10322            let goal_display_column = selection.head().to_display_point(&display_map).column();
10323
10324            // Accumulate contiguous regions of rows that we want to delete.
10325            while let Some(next_selection) = selections.peek() {
10326                let next_rows = next_selection.spanned_rows(false, &display_map);
10327                if next_rows.start <= rows.end {
10328                    rows.end = next_rows.end;
10329                    selections.next().unwrap();
10330                } else {
10331                    break;
10332                }
10333            }
10334
10335            let buffer = &display_map.buffer_snapshot;
10336            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10337            let edit_end;
10338            let cursor_buffer_row;
10339            if buffer.max_point().row >= rows.end.0 {
10340                // If there's a line after the range, delete the \n from the end of the row range
10341                // and position the cursor on the next line.
10342                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10343                cursor_buffer_row = rows.end;
10344            } else {
10345                // If there isn't a line after the range, delete the \n from the line before the
10346                // start of the row range and position the cursor there.
10347                edit_start = edit_start.saturating_sub(1);
10348                edit_end = buffer.len();
10349                cursor_buffer_row = rows.start.previous_row();
10350            }
10351
10352            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10353            *cursor.column_mut() =
10354                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10355
10356            new_cursors.push((
10357                selection.id,
10358                buffer.anchor_after(cursor.to_point(&display_map)),
10359            ));
10360            edit_ranges.push(edit_start..edit_end);
10361        }
10362
10363        self.transact(window, cx, |this, window, cx| {
10364            let buffer = this.buffer.update(cx, |buffer, cx| {
10365                let empty_str: Arc<str> = Arc::default();
10366                buffer.edit(
10367                    edit_ranges
10368                        .into_iter()
10369                        .map(|range| (range, empty_str.clone())),
10370                    None,
10371                    cx,
10372                );
10373                buffer.snapshot(cx)
10374            });
10375            let new_selections = new_cursors
10376                .into_iter()
10377                .map(|(id, cursor)| {
10378                    let cursor = cursor.to_point(&buffer);
10379                    Selection {
10380                        id,
10381                        start: cursor,
10382                        end: cursor,
10383                        reversed: false,
10384                        goal: SelectionGoal::None,
10385                    }
10386                })
10387                .collect();
10388
10389            this.change_selections(Default::default(), window, cx, |s| {
10390                s.select(new_selections);
10391            });
10392        });
10393    }
10394
10395    pub fn join_lines_impl(
10396        &mut self,
10397        insert_whitespace: bool,
10398        window: &mut Window,
10399        cx: &mut Context<Self>,
10400    ) {
10401        if self.read_only(cx) {
10402            return;
10403        }
10404        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10405        for selection in self.selections.all::<Point>(cx) {
10406            let start = MultiBufferRow(selection.start.row);
10407            // Treat single line selections as if they include the next line. Otherwise this action
10408            // would do nothing for single line selections individual cursors.
10409            let end = if selection.start.row == selection.end.row {
10410                MultiBufferRow(selection.start.row + 1)
10411            } else {
10412                MultiBufferRow(selection.end.row)
10413            };
10414
10415            if let Some(last_row_range) = row_ranges.last_mut()
10416                && start <= last_row_range.end
10417            {
10418                last_row_range.end = end;
10419                continue;
10420            }
10421            row_ranges.push(start..end);
10422        }
10423
10424        let snapshot = self.buffer.read(cx).snapshot(cx);
10425        let mut cursor_positions = Vec::new();
10426        for row_range in &row_ranges {
10427            let anchor = snapshot.anchor_before(Point::new(
10428                row_range.end.previous_row().0,
10429                snapshot.line_len(row_range.end.previous_row()),
10430            ));
10431            cursor_positions.push(anchor..anchor);
10432        }
10433
10434        self.transact(window, cx, |this, window, cx| {
10435            for row_range in row_ranges.into_iter().rev() {
10436                for row in row_range.iter_rows().rev() {
10437                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10438                    let next_line_row = row.next_row();
10439                    let indent = snapshot.indent_size_for_line(next_line_row);
10440                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10441
10442                    let replace =
10443                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10444                            " "
10445                        } else {
10446                            ""
10447                        };
10448
10449                    this.buffer.update(cx, |buffer, cx| {
10450                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10451                    });
10452                }
10453            }
10454
10455            this.change_selections(Default::default(), window, cx, |s| {
10456                s.select_anchor_ranges(cursor_positions)
10457            });
10458        });
10459    }
10460
10461    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10462        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10463        self.join_lines_impl(true, window, cx);
10464    }
10465
10466    pub fn sort_lines_case_sensitive(
10467        &mut self,
10468        _: &SortLinesCaseSensitive,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10473    }
10474
10475    pub fn sort_lines_by_length(
10476        &mut self,
10477        _: &SortLinesByLength,
10478        window: &mut Window,
10479        cx: &mut Context<Self>,
10480    ) {
10481        self.manipulate_immutable_lines(window, cx, |lines| {
10482            lines.sort_by_key(|&line| line.chars().count())
10483        })
10484    }
10485
10486    pub fn sort_lines_case_insensitive(
10487        &mut self,
10488        _: &SortLinesCaseInsensitive,
10489        window: &mut Window,
10490        cx: &mut Context<Self>,
10491    ) {
10492        self.manipulate_immutable_lines(window, cx, |lines| {
10493            lines.sort_by_key(|line| line.to_lowercase())
10494        })
10495    }
10496
10497    pub fn unique_lines_case_insensitive(
10498        &mut self,
10499        _: &UniqueLinesCaseInsensitive,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        self.manipulate_immutable_lines(window, cx, |lines| {
10504            let mut seen = HashSet::default();
10505            lines.retain(|line| seen.insert(line.to_lowercase()));
10506        })
10507    }
10508
10509    pub fn unique_lines_case_sensitive(
10510        &mut self,
10511        _: &UniqueLinesCaseSensitive,
10512        window: &mut Window,
10513        cx: &mut Context<Self>,
10514    ) {
10515        self.manipulate_immutable_lines(window, cx, |lines| {
10516            let mut seen = HashSet::default();
10517            lines.retain(|line| seen.insert(*line));
10518        })
10519    }
10520
10521    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10522        let snapshot = self.buffer.read(cx).snapshot(cx);
10523        for selection in self.selections.disjoint_anchors_arc().iter() {
10524            if snapshot
10525                .language_at(selection.start)
10526                .and_then(|lang| lang.config().wrap_characters.as_ref())
10527                .is_some()
10528            {
10529                return true;
10530            }
10531        }
10532        false
10533    }
10534
10535    fn wrap_selections_in_tag(
10536        &mut self,
10537        _: &WrapSelectionsInTag,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10542
10543        let snapshot = self.buffer.read(cx).snapshot(cx);
10544
10545        let mut edits = Vec::new();
10546        let mut boundaries = Vec::new();
10547
10548        for selection in self.selections.all::<Point>(cx).iter() {
10549            let Some(wrap_config) = snapshot
10550                .language_at(selection.start)
10551                .and_then(|lang| lang.config().wrap_characters.clone())
10552            else {
10553                continue;
10554            };
10555
10556            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10557            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10558
10559            let start_before = snapshot.anchor_before(selection.start);
10560            let end_after = snapshot.anchor_after(selection.end);
10561
10562            edits.push((start_before..start_before, open_tag));
10563            edits.push((end_after..end_after, close_tag));
10564
10565            boundaries.push((
10566                start_before,
10567                end_after,
10568                wrap_config.start_prefix.len(),
10569                wrap_config.end_suffix.len(),
10570            ));
10571        }
10572
10573        if edits.is_empty() {
10574            return;
10575        }
10576
10577        self.transact(window, cx, |this, window, cx| {
10578            let buffer = this.buffer.update(cx, |buffer, cx| {
10579                buffer.edit(edits, None, cx);
10580                buffer.snapshot(cx)
10581            });
10582
10583            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10584            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10585                boundaries.into_iter()
10586            {
10587                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10588                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10589                new_selections.push(open_offset..open_offset);
10590                new_selections.push(close_offset..close_offset);
10591            }
10592
10593            this.change_selections(Default::default(), window, cx, |s| {
10594                s.select_ranges(new_selections);
10595            });
10596
10597            this.request_autoscroll(Autoscroll::fit(), cx);
10598        });
10599    }
10600
10601    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10602        let Some(project) = self.project.clone() else {
10603            return;
10604        };
10605        self.reload(project, window, cx)
10606            .detach_and_notify_err(window, cx);
10607    }
10608
10609    pub fn restore_file(
10610        &mut self,
10611        _: &::git::RestoreFile,
10612        window: &mut Window,
10613        cx: &mut Context<Self>,
10614    ) {
10615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10616        let mut buffer_ids = HashSet::default();
10617        let snapshot = self.buffer().read(cx).snapshot(cx);
10618        for selection in self.selections.all::<usize>(cx) {
10619            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10620        }
10621
10622        let buffer = self.buffer().read(cx);
10623        let ranges = buffer_ids
10624            .into_iter()
10625            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10626            .collect::<Vec<_>>();
10627
10628        self.restore_hunks_in_ranges(ranges, window, cx);
10629    }
10630
10631    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10633        let selections = self
10634            .selections
10635            .all(cx)
10636            .into_iter()
10637            .map(|s| s.range())
10638            .collect();
10639        self.restore_hunks_in_ranges(selections, window, cx);
10640    }
10641
10642    pub fn restore_hunks_in_ranges(
10643        &mut self,
10644        ranges: Vec<Range<Point>>,
10645        window: &mut Window,
10646        cx: &mut Context<Editor>,
10647    ) {
10648        let mut revert_changes = HashMap::default();
10649        let chunk_by = self
10650            .snapshot(window, cx)
10651            .hunks_for_ranges(ranges)
10652            .into_iter()
10653            .chunk_by(|hunk| hunk.buffer_id);
10654        for (buffer_id, hunks) in &chunk_by {
10655            let hunks = hunks.collect::<Vec<_>>();
10656            for hunk in &hunks {
10657                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10658            }
10659            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10660        }
10661        drop(chunk_by);
10662        if !revert_changes.is_empty() {
10663            self.transact(window, cx, |editor, window, cx| {
10664                editor.restore(revert_changes, window, cx);
10665            });
10666        }
10667    }
10668
10669    pub fn open_active_item_in_terminal(
10670        &mut self,
10671        _: &OpenInTerminal,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10676            let project_path = buffer.read(cx).project_path(cx)?;
10677            let project = self.project()?.read(cx);
10678            let entry = project.entry_for_path(&project_path, cx)?;
10679            let parent = match &entry.canonical_path {
10680                Some(canonical_path) => canonical_path.to_path_buf(),
10681                None => project.absolute_path(&project_path, cx)?,
10682            }
10683            .parent()?
10684            .to_path_buf();
10685            Some(parent)
10686        }) {
10687            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10688        }
10689    }
10690
10691    fn set_breakpoint_context_menu(
10692        &mut self,
10693        display_row: DisplayRow,
10694        position: Option<Anchor>,
10695        clicked_point: gpui::Point<Pixels>,
10696        window: &mut Window,
10697        cx: &mut Context<Self>,
10698    ) {
10699        let source = self
10700            .buffer
10701            .read(cx)
10702            .snapshot(cx)
10703            .anchor_before(Point::new(display_row.0, 0u32));
10704
10705        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10706
10707        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10708            self,
10709            source,
10710            clicked_point,
10711            context_menu,
10712            window,
10713            cx,
10714        );
10715    }
10716
10717    fn add_edit_breakpoint_block(
10718        &mut self,
10719        anchor: Anchor,
10720        breakpoint: &Breakpoint,
10721        edit_action: BreakpointPromptEditAction,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) {
10725        let weak_editor = cx.weak_entity();
10726        let bp_prompt = cx.new(|cx| {
10727            BreakpointPromptEditor::new(
10728                weak_editor,
10729                anchor,
10730                breakpoint.clone(),
10731                edit_action,
10732                window,
10733                cx,
10734            )
10735        });
10736
10737        let height = bp_prompt.update(cx, |this, cx| {
10738            this.prompt
10739                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10740        });
10741        let cloned_prompt = bp_prompt.clone();
10742        let blocks = vec![BlockProperties {
10743            style: BlockStyle::Sticky,
10744            placement: BlockPlacement::Above(anchor),
10745            height: Some(height),
10746            render: Arc::new(move |cx| {
10747                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10748                cloned_prompt.clone().into_any_element()
10749            }),
10750            priority: 0,
10751        }];
10752
10753        let focus_handle = bp_prompt.focus_handle(cx);
10754        window.focus(&focus_handle);
10755
10756        let block_ids = self.insert_blocks(blocks, None, cx);
10757        bp_prompt.update(cx, |prompt, _| {
10758            prompt.add_block_ids(block_ids);
10759        });
10760    }
10761
10762    pub(crate) fn breakpoint_at_row(
10763        &self,
10764        row: u32,
10765        window: &mut Window,
10766        cx: &mut Context<Self>,
10767    ) -> Option<(Anchor, Breakpoint)> {
10768        let snapshot = self.snapshot(window, cx);
10769        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10770
10771        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10772    }
10773
10774    pub(crate) fn breakpoint_at_anchor(
10775        &self,
10776        breakpoint_position: Anchor,
10777        snapshot: &EditorSnapshot,
10778        cx: &mut Context<Self>,
10779    ) -> Option<(Anchor, Breakpoint)> {
10780        let buffer = self
10781            .buffer
10782            .read(cx)
10783            .buffer_for_anchor(breakpoint_position, cx)?;
10784
10785        let enclosing_excerpt = breakpoint_position.excerpt_id;
10786        let buffer_snapshot = buffer.read(cx).snapshot();
10787
10788        let row = buffer_snapshot
10789            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10790            .row;
10791
10792        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10793        let anchor_end = snapshot
10794            .buffer_snapshot
10795            .anchor_after(Point::new(row, line_len));
10796
10797        self.breakpoint_store
10798            .as_ref()?
10799            .read_with(cx, |breakpoint_store, cx| {
10800                breakpoint_store
10801                    .breakpoints(
10802                        &buffer,
10803                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10804                        &buffer_snapshot,
10805                        cx,
10806                    )
10807                    .next()
10808                    .and_then(|(bp, _)| {
10809                        let breakpoint_row = buffer_snapshot
10810                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10811                            .row;
10812
10813                        if breakpoint_row == row {
10814                            snapshot
10815                                .buffer_snapshot
10816                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10817                                .map(|position| (position, bp.bp.clone()))
10818                        } else {
10819                            None
10820                        }
10821                    })
10822            })
10823    }
10824
10825    pub fn edit_log_breakpoint(
10826        &mut self,
10827        _: &EditLogBreakpoint,
10828        window: &mut Window,
10829        cx: &mut Context<Self>,
10830    ) {
10831        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10832            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10833                message: None,
10834                state: BreakpointState::Enabled,
10835                condition: None,
10836                hit_condition: None,
10837            });
10838
10839            self.add_edit_breakpoint_block(
10840                anchor,
10841                &breakpoint,
10842                BreakpointPromptEditAction::Log,
10843                window,
10844                cx,
10845            );
10846        }
10847    }
10848
10849    fn breakpoints_at_cursors(
10850        &self,
10851        window: &mut Window,
10852        cx: &mut Context<Self>,
10853    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10854        let snapshot = self.snapshot(window, cx);
10855        let cursors = self
10856            .selections
10857            .disjoint_anchors_arc()
10858            .iter()
10859            .map(|selection| {
10860                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10861
10862                let breakpoint_position = self
10863                    .breakpoint_at_row(cursor_position.row, window, cx)
10864                    .map(|bp| bp.0)
10865                    .unwrap_or_else(|| {
10866                        snapshot
10867                            .display_snapshot
10868                            .buffer_snapshot
10869                            .anchor_after(Point::new(cursor_position.row, 0))
10870                    });
10871
10872                let breakpoint = self
10873                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10874                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10875
10876                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10877            })
10878            // 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.
10879            .collect::<HashMap<Anchor, _>>();
10880
10881        cursors.into_iter().collect()
10882    }
10883
10884    pub fn enable_breakpoint(
10885        &mut self,
10886        _: &crate::actions::EnableBreakpoint,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10891            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10892                continue;
10893            };
10894            self.edit_breakpoint_at_anchor(
10895                anchor,
10896                breakpoint,
10897                BreakpointEditAction::InvertState,
10898                cx,
10899            );
10900        }
10901    }
10902
10903    pub fn disable_breakpoint(
10904        &mut self,
10905        _: &crate::actions::DisableBreakpoint,
10906        window: &mut Window,
10907        cx: &mut Context<Self>,
10908    ) {
10909        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10910            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10911                continue;
10912            };
10913            self.edit_breakpoint_at_anchor(
10914                anchor,
10915                breakpoint,
10916                BreakpointEditAction::InvertState,
10917                cx,
10918            );
10919        }
10920    }
10921
10922    pub fn toggle_breakpoint(
10923        &mut self,
10924        _: &crate::actions::ToggleBreakpoint,
10925        window: &mut Window,
10926        cx: &mut Context<Self>,
10927    ) {
10928        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10929            if let Some(breakpoint) = breakpoint {
10930                self.edit_breakpoint_at_anchor(
10931                    anchor,
10932                    breakpoint,
10933                    BreakpointEditAction::Toggle,
10934                    cx,
10935                );
10936            } else {
10937                self.edit_breakpoint_at_anchor(
10938                    anchor,
10939                    Breakpoint::new_standard(),
10940                    BreakpointEditAction::Toggle,
10941                    cx,
10942                );
10943            }
10944        }
10945    }
10946
10947    pub fn edit_breakpoint_at_anchor(
10948        &mut self,
10949        breakpoint_position: Anchor,
10950        breakpoint: Breakpoint,
10951        edit_action: BreakpointEditAction,
10952        cx: &mut Context<Self>,
10953    ) {
10954        let Some(breakpoint_store) = &self.breakpoint_store else {
10955            return;
10956        };
10957
10958        let Some(buffer) = self
10959            .buffer
10960            .read(cx)
10961            .buffer_for_anchor(breakpoint_position, cx)
10962        else {
10963            return;
10964        };
10965
10966        breakpoint_store.update(cx, |breakpoint_store, cx| {
10967            breakpoint_store.toggle_breakpoint(
10968                buffer,
10969                BreakpointWithPosition {
10970                    position: breakpoint_position.text_anchor,
10971                    bp: breakpoint,
10972                },
10973                edit_action,
10974                cx,
10975            );
10976        });
10977
10978        cx.notify();
10979    }
10980
10981    #[cfg(any(test, feature = "test-support"))]
10982    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10983        self.breakpoint_store.clone()
10984    }
10985
10986    pub fn prepare_restore_change(
10987        &self,
10988        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10989        hunk: &MultiBufferDiffHunk,
10990        cx: &mut App,
10991    ) -> Option<()> {
10992        if hunk.is_created_file() {
10993            return None;
10994        }
10995        let buffer = self.buffer.read(cx);
10996        let diff = buffer.diff_for(hunk.buffer_id)?;
10997        let buffer = buffer.buffer(hunk.buffer_id)?;
10998        let buffer = buffer.read(cx);
10999        let original_text = diff
11000            .read(cx)
11001            .base_text()
11002            .as_rope()
11003            .slice(hunk.diff_base_byte_range.clone());
11004        let buffer_snapshot = buffer.snapshot();
11005        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11006        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11007            probe
11008                .0
11009                .start
11010                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11011                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11012        }) {
11013            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11014            Some(())
11015        } else {
11016            None
11017        }
11018    }
11019
11020    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11022    }
11023
11024    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11025        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11026    }
11027
11028    fn manipulate_lines<M>(
11029        &mut self,
11030        window: &mut Window,
11031        cx: &mut Context<Self>,
11032        mut manipulate: M,
11033    ) where
11034        M: FnMut(&str) -> LineManipulationResult,
11035    {
11036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11037
11038        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11039        let buffer = self.buffer.read(cx).snapshot(cx);
11040
11041        let mut edits = Vec::new();
11042
11043        let selections = self.selections.all::<Point>(cx);
11044        let mut selections = selections.iter().peekable();
11045        let mut contiguous_row_selections = Vec::new();
11046        let mut new_selections = Vec::new();
11047        let mut added_lines = 0;
11048        let mut removed_lines = 0;
11049
11050        while let Some(selection) = selections.next() {
11051            let (start_row, end_row) = consume_contiguous_rows(
11052                &mut contiguous_row_selections,
11053                selection,
11054                &display_map,
11055                &mut selections,
11056            );
11057
11058            let start_point = Point::new(start_row.0, 0);
11059            let end_point = Point::new(
11060                end_row.previous_row().0,
11061                buffer.line_len(end_row.previous_row()),
11062            );
11063            let text = buffer
11064                .text_for_range(start_point..end_point)
11065                .collect::<String>();
11066
11067            let LineManipulationResult {
11068                new_text,
11069                line_count_before,
11070                line_count_after,
11071            } = manipulate(&text);
11072
11073            edits.push((start_point..end_point, new_text));
11074
11075            // Selections must change based on added and removed line count
11076            let start_row =
11077                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11078            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11079            new_selections.push(Selection {
11080                id: selection.id,
11081                start: start_row,
11082                end: end_row,
11083                goal: SelectionGoal::None,
11084                reversed: selection.reversed,
11085            });
11086
11087            if line_count_after > line_count_before {
11088                added_lines += line_count_after - line_count_before;
11089            } else if line_count_before > line_count_after {
11090                removed_lines += line_count_before - line_count_after;
11091            }
11092        }
11093
11094        self.transact(window, cx, |this, window, cx| {
11095            let buffer = this.buffer.update(cx, |buffer, cx| {
11096                buffer.edit(edits, None, cx);
11097                buffer.snapshot(cx)
11098            });
11099
11100            // Recalculate offsets on newly edited buffer
11101            let new_selections = new_selections
11102                .iter()
11103                .map(|s| {
11104                    let start_point = Point::new(s.start.0, 0);
11105                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11106                    Selection {
11107                        id: s.id,
11108                        start: buffer.point_to_offset(start_point),
11109                        end: buffer.point_to_offset(end_point),
11110                        goal: s.goal,
11111                        reversed: s.reversed,
11112                    }
11113                })
11114                .collect();
11115
11116            this.change_selections(Default::default(), window, cx, |s| {
11117                s.select(new_selections);
11118            });
11119
11120            this.request_autoscroll(Autoscroll::fit(), cx);
11121        });
11122    }
11123
11124    fn manipulate_immutable_lines<Fn>(
11125        &mut self,
11126        window: &mut Window,
11127        cx: &mut Context<Self>,
11128        mut callback: Fn,
11129    ) where
11130        Fn: FnMut(&mut Vec<&str>),
11131    {
11132        self.manipulate_lines(window, cx, |text| {
11133            let mut lines: Vec<&str> = text.split('\n').collect();
11134            let line_count_before = lines.len();
11135
11136            callback(&mut lines);
11137
11138            LineManipulationResult {
11139                new_text: lines.join("\n"),
11140                line_count_before,
11141                line_count_after: lines.len(),
11142            }
11143        });
11144    }
11145
11146    fn manipulate_mutable_lines<Fn>(
11147        &mut self,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150        mut callback: Fn,
11151    ) where
11152        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11153    {
11154        self.manipulate_lines(window, cx, |text| {
11155            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11156            let line_count_before = lines.len();
11157
11158            callback(&mut lines);
11159
11160            LineManipulationResult {
11161                new_text: lines.join("\n"),
11162                line_count_before,
11163                line_count_after: lines.len(),
11164            }
11165        });
11166    }
11167
11168    pub fn convert_indentation_to_spaces(
11169        &mut self,
11170        _: &ConvertIndentationToSpaces,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        let settings = self.buffer.read(cx).language_settings(cx);
11175        let tab_size = settings.tab_size.get() as usize;
11176
11177        self.manipulate_mutable_lines(window, cx, |lines| {
11178            // Allocates a reasonably sized scratch buffer once for the whole loop
11179            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11180            // Avoids recomputing spaces that could be inserted many times
11181            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11182                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11183                .collect();
11184
11185            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11186                let mut chars = line.as_ref().chars();
11187                let mut col = 0;
11188                let mut changed = false;
11189
11190                for ch in chars.by_ref() {
11191                    match ch {
11192                        ' ' => {
11193                            reindented_line.push(' ');
11194                            col += 1;
11195                        }
11196                        '\t' => {
11197                            // \t are converted to spaces depending on the current column
11198                            let spaces_len = tab_size - (col % tab_size);
11199                            reindented_line.extend(&space_cache[spaces_len - 1]);
11200                            col += spaces_len;
11201                            changed = true;
11202                        }
11203                        _ => {
11204                            // If we dont append before break, the character is consumed
11205                            reindented_line.push(ch);
11206                            break;
11207                        }
11208                    }
11209                }
11210
11211                if !changed {
11212                    reindented_line.clear();
11213                    continue;
11214                }
11215                // Append the rest of the line and replace old reference with new one
11216                reindented_line.extend(chars);
11217                *line = Cow::Owned(reindented_line.clone());
11218                reindented_line.clear();
11219            }
11220        });
11221    }
11222
11223    pub fn convert_indentation_to_tabs(
11224        &mut self,
11225        _: &ConvertIndentationToTabs,
11226        window: &mut Window,
11227        cx: &mut Context<Self>,
11228    ) {
11229        let settings = self.buffer.read(cx).language_settings(cx);
11230        let tab_size = settings.tab_size.get() as usize;
11231
11232        self.manipulate_mutable_lines(window, cx, |lines| {
11233            // Allocates a reasonably sized buffer once for the whole loop
11234            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11235            // Avoids recomputing spaces that could be inserted many times
11236            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11237                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11238                .collect();
11239
11240            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11241                let mut chars = line.chars();
11242                let mut spaces_count = 0;
11243                let mut first_non_indent_char = None;
11244                let mut changed = false;
11245
11246                for ch in chars.by_ref() {
11247                    match ch {
11248                        ' ' => {
11249                            // Keep track of spaces. Append \t when we reach tab_size
11250                            spaces_count += 1;
11251                            changed = true;
11252                            if spaces_count == tab_size {
11253                                reindented_line.push('\t');
11254                                spaces_count = 0;
11255                            }
11256                        }
11257                        '\t' => {
11258                            reindented_line.push('\t');
11259                            spaces_count = 0;
11260                        }
11261                        _ => {
11262                            // Dont append it yet, we might have remaining spaces
11263                            first_non_indent_char = Some(ch);
11264                            break;
11265                        }
11266                    }
11267                }
11268
11269                if !changed {
11270                    reindented_line.clear();
11271                    continue;
11272                }
11273                // Remaining spaces that didn't make a full tab stop
11274                if spaces_count > 0 {
11275                    reindented_line.extend(&space_cache[spaces_count - 1]);
11276                }
11277                // If we consume an extra character that was not indentation, add it back
11278                if let Some(extra_char) = first_non_indent_char {
11279                    reindented_line.push(extra_char);
11280                }
11281                // Append the rest of the line and replace old reference with new one
11282                reindented_line.extend(chars);
11283                *line = Cow::Owned(reindented_line.clone());
11284                reindented_line.clear();
11285            }
11286        });
11287    }
11288
11289    pub fn convert_to_upper_case(
11290        &mut self,
11291        _: &ConvertToUpperCase,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.manipulate_text(window, cx, |text| text.to_uppercase())
11296    }
11297
11298    pub fn convert_to_lower_case(
11299        &mut self,
11300        _: &ConvertToLowerCase,
11301        window: &mut Window,
11302        cx: &mut Context<Self>,
11303    ) {
11304        self.manipulate_text(window, cx, |text| text.to_lowercase())
11305    }
11306
11307    pub fn convert_to_title_case(
11308        &mut self,
11309        _: &ConvertToTitleCase,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.manipulate_text(window, cx, |text| {
11314            text.split('\n')
11315                .map(|line| line.to_case(Case::Title))
11316                .join("\n")
11317        })
11318    }
11319
11320    pub fn convert_to_snake_case(
11321        &mut self,
11322        _: &ConvertToSnakeCase,
11323        window: &mut Window,
11324        cx: &mut Context<Self>,
11325    ) {
11326        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11327    }
11328
11329    pub fn convert_to_kebab_case(
11330        &mut self,
11331        _: &ConvertToKebabCase,
11332        window: &mut Window,
11333        cx: &mut Context<Self>,
11334    ) {
11335        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11336    }
11337
11338    pub fn convert_to_upper_camel_case(
11339        &mut self,
11340        _: &ConvertToUpperCamelCase,
11341        window: &mut Window,
11342        cx: &mut Context<Self>,
11343    ) {
11344        self.manipulate_text(window, cx, |text| {
11345            text.split('\n')
11346                .map(|line| line.to_case(Case::UpperCamel))
11347                .join("\n")
11348        })
11349    }
11350
11351    pub fn convert_to_lower_camel_case(
11352        &mut self,
11353        _: &ConvertToLowerCamelCase,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11358    }
11359
11360    pub fn convert_to_opposite_case(
11361        &mut self,
11362        _: &ConvertToOppositeCase,
11363        window: &mut Window,
11364        cx: &mut Context<Self>,
11365    ) {
11366        self.manipulate_text(window, cx, |text| {
11367            text.chars()
11368                .fold(String::with_capacity(text.len()), |mut t, c| {
11369                    if c.is_uppercase() {
11370                        t.extend(c.to_lowercase());
11371                    } else {
11372                        t.extend(c.to_uppercase());
11373                    }
11374                    t
11375                })
11376        })
11377    }
11378
11379    pub fn convert_to_sentence_case(
11380        &mut self,
11381        _: &ConvertToSentenceCase,
11382        window: &mut Window,
11383        cx: &mut Context<Self>,
11384    ) {
11385        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11386    }
11387
11388    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11389        self.manipulate_text(window, cx, |text| {
11390            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11391            if has_upper_case_characters {
11392                text.to_lowercase()
11393            } else {
11394                text.to_uppercase()
11395            }
11396        })
11397    }
11398
11399    pub fn convert_to_rot13(
11400        &mut self,
11401        _: &ConvertToRot13,
11402        window: &mut Window,
11403        cx: &mut Context<Self>,
11404    ) {
11405        self.manipulate_text(window, cx, |text| {
11406            text.chars()
11407                .map(|c| match c {
11408                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11409                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11410                    _ => c,
11411                })
11412                .collect()
11413        })
11414    }
11415
11416    pub fn convert_to_rot47(
11417        &mut self,
11418        _: &ConvertToRot47,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        self.manipulate_text(window, cx, |text| {
11423            text.chars()
11424                .map(|c| {
11425                    let code_point = c as u32;
11426                    if code_point >= 33 && code_point <= 126 {
11427                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11428                    }
11429                    c
11430                })
11431                .collect()
11432        })
11433    }
11434
11435    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11436    where
11437        Fn: FnMut(&str) -> String,
11438    {
11439        let buffer = self.buffer.read(cx).snapshot(cx);
11440
11441        let mut new_selections = Vec::new();
11442        let mut edits = Vec::new();
11443        let mut selection_adjustment = 0i32;
11444
11445        for selection in self.selections.all_adjusted(cx) {
11446            let selection_is_empty = selection.is_empty();
11447
11448            let (start, end) = if selection_is_empty {
11449                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11450                (word_range.start, word_range.end)
11451            } else {
11452                (
11453                    buffer.point_to_offset(selection.start),
11454                    buffer.point_to_offset(selection.end),
11455                )
11456            };
11457
11458            let text = buffer.text_for_range(start..end).collect::<String>();
11459            let old_length = text.len() as i32;
11460            let text = callback(&text);
11461
11462            new_selections.push(Selection {
11463                start: (start as i32 - selection_adjustment) as usize,
11464                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11465                goal: SelectionGoal::None,
11466                id: selection.id,
11467                reversed: selection.reversed,
11468            });
11469
11470            selection_adjustment += old_length - text.len() as i32;
11471
11472            edits.push((start..end, text));
11473        }
11474
11475        self.transact(window, cx, |this, window, cx| {
11476            this.buffer.update(cx, |buffer, cx| {
11477                buffer.edit(edits, None, cx);
11478            });
11479
11480            this.change_selections(Default::default(), window, cx, |s| {
11481                s.select(new_selections);
11482            });
11483
11484            this.request_autoscroll(Autoscroll::fit(), cx);
11485        });
11486    }
11487
11488    pub fn move_selection_on_drop(
11489        &mut self,
11490        selection: &Selection<Anchor>,
11491        target: DisplayPoint,
11492        is_cut: bool,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) {
11496        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11497        let buffer = &display_map.buffer_snapshot;
11498        let mut edits = Vec::new();
11499        let insert_point = display_map
11500            .clip_point(target, Bias::Left)
11501            .to_point(&display_map);
11502        let text = buffer
11503            .text_for_range(selection.start..selection.end)
11504            .collect::<String>();
11505        if is_cut {
11506            edits.push(((selection.start..selection.end), String::new()));
11507        }
11508        let insert_anchor = buffer.anchor_before(insert_point);
11509        edits.push(((insert_anchor..insert_anchor), text));
11510        let last_edit_start = insert_anchor.bias_left(buffer);
11511        let last_edit_end = insert_anchor.bias_right(buffer);
11512        self.transact(window, cx, |this, window, cx| {
11513            this.buffer.update(cx, |buffer, cx| {
11514                buffer.edit(edits, None, cx);
11515            });
11516            this.change_selections(Default::default(), window, cx, |s| {
11517                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11518            });
11519        });
11520    }
11521
11522    pub fn clear_selection_drag_state(&mut self) {
11523        self.selection_drag_state = SelectionDragState::None;
11524    }
11525
11526    pub fn duplicate(
11527        &mut self,
11528        upwards: bool,
11529        whole_lines: bool,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11534
11535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11536        let buffer = &display_map.buffer_snapshot;
11537        let selections = self.selections.all::<Point>(cx);
11538
11539        let mut edits = Vec::new();
11540        let mut selections_iter = selections.iter().peekable();
11541        while let Some(selection) = selections_iter.next() {
11542            let mut rows = selection.spanned_rows(false, &display_map);
11543            // duplicate line-wise
11544            if whole_lines || selection.start == selection.end {
11545                // Avoid duplicating the same lines twice.
11546                while let Some(next_selection) = selections_iter.peek() {
11547                    let next_rows = next_selection.spanned_rows(false, &display_map);
11548                    if next_rows.start < rows.end {
11549                        rows.end = next_rows.end;
11550                        selections_iter.next().unwrap();
11551                    } else {
11552                        break;
11553                    }
11554                }
11555
11556                // Copy the text from the selected row region and splice it either at the start
11557                // or end of the region.
11558                let start = Point::new(rows.start.0, 0);
11559                let end = Point::new(
11560                    rows.end.previous_row().0,
11561                    buffer.line_len(rows.end.previous_row()),
11562                );
11563                let text = buffer
11564                    .text_for_range(start..end)
11565                    .chain(Some("\n"))
11566                    .collect::<String>();
11567                let insert_location = if upwards {
11568                    Point::new(rows.end.0, 0)
11569                } else {
11570                    start
11571                };
11572                edits.push((insert_location..insert_location, text));
11573            } else {
11574                // duplicate character-wise
11575                let start = selection.start;
11576                let end = selection.end;
11577                let text = buffer.text_for_range(start..end).collect::<String>();
11578                edits.push((selection.end..selection.end, text));
11579            }
11580        }
11581
11582        self.transact(window, cx, |this, _, cx| {
11583            this.buffer.update(cx, |buffer, cx| {
11584                buffer.edit(edits, None, cx);
11585            });
11586
11587            this.request_autoscroll(Autoscroll::fit(), cx);
11588        });
11589    }
11590
11591    pub fn duplicate_line_up(
11592        &mut self,
11593        _: &DuplicateLineUp,
11594        window: &mut Window,
11595        cx: &mut Context<Self>,
11596    ) {
11597        self.duplicate(true, true, window, cx);
11598    }
11599
11600    pub fn duplicate_line_down(
11601        &mut self,
11602        _: &DuplicateLineDown,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        self.duplicate(false, true, window, cx);
11607    }
11608
11609    pub fn duplicate_selection(
11610        &mut self,
11611        _: &DuplicateSelection,
11612        window: &mut Window,
11613        cx: &mut Context<Self>,
11614    ) {
11615        self.duplicate(false, false, window, cx);
11616    }
11617
11618    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11619        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11620        if self.mode.is_single_line() {
11621            cx.propagate();
11622            return;
11623        }
11624
11625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11626        let buffer = self.buffer.read(cx).snapshot(cx);
11627
11628        let mut edits = Vec::new();
11629        let mut unfold_ranges = Vec::new();
11630        let mut refold_creases = Vec::new();
11631
11632        let selections = self.selections.all::<Point>(cx);
11633        let mut selections = selections.iter().peekable();
11634        let mut contiguous_row_selections = Vec::new();
11635        let mut new_selections = Vec::new();
11636
11637        while let Some(selection) = selections.next() {
11638            // Find all the selections that span a contiguous row range
11639            let (start_row, end_row) = consume_contiguous_rows(
11640                &mut contiguous_row_selections,
11641                selection,
11642                &display_map,
11643                &mut selections,
11644            );
11645
11646            // Move the text spanned by the row range to be before the line preceding the row range
11647            if start_row.0 > 0 {
11648                let range_to_move = Point::new(
11649                    start_row.previous_row().0,
11650                    buffer.line_len(start_row.previous_row()),
11651                )
11652                    ..Point::new(
11653                        end_row.previous_row().0,
11654                        buffer.line_len(end_row.previous_row()),
11655                    );
11656                let insertion_point = display_map
11657                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11658                    .0;
11659
11660                // Don't move lines across excerpts
11661                if buffer
11662                    .excerpt_containing(insertion_point..range_to_move.end)
11663                    .is_some()
11664                {
11665                    let text = buffer
11666                        .text_for_range(range_to_move.clone())
11667                        .flat_map(|s| s.chars())
11668                        .skip(1)
11669                        .chain(['\n'])
11670                        .collect::<String>();
11671
11672                    edits.push((
11673                        buffer.anchor_after(range_to_move.start)
11674                            ..buffer.anchor_before(range_to_move.end),
11675                        String::new(),
11676                    ));
11677                    let insertion_anchor = buffer.anchor_after(insertion_point);
11678                    edits.push((insertion_anchor..insertion_anchor, text));
11679
11680                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11681
11682                    // Move selections up
11683                    new_selections.extend(contiguous_row_selections.drain(..).map(
11684                        |mut selection| {
11685                            selection.start.row -= row_delta;
11686                            selection.end.row -= row_delta;
11687                            selection
11688                        },
11689                    ));
11690
11691                    // Move folds up
11692                    unfold_ranges.push(range_to_move.clone());
11693                    for fold in display_map.folds_in_range(
11694                        buffer.anchor_before(range_to_move.start)
11695                            ..buffer.anchor_after(range_to_move.end),
11696                    ) {
11697                        let mut start = fold.range.start.to_point(&buffer);
11698                        let mut end = fold.range.end.to_point(&buffer);
11699                        start.row -= row_delta;
11700                        end.row -= row_delta;
11701                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11702                    }
11703                }
11704            }
11705
11706            // If we didn't move line(s), preserve the existing selections
11707            new_selections.append(&mut contiguous_row_selections);
11708        }
11709
11710        self.transact(window, cx, |this, window, cx| {
11711            this.unfold_ranges(&unfold_ranges, true, true, cx);
11712            this.buffer.update(cx, |buffer, cx| {
11713                for (range, text) in edits {
11714                    buffer.edit([(range, text)], None, cx);
11715                }
11716            });
11717            this.fold_creases(refold_creases, true, window, cx);
11718            this.change_selections(Default::default(), window, cx, |s| {
11719                s.select(new_selections);
11720            })
11721        });
11722    }
11723
11724    pub fn move_line_down(
11725        &mut self,
11726        _: &MoveLineDown,
11727        window: &mut Window,
11728        cx: &mut Context<Self>,
11729    ) {
11730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11731        if self.mode.is_single_line() {
11732            cx.propagate();
11733            return;
11734        }
11735
11736        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11737        let buffer = self.buffer.read(cx).snapshot(cx);
11738
11739        let mut edits = Vec::new();
11740        let mut unfold_ranges = Vec::new();
11741        let mut refold_creases = Vec::new();
11742
11743        let selections = self.selections.all::<Point>(cx);
11744        let mut selections = selections.iter().peekable();
11745        let mut contiguous_row_selections = Vec::new();
11746        let mut new_selections = Vec::new();
11747
11748        while let Some(selection) = selections.next() {
11749            // Find all the selections that span a contiguous row range
11750            let (start_row, end_row) = consume_contiguous_rows(
11751                &mut contiguous_row_selections,
11752                selection,
11753                &display_map,
11754                &mut selections,
11755            );
11756
11757            // Move the text spanned by the row range to be after the last line of the row range
11758            if end_row.0 <= buffer.max_point().row {
11759                let range_to_move =
11760                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11761                let insertion_point = display_map
11762                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11763                    .0;
11764
11765                // Don't move lines across excerpt boundaries
11766                if buffer
11767                    .excerpt_containing(range_to_move.start..insertion_point)
11768                    .is_some()
11769                {
11770                    let mut text = String::from("\n");
11771                    text.extend(buffer.text_for_range(range_to_move.clone()));
11772                    text.pop(); // Drop trailing newline
11773                    edits.push((
11774                        buffer.anchor_after(range_to_move.start)
11775                            ..buffer.anchor_before(range_to_move.end),
11776                        String::new(),
11777                    ));
11778                    let insertion_anchor = buffer.anchor_after(insertion_point);
11779                    edits.push((insertion_anchor..insertion_anchor, text));
11780
11781                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11782
11783                    // Move selections down
11784                    new_selections.extend(contiguous_row_selections.drain(..).map(
11785                        |mut selection| {
11786                            selection.start.row += row_delta;
11787                            selection.end.row += row_delta;
11788                            selection
11789                        },
11790                    ));
11791
11792                    // Move folds down
11793                    unfold_ranges.push(range_to_move.clone());
11794                    for fold in display_map.folds_in_range(
11795                        buffer.anchor_before(range_to_move.start)
11796                            ..buffer.anchor_after(range_to_move.end),
11797                    ) {
11798                        let mut start = fold.range.start.to_point(&buffer);
11799                        let mut end = fold.range.end.to_point(&buffer);
11800                        start.row += row_delta;
11801                        end.row += row_delta;
11802                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11803                    }
11804                }
11805            }
11806
11807            // If we didn't move line(s), preserve the existing selections
11808            new_selections.append(&mut contiguous_row_selections);
11809        }
11810
11811        self.transact(window, cx, |this, window, cx| {
11812            this.unfold_ranges(&unfold_ranges, true, true, cx);
11813            this.buffer.update(cx, |buffer, cx| {
11814                for (range, text) in edits {
11815                    buffer.edit([(range, text)], None, cx);
11816                }
11817            });
11818            this.fold_creases(refold_creases, true, window, cx);
11819            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11820        });
11821    }
11822
11823    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11825        let text_layout_details = &self.text_layout_details(window);
11826        self.transact(window, cx, |this, window, cx| {
11827            let edits = this.change_selections(Default::default(), window, cx, |s| {
11828                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11829                s.move_with(|display_map, selection| {
11830                    if !selection.is_empty() {
11831                        return;
11832                    }
11833
11834                    let mut head = selection.head();
11835                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11836                    if head.column() == display_map.line_len(head.row()) {
11837                        transpose_offset = display_map
11838                            .buffer_snapshot
11839                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11840                    }
11841
11842                    if transpose_offset == 0 {
11843                        return;
11844                    }
11845
11846                    *head.column_mut() += 1;
11847                    head = display_map.clip_point(head, Bias::Right);
11848                    let goal = SelectionGoal::HorizontalPosition(
11849                        display_map
11850                            .x_for_display_point(head, text_layout_details)
11851                            .into(),
11852                    );
11853                    selection.collapse_to(head, goal);
11854
11855                    let transpose_start = display_map
11856                        .buffer_snapshot
11857                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11858                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11859                        let transpose_end = display_map
11860                            .buffer_snapshot
11861                            .clip_offset(transpose_offset + 1, Bias::Right);
11862                        if let Some(ch) =
11863                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11864                        {
11865                            edits.push((transpose_start..transpose_offset, String::new()));
11866                            edits.push((transpose_end..transpose_end, ch.to_string()));
11867                        }
11868                    }
11869                });
11870                edits
11871            });
11872            this.buffer
11873                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11874            let selections = this.selections.all::<usize>(cx);
11875            this.change_selections(Default::default(), window, cx, |s| {
11876                s.select(selections);
11877            });
11878        });
11879    }
11880
11881    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11883        if self.mode.is_single_line() {
11884            cx.propagate();
11885            return;
11886        }
11887
11888        self.rewrap_impl(RewrapOptions::default(), cx)
11889    }
11890
11891    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11892        let buffer = self.buffer.read(cx).snapshot(cx);
11893        let selections = self.selections.all::<Point>(cx);
11894
11895        #[derive(Clone, Debug, PartialEq)]
11896        enum CommentFormat {
11897            /// single line comment, with prefix for line
11898            Line(String),
11899            /// single line within a block comment, with prefix for line
11900            BlockLine(String),
11901            /// a single line of a block comment that includes the initial delimiter
11902            BlockCommentWithStart(BlockCommentConfig),
11903            /// a single line of a block comment that includes the ending delimiter
11904            BlockCommentWithEnd(BlockCommentConfig),
11905        }
11906
11907        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11908        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11909            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11910                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11911                .peekable();
11912
11913            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11914                row
11915            } else {
11916                return Vec::new();
11917            };
11918
11919            let language_settings = buffer.language_settings_at(selection.head(), cx);
11920            let language_scope = buffer.language_scope_at(selection.head());
11921
11922            let indent_and_prefix_for_row =
11923                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11924                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11925                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11926                        &language_scope
11927                    {
11928                        let indent_end = Point::new(row, indent.len);
11929                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11930                        let line_text_after_indent = buffer
11931                            .text_for_range(indent_end..line_end)
11932                            .collect::<String>();
11933
11934                        let is_within_comment_override = buffer
11935                            .language_scope_at(indent_end)
11936                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11937                        let comment_delimiters = if is_within_comment_override {
11938                            // we are within a comment syntax node, but we don't
11939                            // yet know what kind of comment: block, doc or line
11940                            match (
11941                                language_scope.documentation_comment(),
11942                                language_scope.block_comment(),
11943                            ) {
11944                                (Some(config), _) | (_, Some(config))
11945                                    if buffer.contains_str_at(indent_end, &config.start) =>
11946                                {
11947                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11948                                }
11949                                (Some(config), _) | (_, Some(config))
11950                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11951                                {
11952                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11953                                }
11954                                (Some(config), _) | (_, Some(config))
11955                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11956                                {
11957                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11958                                }
11959                                (_, _) => language_scope
11960                                    .line_comment_prefixes()
11961                                    .iter()
11962                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11963                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11964                            }
11965                        } else {
11966                            // we not in an overridden comment node, but we may
11967                            // be within a non-overridden line comment node
11968                            language_scope
11969                                .line_comment_prefixes()
11970                                .iter()
11971                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11972                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11973                        };
11974
11975                        let rewrap_prefix = language_scope
11976                            .rewrap_prefixes()
11977                            .iter()
11978                            .find_map(|prefix_regex| {
11979                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11980                                    if mat.start() == 0 {
11981                                        Some(mat.as_str().to_string())
11982                                    } else {
11983                                        None
11984                                    }
11985                                })
11986                            })
11987                            .flatten();
11988                        (comment_delimiters, rewrap_prefix)
11989                    } else {
11990                        (None, None)
11991                    };
11992                    (indent, comment_prefix, rewrap_prefix)
11993                };
11994
11995            let mut ranges = Vec::new();
11996            let from_empty_selection = selection.is_empty();
11997
11998            let mut current_range_start = first_row;
11999            let mut prev_row = first_row;
12000            let (
12001                mut current_range_indent,
12002                mut current_range_comment_delimiters,
12003                mut current_range_rewrap_prefix,
12004            ) = indent_and_prefix_for_row(first_row);
12005
12006            for row in non_blank_rows_iter.skip(1) {
12007                let has_paragraph_break = row > prev_row + 1;
12008
12009                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12010                    indent_and_prefix_for_row(row);
12011
12012                let has_indent_change = row_indent != current_range_indent;
12013                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12014
12015                let has_boundary_change = has_comment_change
12016                    || row_rewrap_prefix.is_some()
12017                    || (has_indent_change && current_range_comment_delimiters.is_some());
12018
12019                if has_paragraph_break || has_boundary_change {
12020                    ranges.push((
12021                        language_settings.clone(),
12022                        Point::new(current_range_start, 0)
12023                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12024                        current_range_indent,
12025                        current_range_comment_delimiters.clone(),
12026                        current_range_rewrap_prefix.clone(),
12027                        from_empty_selection,
12028                    ));
12029                    current_range_start = row;
12030                    current_range_indent = row_indent;
12031                    current_range_comment_delimiters = row_comment_delimiters;
12032                    current_range_rewrap_prefix = row_rewrap_prefix;
12033                }
12034                prev_row = row;
12035            }
12036
12037            ranges.push((
12038                language_settings.clone(),
12039                Point::new(current_range_start, 0)
12040                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12041                current_range_indent,
12042                current_range_comment_delimiters,
12043                current_range_rewrap_prefix,
12044                from_empty_selection,
12045            ));
12046
12047            ranges
12048        });
12049
12050        let mut edits = Vec::new();
12051        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12052
12053        for (
12054            language_settings,
12055            wrap_range,
12056            mut indent_size,
12057            comment_prefix,
12058            rewrap_prefix,
12059            from_empty_selection,
12060        ) in wrap_ranges
12061        {
12062            let mut start_row = wrap_range.start.row;
12063            let mut end_row = wrap_range.end.row;
12064
12065            // Skip selections that overlap with a range that has already been rewrapped.
12066            let selection_range = start_row..end_row;
12067            if rewrapped_row_ranges
12068                .iter()
12069                .any(|range| range.overlaps(&selection_range))
12070            {
12071                continue;
12072            }
12073
12074            let tab_size = language_settings.tab_size;
12075
12076            let (line_prefix, inside_comment) = match &comment_prefix {
12077                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12078                    (Some(prefix.as_str()), true)
12079                }
12080                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12081                    (Some(prefix.as_ref()), true)
12082                }
12083                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12084                    start: _,
12085                    end: _,
12086                    prefix,
12087                    tab_size,
12088                })) => {
12089                    indent_size.len += tab_size;
12090                    (Some(prefix.as_ref()), true)
12091                }
12092                None => (None, false),
12093            };
12094            let indent_prefix = indent_size.chars().collect::<String>();
12095            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12096
12097            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12098                RewrapBehavior::InComments => inside_comment,
12099                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12100                RewrapBehavior::Anywhere => true,
12101            };
12102
12103            let should_rewrap = options.override_language_settings
12104                || allow_rewrap_based_on_language
12105                || self.hard_wrap.is_some();
12106            if !should_rewrap {
12107                continue;
12108            }
12109
12110            if from_empty_selection {
12111                'expand_upwards: while start_row > 0 {
12112                    let prev_row = start_row - 1;
12113                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12114                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12115                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12116                    {
12117                        start_row = prev_row;
12118                    } else {
12119                        break 'expand_upwards;
12120                    }
12121                }
12122
12123                'expand_downwards: while end_row < buffer.max_point().row {
12124                    let next_row = end_row + 1;
12125                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12126                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12127                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12128                    {
12129                        end_row = next_row;
12130                    } else {
12131                        break 'expand_downwards;
12132                    }
12133                }
12134            }
12135
12136            let start = Point::new(start_row, 0);
12137            let start_offset = start.to_offset(&buffer);
12138            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12139            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12140            let mut first_line_delimiter = None;
12141            let mut last_line_delimiter = None;
12142            let Some(lines_without_prefixes) = selection_text
12143                .lines()
12144                .enumerate()
12145                .map(|(ix, line)| {
12146                    let line_trimmed = line.trim_start();
12147                    if rewrap_prefix.is_some() && ix > 0 {
12148                        Ok(line_trimmed)
12149                    } else if let Some(
12150                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12151                            start,
12152                            prefix,
12153                            end,
12154                            tab_size,
12155                        })
12156                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12157                            start,
12158                            prefix,
12159                            end,
12160                            tab_size,
12161                        }),
12162                    ) = &comment_prefix
12163                    {
12164                        let line_trimmed = line_trimmed
12165                            .strip_prefix(start.as_ref())
12166                            .map(|s| {
12167                                let mut indent_size = indent_size;
12168                                indent_size.len -= tab_size;
12169                                let indent_prefix: String = indent_size.chars().collect();
12170                                first_line_delimiter = Some((indent_prefix, start));
12171                                s.trim_start()
12172                            })
12173                            .unwrap_or(line_trimmed);
12174                        let line_trimmed = line_trimmed
12175                            .strip_suffix(end.as_ref())
12176                            .map(|s| {
12177                                last_line_delimiter = Some(end);
12178                                s.trim_end()
12179                            })
12180                            .unwrap_or(line_trimmed);
12181                        let line_trimmed = line_trimmed
12182                            .strip_prefix(prefix.as_ref())
12183                            .unwrap_or(line_trimmed);
12184                        Ok(line_trimmed)
12185                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12186                        line_trimmed.strip_prefix(prefix).with_context(|| {
12187                            format!("line did not start with prefix {prefix:?}: {line:?}")
12188                        })
12189                    } else {
12190                        line_trimmed
12191                            .strip_prefix(&line_prefix.trim_start())
12192                            .with_context(|| {
12193                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12194                            })
12195                    }
12196                })
12197                .collect::<Result<Vec<_>, _>>()
12198                .log_err()
12199            else {
12200                continue;
12201            };
12202
12203            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12204                buffer
12205                    .language_settings_at(Point::new(start_row, 0), cx)
12206                    .preferred_line_length as usize
12207            });
12208
12209            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12210                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12211            } else {
12212                line_prefix.clone()
12213            };
12214
12215            let wrapped_text = {
12216                let mut wrapped_text = wrap_with_prefix(
12217                    line_prefix,
12218                    subsequent_lines_prefix,
12219                    lines_without_prefixes.join("\n"),
12220                    wrap_column,
12221                    tab_size,
12222                    options.preserve_existing_whitespace,
12223                );
12224
12225                if let Some((indent, delimiter)) = first_line_delimiter {
12226                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12227                }
12228                if let Some(last_line) = last_line_delimiter {
12229                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12230                }
12231
12232                wrapped_text
12233            };
12234
12235            // TODO: should always use char-based diff while still supporting cursor behavior that
12236            // matches vim.
12237            let mut diff_options = DiffOptions::default();
12238            if options.override_language_settings {
12239                diff_options.max_word_diff_len = 0;
12240                diff_options.max_word_diff_line_count = 0;
12241            } else {
12242                diff_options.max_word_diff_len = usize::MAX;
12243                diff_options.max_word_diff_line_count = usize::MAX;
12244            }
12245
12246            for (old_range, new_text) in
12247                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12248            {
12249                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12250                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12251                edits.push((edit_start..edit_end, new_text));
12252            }
12253
12254            rewrapped_row_ranges.push(start_row..=end_row);
12255        }
12256
12257        self.buffer
12258            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12259    }
12260
12261    pub fn cut_common(
12262        &mut self,
12263        cut_no_selection_line: bool,
12264        window: &mut Window,
12265        cx: &mut Context<Self>,
12266    ) -> ClipboardItem {
12267        let mut text = String::new();
12268        let buffer = self.buffer.read(cx).snapshot(cx);
12269        let mut selections = self.selections.all::<Point>(cx);
12270        let mut clipboard_selections = Vec::with_capacity(selections.len());
12271        {
12272            let max_point = buffer.max_point();
12273            let mut is_first = true;
12274            for selection in &mut selections {
12275                let is_entire_line =
12276                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12277                if is_entire_line {
12278                    selection.start = Point::new(selection.start.row, 0);
12279                    if !selection.is_empty() && selection.end.column == 0 {
12280                        selection.end = cmp::min(max_point, selection.end);
12281                    } else {
12282                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12283                    }
12284                    selection.goal = SelectionGoal::None;
12285                }
12286                if is_first {
12287                    is_first = false;
12288                } else {
12289                    text += "\n";
12290                }
12291                let mut len = 0;
12292                for chunk in buffer.text_for_range(selection.start..selection.end) {
12293                    text.push_str(chunk);
12294                    len += chunk.len();
12295                }
12296                clipboard_selections.push(ClipboardSelection {
12297                    len,
12298                    is_entire_line,
12299                    first_line_indent: buffer
12300                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12301                        .len,
12302                });
12303            }
12304        }
12305
12306        self.transact(window, cx, |this, window, cx| {
12307            this.change_selections(Default::default(), window, cx, |s| {
12308                s.select(selections);
12309            });
12310            this.insert("", window, cx);
12311        });
12312        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12313    }
12314
12315    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12317        let item = self.cut_common(true, window, cx);
12318        cx.write_to_clipboard(item);
12319    }
12320
12321    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12323        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12324            s.move_with(|snapshot, sel| {
12325                if sel.is_empty() {
12326                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12327                }
12328                if sel.is_empty() {
12329                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12330                }
12331            });
12332        });
12333        let item = self.cut_common(true, window, cx);
12334        cx.set_global(KillRing(item))
12335    }
12336
12337    pub fn kill_ring_yank(
12338        &mut self,
12339        _: &KillRingYank,
12340        window: &mut Window,
12341        cx: &mut Context<Self>,
12342    ) {
12343        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12344        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12345            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12346                (kill_ring.text().to_string(), kill_ring.metadata_json())
12347            } else {
12348                return;
12349            }
12350        } else {
12351            return;
12352        };
12353        self.do_paste(&text, metadata, false, window, cx);
12354    }
12355
12356    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12357        self.do_copy(true, cx);
12358    }
12359
12360    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12361        self.do_copy(false, cx);
12362    }
12363
12364    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12365        let selections = self.selections.all::<Point>(cx);
12366        let buffer = self.buffer.read(cx).read(cx);
12367        let mut text = String::new();
12368
12369        let mut clipboard_selections = Vec::with_capacity(selections.len());
12370        {
12371            let max_point = buffer.max_point();
12372            let mut is_first = true;
12373            for selection in &selections {
12374                let mut start = selection.start;
12375                let mut end = selection.end;
12376                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12377                if is_entire_line {
12378                    start = Point::new(start.row, 0);
12379                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12380                }
12381
12382                let mut trimmed_selections = Vec::new();
12383                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12384                    let row = MultiBufferRow(start.row);
12385                    let first_indent = buffer.indent_size_for_line(row);
12386                    if first_indent.len == 0 || start.column > first_indent.len {
12387                        trimmed_selections.push(start..end);
12388                    } else {
12389                        trimmed_selections.push(
12390                            Point::new(row.0, first_indent.len)
12391                                ..Point::new(row.0, buffer.line_len(row)),
12392                        );
12393                        for row in start.row + 1..=end.row {
12394                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12395                            if row == end.row {
12396                                line_len = end.column;
12397                            }
12398                            if line_len == 0 {
12399                                trimmed_selections
12400                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12401                                continue;
12402                            }
12403                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12404                            if row_indent_size.len >= first_indent.len {
12405                                trimmed_selections.push(
12406                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12407                                );
12408                            } else {
12409                                trimmed_selections.clear();
12410                                trimmed_selections.push(start..end);
12411                                break;
12412                            }
12413                        }
12414                    }
12415                } else {
12416                    trimmed_selections.push(start..end);
12417                }
12418
12419                for trimmed_range in trimmed_selections {
12420                    if is_first {
12421                        is_first = false;
12422                    } else {
12423                        text += "\n";
12424                    }
12425                    let mut len = 0;
12426                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12427                        text.push_str(chunk);
12428                        len += chunk.len();
12429                    }
12430                    clipboard_selections.push(ClipboardSelection {
12431                        len,
12432                        is_entire_line,
12433                        first_line_indent: buffer
12434                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12435                            .len,
12436                    });
12437                }
12438            }
12439        }
12440
12441        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12442            text,
12443            clipboard_selections,
12444        ));
12445    }
12446
12447    pub fn do_paste(
12448        &mut self,
12449        text: &String,
12450        clipboard_selections: Option<Vec<ClipboardSelection>>,
12451        handle_entire_lines: bool,
12452        window: &mut Window,
12453        cx: &mut Context<Self>,
12454    ) {
12455        if self.read_only(cx) {
12456            return;
12457        }
12458
12459        let clipboard_text = Cow::Borrowed(text.as_str());
12460
12461        self.transact(window, cx, |this, window, cx| {
12462            let had_active_edit_prediction = this.has_active_edit_prediction();
12463            let old_selections = this.selections.all::<usize>(cx);
12464            let cursor_offset = this.selections.last::<usize>(cx).head();
12465
12466            if let Some(mut clipboard_selections) = clipboard_selections {
12467                let all_selections_were_entire_line =
12468                    clipboard_selections.iter().all(|s| s.is_entire_line);
12469                let first_selection_indent_column =
12470                    clipboard_selections.first().map(|s| s.first_line_indent);
12471                if clipboard_selections.len() != old_selections.len() {
12472                    clipboard_selections.drain(..);
12473                }
12474                let mut auto_indent_on_paste = true;
12475
12476                this.buffer.update(cx, |buffer, cx| {
12477                    let snapshot = buffer.read(cx);
12478                    auto_indent_on_paste = snapshot
12479                        .language_settings_at(cursor_offset, cx)
12480                        .auto_indent_on_paste;
12481
12482                    let mut start_offset = 0;
12483                    let mut edits = Vec::new();
12484                    let mut original_indent_columns = Vec::new();
12485                    for (ix, selection) in old_selections.iter().enumerate() {
12486                        let to_insert;
12487                        let entire_line;
12488                        let original_indent_column;
12489                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12490                            let end_offset = start_offset + clipboard_selection.len;
12491                            to_insert = &clipboard_text[start_offset..end_offset];
12492                            entire_line = clipboard_selection.is_entire_line;
12493                            start_offset = end_offset + 1;
12494                            original_indent_column = Some(clipboard_selection.first_line_indent);
12495                        } else {
12496                            to_insert = &*clipboard_text;
12497                            entire_line = all_selections_were_entire_line;
12498                            original_indent_column = first_selection_indent_column
12499                        }
12500
12501                        let (range, to_insert) =
12502                            if selection.is_empty() && handle_entire_lines && entire_line {
12503                                // If the corresponding selection was empty when this slice of the
12504                                // clipboard text was written, then the entire line containing the
12505                                // selection was copied. If this selection is also currently empty,
12506                                // then paste the line before the current line of the buffer.
12507                                let column = selection.start.to_point(&snapshot).column as usize;
12508                                let line_start = selection.start - column;
12509                                (line_start..line_start, Cow::Borrowed(to_insert))
12510                            } else {
12511                                let language = snapshot.language_at(selection.head());
12512                                let range = selection.range();
12513                                if let Some(language) = language
12514                                    && language.name() == "Markdown".into()
12515                                {
12516                                    edit_for_markdown_paste(
12517                                        &snapshot,
12518                                        range,
12519                                        to_insert,
12520                                        url::Url::parse(to_insert).ok(),
12521                                    )
12522                                } else {
12523                                    (range, Cow::Borrowed(to_insert))
12524                                }
12525                            };
12526
12527                        edits.push((range, to_insert));
12528                        original_indent_columns.push(original_indent_column);
12529                    }
12530                    drop(snapshot);
12531
12532                    buffer.edit(
12533                        edits,
12534                        if auto_indent_on_paste {
12535                            Some(AutoindentMode::Block {
12536                                original_indent_columns,
12537                            })
12538                        } else {
12539                            None
12540                        },
12541                        cx,
12542                    );
12543                });
12544
12545                let selections = this.selections.all::<usize>(cx);
12546                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12547            } else {
12548                let url = url::Url::parse(&clipboard_text).ok();
12549
12550                let auto_indent_mode = if !clipboard_text.is_empty() {
12551                    Some(AutoindentMode::Block {
12552                        original_indent_columns: Vec::new(),
12553                    })
12554                } else {
12555                    None
12556                };
12557
12558                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12559                    let snapshot = buffer.snapshot(cx);
12560
12561                    let anchors = old_selections
12562                        .iter()
12563                        .map(|s| {
12564                            let anchor = snapshot.anchor_after(s.head());
12565                            s.map(|_| anchor)
12566                        })
12567                        .collect::<Vec<_>>();
12568
12569                    let mut edits = Vec::new();
12570
12571                    for selection in old_selections.iter() {
12572                        let language = snapshot.language_at(selection.head());
12573                        let range = selection.range();
12574
12575                        let (edit_range, edit_text) = if let Some(language) = language
12576                            && language.name() == "Markdown".into()
12577                        {
12578                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12579                        } else {
12580                            (range, clipboard_text.clone())
12581                        };
12582
12583                        edits.push((edit_range, edit_text));
12584                    }
12585
12586                    drop(snapshot);
12587                    buffer.edit(edits, auto_indent_mode, cx);
12588
12589                    anchors
12590                });
12591
12592                this.change_selections(Default::default(), window, cx, |s| {
12593                    s.select_anchors(selection_anchors);
12594                });
12595            }
12596
12597            let trigger_in_words =
12598                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12599
12600            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12601        });
12602    }
12603
12604    pub fn diff_clipboard_with_selection(
12605        &mut self,
12606        _: &DiffClipboardWithSelection,
12607        window: &mut Window,
12608        cx: &mut Context<Self>,
12609    ) {
12610        let selections = self.selections.all::<usize>(cx);
12611
12612        if selections.is_empty() {
12613            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12614            return;
12615        };
12616
12617        let clipboard_text = match cx.read_from_clipboard() {
12618            Some(item) => match item.entries().first() {
12619                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12620                _ => None,
12621            },
12622            None => None,
12623        };
12624
12625        let Some(clipboard_text) = clipboard_text else {
12626            log::warn!("Clipboard doesn't contain text.");
12627            return;
12628        };
12629
12630        window.dispatch_action(
12631            Box::new(DiffClipboardWithSelectionData {
12632                clipboard_text,
12633                editor: cx.entity(),
12634            }),
12635            cx,
12636        );
12637    }
12638
12639    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12641        if let Some(item) = cx.read_from_clipboard() {
12642            let entries = item.entries();
12643
12644            match entries.first() {
12645                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12646                // of all the pasted entries.
12647                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12648                    .do_paste(
12649                        clipboard_string.text(),
12650                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12651                        true,
12652                        window,
12653                        cx,
12654                    ),
12655                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12656            }
12657        }
12658    }
12659
12660    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12661        if self.read_only(cx) {
12662            return;
12663        }
12664
12665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12666
12667        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12668            if let Some((selections, _)) =
12669                self.selection_history.transaction(transaction_id).cloned()
12670            {
12671                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12672                    s.select_anchors(selections.to_vec());
12673                });
12674            } else {
12675                log::error!(
12676                    "No entry in selection_history found for undo. \
12677                     This may correspond to a bug where undo does not update the selection. \
12678                     If this is occurring, please add details to \
12679                     https://github.com/zed-industries/zed/issues/22692"
12680                );
12681            }
12682            self.request_autoscroll(Autoscroll::fit(), cx);
12683            self.unmark_text(window, cx);
12684            self.refresh_edit_prediction(true, false, window, cx);
12685            cx.emit(EditorEvent::Edited { transaction_id });
12686            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12687        }
12688    }
12689
12690    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12691        if self.read_only(cx) {
12692            return;
12693        }
12694
12695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12696
12697        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12698            if let Some((_, Some(selections))) =
12699                self.selection_history.transaction(transaction_id).cloned()
12700            {
12701                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12702                    s.select_anchors(selections.to_vec());
12703                });
12704            } else {
12705                log::error!(
12706                    "No entry in selection_history found for redo. \
12707                     This may correspond to a bug where undo does not update the selection. \
12708                     If this is occurring, please add details to \
12709                     https://github.com/zed-industries/zed/issues/22692"
12710                );
12711            }
12712            self.request_autoscroll(Autoscroll::fit(), cx);
12713            self.unmark_text(window, cx);
12714            self.refresh_edit_prediction(true, false, window, cx);
12715            cx.emit(EditorEvent::Edited { transaction_id });
12716        }
12717    }
12718
12719    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12720        self.buffer
12721            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12722    }
12723
12724    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12725        self.buffer
12726            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12727    }
12728
12729    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12731        self.change_selections(Default::default(), window, cx, |s| {
12732            s.move_with(|map, selection| {
12733                let cursor = if selection.is_empty() {
12734                    movement::left(map, selection.start)
12735                } else {
12736                    selection.start
12737                };
12738                selection.collapse_to(cursor, SelectionGoal::None);
12739            });
12740        })
12741    }
12742
12743    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12745        self.change_selections(Default::default(), window, cx, |s| {
12746            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12747        })
12748    }
12749
12750    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12752        self.change_selections(Default::default(), window, cx, |s| {
12753            s.move_with(|map, selection| {
12754                let cursor = if selection.is_empty() {
12755                    movement::right(map, selection.end)
12756                } else {
12757                    selection.end
12758                };
12759                selection.collapse_to(cursor, SelectionGoal::None)
12760            });
12761        })
12762    }
12763
12764    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12766        self.change_selections(Default::default(), window, cx, |s| {
12767            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12768        })
12769    }
12770
12771    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12772        if self.take_rename(true, window, cx).is_some() {
12773            return;
12774        }
12775
12776        if self.mode.is_single_line() {
12777            cx.propagate();
12778            return;
12779        }
12780
12781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12782
12783        let text_layout_details = &self.text_layout_details(window);
12784        let selection_count = self.selections.count();
12785        let first_selection = self.selections.first_anchor();
12786
12787        self.change_selections(Default::default(), window, cx, |s| {
12788            s.move_with(|map, selection| {
12789                if !selection.is_empty() {
12790                    selection.goal = SelectionGoal::None;
12791                }
12792                let (cursor, goal) = movement::up(
12793                    map,
12794                    selection.start,
12795                    selection.goal,
12796                    false,
12797                    text_layout_details,
12798                );
12799                selection.collapse_to(cursor, goal);
12800            });
12801        });
12802
12803        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12804        {
12805            cx.propagate();
12806        }
12807    }
12808
12809    pub fn move_up_by_lines(
12810        &mut self,
12811        action: &MoveUpByLines,
12812        window: &mut Window,
12813        cx: &mut Context<Self>,
12814    ) {
12815        if self.take_rename(true, window, cx).is_some() {
12816            return;
12817        }
12818
12819        if self.mode.is_single_line() {
12820            cx.propagate();
12821            return;
12822        }
12823
12824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12825
12826        let text_layout_details = &self.text_layout_details(window);
12827
12828        self.change_selections(Default::default(), window, cx, |s| {
12829            s.move_with(|map, selection| {
12830                if !selection.is_empty() {
12831                    selection.goal = SelectionGoal::None;
12832                }
12833                let (cursor, goal) = movement::up_by_rows(
12834                    map,
12835                    selection.start,
12836                    action.lines,
12837                    selection.goal,
12838                    false,
12839                    text_layout_details,
12840                );
12841                selection.collapse_to(cursor, goal);
12842            });
12843        })
12844    }
12845
12846    pub fn move_down_by_lines(
12847        &mut self,
12848        action: &MoveDownByLines,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        if self.take_rename(true, window, cx).is_some() {
12853            return;
12854        }
12855
12856        if self.mode.is_single_line() {
12857            cx.propagate();
12858            return;
12859        }
12860
12861        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12862
12863        let text_layout_details = &self.text_layout_details(window);
12864
12865        self.change_selections(Default::default(), window, cx, |s| {
12866            s.move_with(|map, selection| {
12867                if !selection.is_empty() {
12868                    selection.goal = SelectionGoal::None;
12869                }
12870                let (cursor, goal) = movement::down_by_rows(
12871                    map,
12872                    selection.start,
12873                    action.lines,
12874                    selection.goal,
12875                    false,
12876                    text_layout_details,
12877                );
12878                selection.collapse_to(cursor, goal);
12879            });
12880        })
12881    }
12882
12883    pub fn select_down_by_lines(
12884        &mut self,
12885        action: &SelectDownByLines,
12886        window: &mut Window,
12887        cx: &mut Context<Self>,
12888    ) {
12889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12890        let text_layout_details = &self.text_layout_details(window);
12891        self.change_selections(Default::default(), window, cx, |s| {
12892            s.move_heads_with(|map, head, goal| {
12893                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12894            })
12895        })
12896    }
12897
12898    pub fn select_up_by_lines(
12899        &mut self,
12900        action: &SelectUpByLines,
12901        window: &mut Window,
12902        cx: &mut Context<Self>,
12903    ) {
12904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12905        let text_layout_details = &self.text_layout_details(window);
12906        self.change_selections(Default::default(), window, cx, |s| {
12907            s.move_heads_with(|map, head, goal| {
12908                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12909            })
12910        })
12911    }
12912
12913    pub fn select_page_up(
12914        &mut self,
12915        _: &SelectPageUp,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        let Some(row_count) = self.visible_row_count() else {
12920            return;
12921        };
12922
12923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12924
12925        let text_layout_details = &self.text_layout_details(window);
12926
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_heads_with(|map, head, goal| {
12929                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12930            })
12931        })
12932    }
12933
12934    pub fn move_page_up(
12935        &mut self,
12936        action: &MovePageUp,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        if self.take_rename(true, window, cx).is_some() {
12941            return;
12942        }
12943
12944        if self
12945            .context_menu
12946            .borrow_mut()
12947            .as_mut()
12948            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12949            .unwrap_or(false)
12950        {
12951            return;
12952        }
12953
12954        if matches!(self.mode, EditorMode::SingleLine) {
12955            cx.propagate();
12956            return;
12957        }
12958
12959        let Some(row_count) = self.visible_row_count() else {
12960            return;
12961        };
12962
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12964
12965        let effects = if action.center_cursor {
12966            SelectionEffects::scroll(Autoscroll::center())
12967        } else {
12968            SelectionEffects::default()
12969        };
12970
12971        let text_layout_details = &self.text_layout_details(window);
12972
12973        self.change_selections(effects, window, cx, |s| {
12974            s.move_with(|map, selection| {
12975                if !selection.is_empty() {
12976                    selection.goal = SelectionGoal::None;
12977                }
12978                let (cursor, goal) = movement::up_by_rows(
12979                    map,
12980                    selection.end,
12981                    row_count,
12982                    selection.goal,
12983                    false,
12984                    text_layout_details,
12985                );
12986                selection.collapse_to(cursor, goal);
12987            });
12988        });
12989    }
12990
12991    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12993        let text_layout_details = &self.text_layout_details(window);
12994        self.change_selections(Default::default(), window, cx, |s| {
12995            s.move_heads_with(|map, head, goal| {
12996                movement::up(map, head, goal, false, text_layout_details)
12997            })
12998        })
12999    }
13000
13001    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13002        self.take_rename(true, window, cx);
13003
13004        if self.mode.is_single_line() {
13005            cx.propagate();
13006            return;
13007        }
13008
13009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13010
13011        let text_layout_details = &self.text_layout_details(window);
13012        let selection_count = self.selections.count();
13013        let first_selection = self.selections.first_anchor();
13014
13015        self.change_selections(Default::default(), window, cx, |s| {
13016            s.move_with(|map, selection| {
13017                if !selection.is_empty() {
13018                    selection.goal = SelectionGoal::None;
13019                }
13020                let (cursor, goal) = movement::down(
13021                    map,
13022                    selection.end,
13023                    selection.goal,
13024                    false,
13025                    text_layout_details,
13026                );
13027                selection.collapse_to(cursor, goal);
13028            });
13029        });
13030
13031        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13032        {
13033            cx.propagate();
13034        }
13035    }
13036
13037    pub fn select_page_down(
13038        &mut self,
13039        _: &SelectPageDown,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        let Some(row_count) = self.visible_row_count() else {
13044            return;
13045        };
13046
13047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13048
13049        let text_layout_details = &self.text_layout_details(window);
13050
13051        self.change_selections(Default::default(), window, cx, |s| {
13052            s.move_heads_with(|map, head, goal| {
13053                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13054            })
13055        })
13056    }
13057
13058    pub fn move_page_down(
13059        &mut self,
13060        action: &MovePageDown,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        if self.take_rename(true, window, cx).is_some() {
13065            return;
13066        }
13067
13068        if self
13069            .context_menu
13070            .borrow_mut()
13071            .as_mut()
13072            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13073            .unwrap_or(false)
13074        {
13075            return;
13076        }
13077
13078        if matches!(self.mode, EditorMode::SingleLine) {
13079            cx.propagate();
13080            return;
13081        }
13082
13083        let Some(row_count) = self.visible_row_count() else {
13084            return;
13085        };
13086
13087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13088
13089        let effects = if action.center_cursor {
13090            SelectionEffects::scroll(Autoscroll::center())
13091        } else {
13092            SelectionEffects::default()
13093        };
13094
13095        let text_layout_details = &self.text_layout_details(window);
13096        self.change_selections(effects, window, cx, |s| {
13097            s.move_with(|map, selection| {
13098                if !selection.is_empty() {
13099                    selection.goal = SelectionGoal::None;
13100                }
13101                let (cursor, goal) = movement::down_by_rows(
13102                    map,
13103                    selection.end,
13104                    row_count,
13105                    selection.goal,
13106                    false,
13107                    text_layout_details,
13108                );
13109                selection.collapse_to(cursor, goal);
13110            });
13111        });
13112    }
13113
13114    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13116        let text_layout_details = &self.text_layout_details(window);
13117        self.change_selections(Default::default(), window, cx, |s| {
13118            s.move_heads_with(|map, head, goal| {
13119                movement::down(map, head, goal, false, text_layout_details)
13120            })
13121        });
13122    }
13123
13124    pub fn context_menu_first(
13125        &mut self,
13126        _: &ContextMenuFirst,
13127        window: &mut Window,
13128        cx: &mut Context<Self>,
13129    ) {
13130        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13131            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13132        }
13133    }
13134
13135    pub fn context_menu_prev(
13136        &mut self,
13137        _: &ContextMenuPrevious,
13138        window: &mut Window,
13139        cx: &mut Context<Self>,
13140    ) {
13141        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13142            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13143        }
13144    }
13145
13146    pub fn context_menu_next(
13147        &mut self,
13148        _: &ContextMenuNext,
13149        window: &mut Window,
13150        cx: &mut Context<Self>,
13151    ) {
13152        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13153            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13154        }
13155    }
13156
13157    pub fn context_menu_last(
13158        &mut self,
13159        _: &ContextMenuLast,
13160        window: &mut Window,
13161        cx: &mut Context<Self>,
13162    ) {
13163        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13164            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13165        }
13166    }
13167
13168    pub fn signature_help_prev(
13169        &mut self,
13170        _: &SignatureHelpPrevious,
13171        _: &mut Window,
13172        cx: &mut Context<Self>,
13173    ) {
13174        if let Some(popover) = self.signature_help_state.popover_mut() {
13175            if popover.current_signature == 0 {
13176                popover.current_signature = popover.signatures.len() - 1;
13177            } else {
13178                popover.current_signature -= 1;
13179            }
13180            cx.notify();
13181        }
13182    }
13183
13184    pub fn signature_help_next(
13185        &mut self,
13186        _: &SignatureHelpNext,
13187        _: &mut Window,
13188        cx: &mut Context<Self>,
13189    ) {
13190        if let Some(popover) = self.signature_help_state.popover_mut() {
13191            if popover.current_signature + 1 == popover.signatures.len() {
13192                popover.current_signature = 0;
13193            } else {
13194                popover.current_signature += 1;
13195            }
13196            cx.notify();
13197        }
13198    }
13199
13200    pub fn move_to_previous_word_start(
13201        &mut self,
13202        _: &MoveToPreviousWordStart,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13207        self.change_selections(Default::default(), window, cx, |s| {
13208            s.move_cursors_with(|map, head, _| {
13209                (
13210                    movement::previous_word_start(map, head),
13211                    SelectionGoal::None,
13212                )
13213            });
13214        })
13215    }
13216
13217    pub fn move_to_previous_subword_start(
13218        &mut self,
13219        _: &MoveToPreviousSubwordStart,
13220        window: &mut Window,
13221        cx: &mut Context<Self>,
13222    ) {
13223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13224        self.change_selections(Default::default(), window, cx, |s| {
13225            s.move_cursors_with(|map, head, _| {
13226                (
13227                    movement::previous_subword_start(map, head),
13228                    SelectionGoal::None,
13229                )
13230            });
13231        })
13232    }
13233
13234    pub fn select_to_previous_word_start(
13235        &mut self,
13236        _: &SelectToPreviousWordStart,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13241        self.change_selections(Default::default(), window, cx, |s| {
13242            s.move_heads_with(|map, head, _| {
13243                (
13244                    movement::previous_word_start(map, head),
13245                    SelectionGoal::None,
13246                )
13247            });
13248        })
13249    }
13250
13251    pub fn select_to_previous_subword_start(
13252        &mut self,
13253        _: &SelectToPreviousSubwordStart,
13254        window: &mut Window,
13255        cx: &mut Context<Self>,
13256    ) {
13257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13258        self.change_selections(Default::default(), window, cx, |s| {
13259            s.move_heads_with(|map, head, _| {
13260                (
13261                    movement::previous_subword_start(map, head),
13262                    SelectionGoal::None,
13263                )
13264            });
13265        })
13266    }
13267
13268    pub fn delete_to_previous_word_start(
13269        &mut self,
13270        action: &DeleteToPreviousWordStart,
13271        window: &mut Window,
13272        cx: &mut Context<Self>,
13273    ) {
13274        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13275        self.transact(window, cx, |this, window, cx| {
13276            this.select_autoclose_pair(window, cx);
13277            this.change_selections(Default::default(), window, cx, |s| {
13278                s.move_with(|map, selection| {
13279                    if selection.is_empty() {
13280                        let mut cursor = if action.ignore_newlines {
13281                            movement::previous_word_start(map, selection.head())
13282                        } else {
13283                            movement::previous_word_start_or_newline(map, selection.head())
13284                        };
13285                        cursor = movement::adjust_greedy_deletion(
13286                            map,
13287                            selection.head(),
13288                            cursor,
13289                            action.ignore_brackets,
13290                        );
13291                        selection.set_head(cursor, SelectionGoal::None);
13292                    }
13293                });
13294            });
13295            this.insert("", window, cx);
13296        });
13297    }
13298
13299    pub fn delete_to_previous_subword_start(
13300        &mut self,
13301        _: &DeleteToPreviousSubwordStart,
13302        window: &mut Window,
13303        cx: &mut Context<Self>,
13304    ) {
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13306        self.transact(window, cx, |this, window, cx| {
13307            this.select_autoclose_pair(window, cx);
13308            this.change_selections(Default::default(), window, cx, |s| {
13309                s.move_with(|map, selection| {
13310                    if selection.is_empty() {
13311                        let mut cursor = movement::previous_subword_start(map, selection.head());
13312                        cursor =
13313                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13314                        selection.set_head(cursor, SelectionGoal::None);
13315                    }
13316                });
13317            });
13318            this.insert("", window, cx);
13319        });
13320    }
13321
13322    pub fn move_to_next_word_end(
13323        &mut self,
13324        _: &MoveToNextWordEnd,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13329        self.change_selections(Default::default(), window, cx, |s| {
13330            s.move_cursors_with(|map, head, _| {
13331                (movement::next_word_end(map, head), SelectionGoal::None)
13332            });
13333        })
13334    }
13335
13336    pub fn move_to_next_subword_end(
13337        &mut self,
13338        _: &MoveToNextSubwordEnd,
13339        window: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13343        self.change_selections(Default::default(), window, cx, |s| {
13344            s.move_cursors_with(|map, head, _| {
13345                (movement::next_subword_end(map, head), SelectionGoal::None)
13346            });
13347        })
13348    }
13349
13350    pub fn select_to_next_word_end(
13351        &mut self,
13352        _: &SelectToNextWordEnd,
13353        window: &mut Window,
13354        cx: &mut Context<Self>,
13355    ) {
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357        self.change_selections(Default::default(), window, cx, |s| {
13358            s.move_heads_with(|map, head, _| {
13359                (movement::next_word_end(map, head), SelectionGoal::None)
13360            });
13361        })
13362    }
13363
13364    pub fn select_to_next_subword_end(
13365        &mut self,
13366        _: &SelectToNextSubwordEnd,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13371        self.change_selections(Default::default(), window, cx, |s| {
13372            s.move_heads_with(|map, head, _| {
13373                (movement::next_subword_end(map, head), SelectionGoal::None)
13374            });
13375        })
13376    }
13377
13378    pub fn delete_to_next_word_end(
13379        &mut self,
13380        action: &DeleteToNextWordEnd,
13381        window: &mut Window,
13382        cx: &mut Context<Self>,
13383    ) {
13384        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13385        self.transact(window, cx, |this, window, cx| {
13386            this.change_selections(Default::default(), window, cx, |s| {
13387                s.move_with(|map, selection| {
13388                    if selection.is_empty() {
13389                        let mut cursor = if action.ignore_newlines {
13390                            movement::next_word_end(map, selection.head())
13391                        } else {
13392                            movement::next_word_end_or_newline(map, selection.head())
13393                        };
13394                        cursor = movement::adjust_greedy_deletion(
13395                            map,
13396                            selection.head(),
13397                            cursor,
13398                            action.ignore_brackets,
13399                        );
13400                        selection.set_head(cursor, SelectionGoal::None);
13401                    }
13402                });
13403            });
13404            this.insert("", window, cx);
13405        });
13406    }
13407
13408    pub fn delete_to_next_subword_end(
13409        &mut self,
13410        _: &DeleteToNextSubwordEnd,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) {
13414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13415        self.transact(window, cx, |this, window, cx| {
13416            this.change_selections(Default::default(), window, cx, |s| {
13417                s.move_with(|map, selection| {
13418                    if selection.is_empty() {
13419                        let mut cursor = movement::next_subword_end(map, selection.head());
13420                        cursor =
13421                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13422                        selection.set_head(cursor, SelectionGoal::None);
13423                    }
13424                });
13425            });
13426            this.insert("", window, cx);
13427        });
13428    }
13429
13430    pub fn move_to_beginning_of_line(
13431        &mut self,
13432        action: &MoveToBeginningOfLine,
13433        window: &mut Window,
13434        cx: &mut Context<Self>,
13435    ) {
13436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13437        self.change_selections(Default::default(), window, cx, |s| {
13438            s.move_cursors_with(|map, head, _| {
13439                (
13440                    movement::indented_line_beginning(
13441                        map,
13442                        head,
13443                        action.stop_at_soft_wraps,
13444                        action.stop_at_indent,
13445                    ),
13446                    SelectionGoal::None,
13447                )
13448            });
13449        })
13450    }
13451
13452    pub fn select_to_beginning_of_line(
13453        &mut self,
13454        action: &SelectToBeginningOfLine,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_heads_with(|map, head, _| {
13461                (
13462                    movement::indented_line_beginning(
13463                        map,
13464                        head,
13465                        action.stop_at_soft_wraps,
13466                        action.stop_at_indent,
13467                    ),
13468                    SelectionGoal::None,
13469                )
13470            });
13471        });
13472    }
13473
13474    pub fn delete_to_beginning_of_line(
13475        &mut self,
13476        action: &DeleteToBeginningOfLine,
13477        window: &mut Window,
13478        cx: &mut Context<Self>,
13479    ) {
13480        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13481        self.transact(window, cx, |this, window, cx| {
13482            this.change_selections(Default::default(), window, cx, |s| {
13483                s.move_with(|_, selection| {
13484                    selection.reversed = true;
13485                });
13486            });
13487
13488            this.select_to_beginning_of_line(
13489                &SelectToBeginningOfLine {
13490                    stop_at_soft_wraps: false,
13491                    stop_at_indent: action.stop_at_indent,
13492                },
13493                window,
13494                cx,
13495            );
13496            this.backspace(&Backspace, window, cx);
13497        });
13498    }
13499
13500    pub fn move_to_end_of_line(
13501        &mut self,
13502        action: &MoveToEndOfLine,
13503        window: &mut Window,
13504        cx: &mut Context<Self>,
13505    ) {
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13507        self.change_selections(Default::default(), window, cx, |s| {
13508            s.move_cursors_with(|map, head, _| {
13509                (
13510                    movement::line_end(map, head, action.stop_at_soft_wraps),
13511                    SelectionGoal::None,
13512                )
13513            });
13514        })
13515    }
13516
13517    pub fn select_to_end_of_line(
13518        &mut self,
13519        action: &SelectToEndOfLine,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13524        self.change_selections(Default::default(), window, cx, |s| {
13525            s.move_heads_with(|map, head, _| {
13526                (
13527                    movement::line_end(map, head, action.stop_at_soft_wraps),
13528                    SelectionGoal::None,
13529                )
13530            });
13531        })
13532    }
13533
13534    pub fn delete_to_end_of_line(
13535        &mut self,
13536        _: &DeleteToEndOfLine,
13537        window: &mut Window,
13538        cx: &mut Context<Self>,
13539    ) {
13540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13541        self.transact(window, cx, |this, window, cx| {
13542            this.select_to_end_of_line(
13543                &SelectToEndOfLine {
13544                    stop_at_soft_wraps: false,
13545                },
13546                window,
13547                cx,
13548            );
13549            this.delete(&Delete, window, cx);
13550        });
13551    }
13552
13553    pub fn cut_to_end_of_line(
13554        &mut self,
13555        action: &CutToEndOfLine,
13556        window: &mut Window,
13557        cx: &mut Context<Self>,
13558    ) {
13559        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13560        self.transact(window, cx, |this, window, cx| {
13561            this.select_to_end_of_line(
13562                &SelectToEndOfLine {
13563                    stop_at_soft_wraps: false,
13564                },
13565                window,
13566                cx,
13567            );
13568            if !action.stop_at_newlines {
13569                this.change_selections(Default::default(), window, cx, |s| {
13570                    s.move_with(|_, sel| {
13571                        if sel.is_empty() {
13572                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13573                        }
13574                    });
13575                });
13576            }
13577            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13578            let item = this.cut_common(false, window, cx);
13579            cx.write_to_clipboard(item);
13580        });
13581    }
13582
13583    pub fn move_to_start_of_paragraph(
13584        &mut self,
13585        _: &MoveToStartOfParagraph,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        if matches!(self.mode, EditorMode::SingleLine) {
13590            cx.propagate();
13591            return;
13592        }
13593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.move_with(|map, selection| {
13596                selection.collapse_to(
13597                    movement::start_of_paragraph(map, selection.head(), 1),
13598                    SelectionGoal::None,
13599                )
13600            });
13601        })
13602    }
13603
13604    pub fn move_to_end_of_paragraph(
13605        &mut self,
13606        _: &MoveToEndOfParagraph,
13607        window: &mut Window,
13608        cx: &mut Context<Self>,
13609    ) {
13610        if matches!(self.mode, EditorMode::SingleLine) {
13611            cx.propagate();
13612            return;
13613        }
13614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13615        self.change_selections(Default::default(), window, cx, |s| {
13616            s.move_with(|map, selection| {
13617                selection.collapse_to(
13618                    movement::end_of_paragraph(map, selection.head(), 1),
13619                    SelectionGoal::None,
13620                )
13621            });
13622        })
13623    }
13624
13625    pub fn select_to_start_of_paragraph(
13626        &mut self,
13627        _: &SelectToStartOfParagraph,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        if matches!(self.mode, EditorMode::SingleLine) {
13632            cx.propagate();
13633            return;
13634        }
13635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13636        self.change_selections(Default::default(), window, cx, |s| {
13637            s.move_heads_with(|map, head, _| {
13638                (
13639                    movement::start_of_paragraph(map, head, 1),
13640                    SelectionGoal::None,
13641                )
13642            });
13643        })
13644    }
13645
13646    pub fn select_to_end_of_paragraph(
13647        &mut self,
13648        _: &SelectToEndOfParagraph,
13649        window: &mut Window,
13650        cx: &mut Context<Self>,
13651    ) {
13652        if matches!(self.mode, EditorMode::SingleLine) {
13653            cx.propagate();
13654            return;
13655        }
13656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13657        self.change_selections(Default::default(), window, cx, |s| {
13658            s.move_heads_with(|map, head, _| {
13659                (
13660                    movement::end_of_paragraph(map, head, 1),
13661                    SelectionGoal::None,
13662                )
13663            });
13664        })
13665    }
13666
13667    pub fn move_to_start_of_excerpt(
13668        &mut self,
13669        _: &MoveToStartOfExcerpt,
13670        window: &mut Window,
13671        cx: &mut Context<Self>,
13672    ) {
13673        if matches!(self.mode, EditorMode::SingleLine) {
13674            cx.propagate();
13675            return;
13676        }
13677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13678        self.change_selections(Default::default(), window, cx, |s| {
13679            s.move_with(|map, selection| {
13680                selection.collapse_to(
13681                    movement::start_of_excerpt(
13682                        map,
13683                        selection.head(),
13684                        workspace::searchable::Direction::Prev,
13685                    ),
13686                    SelectionGoal::None,
13687                )
13688            });
13689        })
13690    }
13691
13692    pub fn move_to_start_of_next_excerpt(
13693        &mut self,
13694        _: &MoveToStartOfNextExcerpt,
13695        window: &mut Window,
13696        cx: &mut Context<Self>,
13697    ) {
13698        if matches!(self.mode, EditorMode::SingleLine) {
13699            cx.propagate();
13700            return;
13701        }
13702
13703        self.change_selections(Default::default(), window, cx, |s| {
13704            s.move_with(|map, selection| {
13705                selection.collapse_to(
13706                    movement::start_of_excerpt(
13707                        map,
13708                        selection.head(),
13709                        workspace::searchable::Direction::Next,
13710                    ),
13711                    SelectionGoal::None,
13712                )
13713            });
13714        })
13715    }
13716
13717    pub fn move_to_end_of_excerpt(
13718        &mut self,
13719        _: &MoveToEndOfExcerpt,
13720        window: &mut Window,
13721        cx: &mut Context<Self>,
13722    ) {
13723        if matches!(self.mode, EditorMode::SingleLine) {
13724            cx.propagate();
13725            return;
13726        }
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13728        self.change_selections(Default::default(), window, cx, |s| {
13729            s.move_with(|map, selection| {
13730                selection.collapse_to(
13731                    movement::end_of_excerpt(
13732                        map,
13733                        selection.head(),
13734                        workspace::searchable::Direction::Next,
13735                    ),
13736                    SelectionGoal::None,
13737                )
13738            });
13739        })
13740    }
13741
13742    pub fn move_to_end_of_previous_excerpt(
13743        &mut self,
13744        _: &MoveToEndOfPreviousExcerpt,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if matches!(self.mode, EditorMode::SingleLine) {
13749            cx.propagate();
13750            return;
13751        }
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.move_with(|map, selection| {
13755                selection.collapse_to(
13756                    movement::end_of_excerpt(
13757                        map,
13758                        selection.head(),
13759                        workspace::searchable::Direction::Prev,
13760                    ),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn select_to_start_of_excerpt(
13768        &mut self,
13769        _: &SelectToStartOfExcerpt,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_heads_with(|map, head, _| {
13780                (
13781                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13782                    SelectionGoal::None,
13783                )
13784            });
13785        })
13786    }
13787
13788    pub fn select_to_start_of_next_excerpt(
13789        &mut self,
13790        _: &SelectToStartOfNextExcerpt,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) {
13794        if matches!(self.mode, EditorMode::SingleLine) {
13795            cx.propagate();
13796            return;
13797        }
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13799        self.change_selections(Default::default(), window, cx, |s| {
13800            s.move_heads_with(|map, head, _| {
13801                (
13802                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13803                    SelectionGoal::None,
13804                )
13805            });
13806        })
13807    }
13808
13809    pub fn select_to_end_of_excerpt(
13810        &mut self,
13811        _: &SelectToEndOfExcerpt,
13812        window: &mut Window,
13813        cx: &mut Context<Self>,
13814    ) {
13815        if matches!(self.mode, EditorMode::SingleLine) {
13816            cx.propagate();
13817            return;
13818        }
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13820        self.change_selections(Default::default(), window, cx, |s| {
13821            s.move_heads_with(|map, head, _| {
13822                (
13823                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13824                    SelectionGoal::None,
13825                )
13826            });
13827        })
13828    }
13829
13830    pub fn select_to_end_of_previous_excerpt(
13831        &mut self,
13832        _: &SelectToEndOfPreviousExcerpt,
13833        window: &mut Window,
13834        cx: &mut Context<Self>,
13835    ) {
13836        if matches!(self.mode, EditorMode::SingleLine) {
13837            cx.propagate();
13838            return;
13839        }
13840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13841        self.change_selections(Default::default(), window, cx, |s| {
13842            s.move_heads_with(|map, head, _| {
13843                (
13844                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13845                    SelectionGoal::None,
13846                )
13847            });
13848        })
13849    }
13850
13851    pub fn move_to_beginning(
13852        &mut self,
13853        _: &MoveToBeginning,
13854        window: &mut Window,
13855        cx: &mut Context<Self>,
13856    ) {
13857        if matches!(self.mode, EditorMode::SingleLine) {
13858            cx.propagate();
13859            return;
13860        }
13861        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13862        self.change_selections(Default::default(), window, cx, |s| {
13863            s.select_ranges(vec![0..0]);
13864        });
13865    }
13866
13867    pub fn select_to_beginning(
13868        &mut self,
13869        _: &SelectToBeginning,
13870        window: &mut Window,
13871        cx: &mut Context<Self>,
13872    ) {
13873        let mut selection = self.selections.last::<Point>(cx);
13874        selection.set_head(Point::zero(), SelectionGoal::None);
13875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13876        self.change_selections(Default::default(), window, cx, |s| {
13877            s.select(vec![selection]);
13878        });
13879    }
13880
13881    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13882        if matches!(self.mode, EditorMode::SingleLine) {
13883            cx.propagate();
13884            return;
13885        }
13886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13887        let cursor = self.buffer.read(cx).read(cx).len();
13888        self.change_selections(Default::default(), window, cx, |s| {
13889            s.select_ranges(vec![cursor..cursor])
13890        });
13891    }
13892
13893    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13894        self.nav_history = nav_history;
13895    }
13896
13897    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13898        self.nav_history.as_ref()
13899    }
13900
13901    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13902        self.push_to_nav_history(
13903            self.selections.newest_anchor().head(),
13904            None,
13905            false,
13906            true,
13907            cx,
13908        );
13909    }
13910
13911    fn push_to_nav_history(
13912        &mut self,
13913        cursor_anchor: Anchor,
13914        new_position: Option<Point>,
13915        is_deactivate: bool,
13916        always: bool,
13917        cx: &mut Context<Self>,
13918    ) {
13919        if let Some(nav_history) = self.nav_history.as_mut() {
13920            let buffer = self.buffer.read(cx).read(cx);
13921            let cursor_position = cursor_anchor.to_point(&buffer);
13922            let scroll_state = self.scroll_manager.anchor();
13923            let scroll_top_row = scroll_state.top_row(&buffer);
13924            drop(buffer);
13925
13926            if let Some(new_position) = new_position {
13927                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13928                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13929                    return;
13930                }
13931            }
13932
13933            nav_history.push(
13934                Some(NavigationData {
13935                    cursor_anchor,
13936                    cursor_position,
13937                    scroll_anchor: scroll_state,
13938                    scroll_top_row,
13939                }),
13940                cx,
13941            );
13942            cx.emit(EditorEvent::PushedToNavHistory {
13943                anchor: cursor_anchor,
13944                is_deactivate,
13945            })
13946        }
13947    }
13948
13949    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13951        let buffer = self.buffer.read(cx).snapshot(cx);
13952        let mut selection = self.selections.first::<usize>(cx);
13953        selection.set_head(buffer.len(), SelectionGoal::None);
13954        self.change_selections(Default::default(), window, cx, |s| {
13955            s.select(vec![selection]);
13956        });
13957    }
13958
13959    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13961        let end = self.buffer.read(cx).read(cx).len();
13962        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13963            s.select_ranges(vec![0..end]);
13964        });
13965    }
13966
13967    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13970        let mut selections = self.selections.all::<Point>(cx);
13971        let max_point = display_map.buffer_snapshot.max_point();
13972        for selection in &mut selections {
13973            let rows = selection.spanned_rows(true, &display_map);
13974            selection.start = Point::new(rows.start.0, 0);
13975            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13976            selection.reversed = false;
13977        }
13978        self.change_selections(Default::default(), window, cx, |s| {
13979            s.select(selections);
13980        });
13981    }
13982
13983    pub fn split_selection_into_lines(
13984        &mut self,
13985        action: &SplitSelectionIntoLines,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        let selections = self
13990            .selections
13991            .all::<Point>(cx)
13992            .into_iter()
13993            .map(|selection| selection.start..selection.end)
13994            .collect::<Vec<_>>();
13995        self.unfold_ranges(&selections, true, true, cx);
13996
13997        let mut new_selection_ranges = Vec::new();
13998        {
13999            let buffer = self.buffer.read(cx).read(cx);
14000            for selection in selections {
14001                for row in selection.start.row..selection.end.row {
14002                    let line_start = Point::new(row, 0);
14003                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14004
14005                    if action.keep_selections {
14006                        // Keep the selection range for each line
14007                        let selection_start = if row == selection.start.row {
14008                            selection.start
14009                        } else {
14010                            line_start
14011                        };
14012                        new_selection_ranges.push(selection_start..line_end);
14013                    } else {
14014                        // Collapse to cursor at end of line
14015                        new_selection_ranges.push(line_end..line_end);
14016                    }
14017                }
14018
14019                let is_multiline_selection = selection.start.row != selection.end.row;
14020                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14021                // so this action feels more ergonomic when paired with other selection operations
14022                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14023                if !should_skip_last {
14024                    if action.keep_selections {
14025                        if is_multiline_selection {
14026                            let line_start = Point::new(selection.end.row, 0);
14027                            new_selection_ranges.push(line_start..selection.end);
14028                        } else {
14029                            new_selection_ranges.push(selection.start..selection.end);
14030                        }
14031                    } else {
14032                        new_selection_ranges.push(selection.end..selection.end);
14033                    }
14034                }
14035            }
14036        }
14037        self.change_selections(Default::default(), window, cx, |s| {
14038            s.select_ranges(new_selection_ranges);
14039        });
14040    }
14041
14042    pub fn add_selection_above(
14043        &mut self,
14044        _: &AddSelectionAbove,
14045        window: &mut Window,
14046        cx: &mut Context<Self>,
14047    ) {
14048        self.add_selection(true, window, cx);
14049    }
14050
14051    pub fn add_selection_below(
14052        &mut self,
14053        _: &AddSelectionBelow,
14054        window: &mut Window,
14055        cx: &mut Context<Self>,
14056    ) {
14057        self.add_selection(false, window, cx);
14058    }
14059
14060    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14062
14063        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14064        let all_selections = self.selections.all::<Point>(cx);
14065        let text_layout_details = self.text_layout_details(window);
14066
14067        let (mut columnar_selections, new_selections_to_columnarize) = {
14068            if let Some(state) = self.add_selections_state.as_ref() {
14069                let columnar_selection_ids: HashSet<_> = state
14070                    .groups
14071                    .iter()
14072                    .flat_map(|group| group.stack.iter())
14073                    .copied()
14074                    .collect();
14075
14076                all_selections
14077                    .into_iter()
14078                    .partition(|s| columnar_selection_ids.contains(&s.id))
14079            } else {
14080                (Vec::new(), all_selections)
14081            }
14082        };
14083
14084        let mut state = self
14085            .add_selections_state
14086            .take()
14087            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14088
14089        for selection in new_selections_to_columnarize {
14090            let range = selection.display_range(&display_map).sorted();
14091            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14092            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14093            let positions = start_x.min(end_x)..start_x.max(end_x);
14094            let mut stack = Vec::new();
14095            for row in range.start.row().0..=range.end.row().0 {
14096                if let Some(selection) = self.selections.build_columnar_selection(
14097                    &display_map,
14098                    DisplayRow(row),
14099                    &positions,
14100                    selection.reversed,
14101                    &text_layout_details,
14102                ) {
14103                    stack.push(selection.id);
14104                    columnar_selections.push(selection);
14105                }
14106            }
14107            if !stack.is_empty() {
14108                if above {
14109                    stack.reverse();
14110                }
14111                state.groups.push(AddSelectionsGroup { above, stack });
14112            }
14113        }
14114
14115        let mut final_selections = Vec::new();
14116        let end_row = if above {
14117            DisplayRow(0)
14118        } else {
14119            display_map.max_point().row()
14120        };
14121
14122        let mut last_added_item_per_group = HashMap::default();
14123        for group in state.groups.iter_mut() {
14124            if let Some(last_id) = group.stack.last() {
14125                last_added_item_per_group.insert(*last_id, group);
14126            }
14127        }
14128
14129        for selection in columnar_selections {
14130            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14131                if above == group.above {
14132                    let range = selection.display_range(&display_map).sorted();
14133                    debug_assert_eq!(range.start.row(), range.end.row());
14134                    let mut row = range.start.row();
14135                    let positions =
14136                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14137                            px(start)..px(end)
14138                        } else {
14139                            let start_x =
14140                                display_map.x_for_display_point(range.start, &text_layout_details);
14141                            let end_x =
14142                                display_map.x_for_display_point(range.end, &text_layout_details);
14143                            start_x.min(end_x)..start_x.max(end_x)
14144                        };
14145
14146                    let mut maybe_new_selection = None;
14147                    while row != end_row {
14148                        if above {
14149                            row.0 -= 1;
14150                        } else {
14151                            row.0 += 1;
14152                        }
14153                        if let Some(new_selection) = self.selections.build_columnar_selection(
14154                            &display_map,
14155                            row,
14156                            &positions,
14157                            selection.reversed,
14158                            &text_layout_details,
14159                        ) {
14160                            maybe_new_selection = Some(new_selection);
14161                            break;
14162                        }
14163                    }
14164
14165                    if let Some(new_selection) = maybe_new_selection {
14166                        group.stack.push(new_selection.id);
14167                        if above {
14168                            final_selections.push(new_selection);
14169                            final_selections.push(selection);
14170                        } else {
14171                            final_selections.push(selection);
14172                            final_selections.push(new_selection);
14173                        }
14174                    } else {
14175                        final_selections.push(selection);
14176                    }
14177                } else {
14178                    group.stack.pop();
14179                }
14180            } else {
14181                final_selections.push(selection);
14182            }
14183        }
14184
14185        self.change_selections(Default::default(), window, cx, |s| {
14186            s.select(final_selections);
14187        });
14188
14189        let final_selection_ids: HashSet<_> = self
14190            .selections
14191            .all::<Point>(cx)
14192            .iter()
14193            .map(|s| s.id)
14194            .collect();
14195        state.groups.retain_mut(|group| {
14196            // selections might get merged above so we remove invalid items from stacks
14197            group.stack.retain(|id| final_selection_ids.contains(id));
14198
14199            // single selection in stack can be treated as initial state
14200            group.stack.len() > 1
14201        });
14202
14203        if !state.groups.is_empty() {
14204            self.add_selections_state = Some(state);
14205        }
14206    }
14207
14208    fn select_match_ranges(
14209        &mut self,
14210        range: Range<usize>,
14211        reversed: bool,
14212        replace_newest: bool,
14213        auto_scroll: Option<Autoscroll>,
14214        window: &mut Window,
14215        cx: &mut Context<Editor>,
14216    ) {
14217        self.unfold_ranges(
14218            std::slice::from_ref(&range),
14219            false,
14220            auto_scroll.is_some(),
14221            cx,
14222        );
14223        let effects = if let Some(scroll) = auto_scroll {
14224            SelectionEffects::scroll(scroll)
14225        } else {
14226            SelectionEffects::no_scroll()
14227        };
14228        self.change_selections(effects, window, cx, |s| {
14229            if replace_newest {
14230                s.delete(s.newest_anchor().id);
14231            }
14232            if reversed {
14233                s.insert_range(range.end..range.start);
14234            } else {
14235                s.insert_range(range);
14236            }
14237        });
14238    }
14239
14240    pub fn select_next_match_internal(
14241        &mut self,
14242        display_map: &DisplaySnapshot,
14243        replace_newest: bool,
14244        autoscroll: Option<Autoscroll>,
14245        window: &mut Window,
14246        cx: &mut Context<Self>,
14247    ) -> Result<()> {
14248        let buffer = &display_map.buffer_snapshot;
14249        let mut selections = self.selections.all::<usize>(cx);
14250        if let Some(mut select_next_state) = self.select_next_state.take() {
14251            let query = &select_next_state.query;
14252            if !select_next_state.done {
14253                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14254                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14255                let mut next_selected_range = None;
14256
14257                let bytes_after_last_selection =
14258                    buffer.bytes_in_range(last_selection.end..buffer.len());
14259                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14260                let query_matches = query
14261                    .stream_find_iter(bytes_after_last_selection)
14262                    .map(|result| (last_selection.end, result))
14263                    .chain(
14264                        query
14265                            .stream_find_iter(bytes_before_first_selection)
14266                            .map(|result| (0, result)),
14267                    );
14268
14269                for (start_offset, query_match) in query_matches {
14270                    let query_match = query_match.unwrap(); // can only fail due to I/O
14271                    let offset_range =
14272                        start_offset + query_match.start()..start_offset + query_match.end();
14273
14274                    if !select_next_state.wordwise
14275                        || (!buffer.is_inside_word(offset_range.start, None)
14276                            && !buffer.is_inside_word(offset_range.end, None))
14277                    {
14278                        // TODO: This is n^2, because we might check all the selections
14279                        if !selections
14280                            .iter()
14281                            .any(|selection| selection.range().overlaps(&offset_range))
14282                        {
14283                            next_selected_range = Some(offset_range);
14284                            break;
14285                        }
14286                    }
14287                }
14288
14289                if let Some(next_selected_range) = next_selected_range {
14290                    self.select_match_ranges(
14291                        next_selected_range,
14292                        last_selection.reversed,
14293                        replace_newest,
14294                        autoscroll,
14295                        window,
14296                        cx,
14297                    );
14298                } else {
14299                    select_next_state.done = true;
14300                }
14301            }
14302
14303            self.select_next_state = Some(select_next_state);
14304        } else {
14305            let mut only_carets = true;
14306            let mut same_text_selected = true;
14307            let mut selected_text = None;
14308
14309            let mut selections_iter = selections.iter().peekable();
14310            while let Some(selection) = selections_iter.next() {
14311                if selection.start != selection.end {
14312                    only_carets = false;
14313                }
14314
14315                if same_text_selected {
14316                    if selected_text.is_none() {
14317                        selected_text =
14318                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14319                    }
14320
14321                    if let Some(next_selection) = selections_iter.peek() {
14322                        if next_selection.range().len() == selection.range().len() {
14323                            let next_selected_text = buffer
14324                                .text_for_range(next_selection.range())
14325                                .collect::<String>();
14326                            if Some(next_selected_text) != selected_text {
14327                                same_text_selected = false;
14328                                selected_text = None;
14329                            }
14330                        } else {
14331                            same_text_selected = false;
14332                            selected_text = None;
14333                        }
14334                    }
14335                }
14336            }
14337
14338            if only_carets {
14339                for selection in &mut selections {
14340                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14341                    selection.start = word_range.start;
14342                    selection.end = word_range.end;
14343                    selection.goal = SelectionGoal::None;
14344                    selection.reversed = false;
14345                    self.select_match_ranges(
14346                        selection.start..selection.end,
14347                        selection.reversed,
14348                        replace_newest,
14349                        autoscroll,
14350                        window,
14351                        cx,
14352                    );
14353                }
14354
14355                if selections.len() == 1 {
14356                    let selection = selections
14357                        .last()
14358                        .expect("ensured that there's only one selection");
14359                    let query = buffer
14360                        .text_for_range(selection.start..selection.end)
14361                        .collect::<String>();
14362                    let is_empty = query.is_empty();
14363                    let select_state = SelectNextState {
14364                        query: AhoCorasick::new(&[query])?,
14365                        wordwise: true,
14366                        done: is_empty,
14367                    };
14368                    self.select_next_state = Some(select_state);
14369                } else {
14370                    self.select_next_state = None;
14371                }
14372            } else if let Some(selected_text) = selected_text {
14373                self.select_next_state = Some(SelectNextState {
14374                    query: AhoCorasick::new(&[selected_text])?,
14375                    wordwise: false,
14376                    done: false,
14377                });
14378                self.select_next_match_internal(
14379                    display_map,
14380                    replace_newest,
14381                    autoscroll,
14382                    window,
14383                    cx,
14384                )?;
14385            }
14386        }
14387        Ok(())
14388    }
14389
14390    pub fn select_all_matches(
14391        &mut self,
14392        _action: &SelectAllMatches,
14393        window: &mut Window,
14394        cx: &mut Context<Self>,
14395    ) -> Result<()> {
14396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14397
14398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14399
14400        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14401        let Some(select_next_state) = self.select_next_state.as_mut() else {
14402            return Ok(());
14403        };
14404        if select_next_state.done {
14405            return Ok(());
14406        }
14407
14408        let mut new_selections = Vec::new();
14409
14410        let reversed = self.selections.oldest::<usize>(cx).reversed;
14411        let buffer = &display_map.buffer_snapshot;
14412        let query_matches = select_next_state
14413            .query
14414            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14415
14416        for query_match in query_matches.into_iter() {
14417            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14418            let offset_range = if reversed {
14419                query_match.end()..query_match.start()
14420            } else {
14421                query_match.start()..query_match.end()
14422            };
14423
14424            if !select_next_state.wordwise
14425                || (!buffer.is_inside_word(offset_range.start, None)
14426                    && !buffer.is_inside_word(offset_range.end, None))
14427            {
14428                new_selections.push(offset_range.start..offset_range.end);
14429            }
14430        }
14431
14432        select_next_state.done = true;
14433
14434        if new_selections.is_empty() {
14435            log::error!("bug: new_selections is empty in select_all_matches");
14436            return Ok(());
14437        }
14438
14439        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14440        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14441            selections.select_ranges(new_selections)
14442        });
14443
14444        Ok(())
14445    }
14446
14447    pub fn select_next(
14448        &mut self,
14449        action: &SelectNext,
14450        window: &mut Window,
14451        cx: &mut Context<Self>,
14452    ) -> Result<()> {
14453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14454        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14455        self.select_next_match_internal(
14456            &display_map,
14457            action.replace_newest,
14458            Some(Autoscroll::newest()),
14459            window,
14460            cx,
14461        )?;
14462        Ok(())
14463    }
14464
14465    pub fn select_previous(
14466        &mut self,
14467        action: &SelectPrevious,
14468        window: &mut Window,
14469        cx: &mut Context<Self>,
14470    ) -> Result<()> {
14471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14473        let buffer = &display_map.buffer_snapshot;
14474        let mut selections = self.selections.all::<usize>(cx);
14475        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14476            let query = &select_prev_state.query;
14477            if !select_prev_state.done {
14478                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14479                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14480                let mut next_selected_range = None;
14481                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14482                let bytes_before_last_selection =
14483                    buffer.reversed_bytes_in_range(0..last_selection.start);
14484                let bytes_after_first_selection =
14485                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14486                let query_matches = query
14487                    .stream_find_iter(bytes_before_last_selection)
14488                    .map(|result| (last_selection.start, result))
14489                    .chain(
14490                        query
14491                            .stream_find_iter(bytes_after_first_selection)
14492                            .map(|result| (buffer.len(), result)),
14493                    );
14494                for (end_offset, query_match) in query_matches {
14495                    let query_match = query_match.unwrap(); // can only fail due to I/O
14496                    let offset_range =
14497                        end_offset - query_match.end()..end_offset - query_match.start();
14498
14499                    if !select_prev_state.wordwise
14500                        || (!buffer.is_inside_word(offset_range.start, None)
14501                            && !buffer.is_inside_word(offset_range.end, None))
14502                    {
14503                        next_selected_range = Some(offset_range);
14504                        break;
14505                    }
14506                }
14507
14508                if let Some(next_selected_range) = next_selected_range {
14509                    self.select_match_ranges(
14510                        next_selected_range,
14511                        last_selection.reversed,
14512                        action.replace_newest,
14513                        Some(Autoscroll::newest()),
14514                        window,
14515                        cx,
14516                    );
14517                } else {
14518                    select_prev_state.done = true;
14519                }
14520            }
14521
14522            self.select_prev_state = Some(select_prev_state);
14523        } else {
14524            let mut only_carets = true;
14525            let mut same_text_selected = true;
14526            let mut selected_text = None;
14527
14528            let mut selections_iter = selections.iter().peekable();
14529            while let Some(selection) = selections_iter.next() {
14530                if selection.start != selection.end {
14531                    only_carets = false;
14532                }
14533
14534                if same_text_selected {
14535                    if selected_text.is_none() {
14536                        selected_text =
14537                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14538                    }
14539
14540                    if let Some(next_selection) = selections_iter.peek() {
14541                        if next_selection.range().len() == selection.range().len() {
14542                            let next_selected_text = buffer
14543                                .text_for_range(next_selection.range())
14544                                .collect::<String>();
14545                            if Some(next_selected_text) != selected_text {
14546                                same_text_selected = false;
14547                                selected_text = None;
14548                            }
14549                        } else {
14550                            same_text_selected = false;
14551                            selected_text = None;
14552                        }
14553                    }
14554                }
14555            }
14556
14557            if only_carets {
14558                for selection in &mut selections {
14559                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14560                    selection.start = word_range.start;
14561                    selection.end = word_range.end;
14562                    selection.goal = SelectionGoal::None;
14563                    selection.reversed = false;
14564                    self.select_match_ranges(
14565                        selection.start..selection.end,
14566                        selection.reversed,
14567                        action.replace_newest,
14568                        Some(Autoscroll::newest()),
14569                        window,
14570                        cx,
14571                    );
14572                }
14573                if selections.len() == 1 {
14574                    let selection = selections
14575                        .last()
14576                        .expect("ensured that there's only one selection");
14577                    let query = buffer
14578                        .text_for_range(selection.start..selection.end)
14579                        .collect::<String>();
14580                    let is_empty = query.is_empty();
14581                    let select_state = SelectNextState {
14582                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14583                        wordwise: true,
14584                        done: is_empty,
14585                    };
14586                    self.select_prev_state = Some(select_state);
14587                } else {
14588                    self.select_prev_state = None;
14589                }
14590            } else if let Some(selected_text) = selected_text {
14591                self.select_prev_state = Some(SelectNextState {
14592                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14593                    wordwise: false,
14594                    done: false,
14595                });
14596                self.select_previous(action, window, cx)?;
14597            }
14598        }
14599        Ok(())
14600    }
14601
14602    pub fn find_next_match(
14603        &mut self,
14604        _: &FindNextMatch,
14605        window: &mut Window,
14606        cx: &mut Context<Self>,
14607    ) -> Result<()> {
14608        let selections = self.selections.disjoint_anchors_arc();
14609        match selections.first() {
14610            Some(first) if selections.len() >= 2 => {
14611                self.change_selections(Default::default(), window, cx, |s| {
14612                    s.select_ranges([first.range()]);
14613                });
14614            }
14615            _ => self.select_next(
14616                &SelectNext {
14617                    replace_newest: true,
14618                },
14619                window,
14620                cx,
14621            )?,
14622        }
14623        Ok(())
14624    }
14625
14626    pub fn find_previous_match(
14627        &mut self,
14628        _: &FindPreviousMatch,
14629        window: &mut Window,
14630        cx: &mut Context<Self>,
14631    ) -> Result<()> {
14632        let selections = self.selections.disjoint_anchors_arc();
14633        match selections.last() {
14634            Some(last) if selections.len() >= 2 => {
14635                self.change_selections(Default::default(), window, cx, |s| {
14636                    s.select_ranges([last.range()]);
14637                });
14638            }
14639            _ => self.select_previous(
14640                &SelectPrevious {
14641                    replace_newest: true,
14642                },
14643                window,
14644                cx,
14645            )?,
14646        }
14647        Ok(())
14648    }
14649
14650    pub fn toggle_comments(
14651        &mut self,
14652        action: &ToggleComments,
14653        window: &mut Window,
14654        cx: &mut Context<Self>,
14655    ) {
14656        if self.read_only(cx) {
14657            return;
14658        }
14659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14660        let text_layout_details = &self.text_layout_details(window);
14661        self.transact(window, cx, |this, window, cx| {
14662            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14663            let mut edits = Vec::new();
14664            let mut selection_edit_ranges = Vec::new();
14665            let mut last_toggled_row = None;
14666            let snapshot = this.buffer.read(cx).read(cx);
14667            let empty_str: Arc<str> = Arc::default();
14668            let mut suffixes_inserted = Vec::new();
14669            let ignore_indent = action.ignore_indent;
14670
14671            fn comment_prefix_range(
14672                snapshot: &MultiBufferSnapshot,
14673                row: MultiBufferRow,
14674                comment_prefix: &str,
14675                comment_prefix_whitespace: &str,
14676                ignore_indent: bool,
14677            ) -> Range<Point> {
14678                let indent_size = if ignore_indent {
14679                    0
14680                } else {
14681                    snapshot.indent_size_for_line(row).len
14682                };
14683
14684                let start = Point::new(row.0, indent_size);
14685
14686                let mut line_bytes = snapshot
14687                    .bytes_in_range(start..snapshot.max_point())
14688                    .flatten()
14689                    .copied();
14690
14691                // If this line currently begins with the line comment prefix, then record
14692                // the range containing the prefix.
14693                if line_bytes
14694                    .by_ref()
14695                    .take(comment_prefix.len())
14696                    .eq(comment_prefix.bytes())
14697                {
14698                    // Include any whitespace that matches the comment prefix.
14699                    let matching_whitespace_len = line_bytes
14700                        .zip(comment_prefix_whitespace.bytes())
14701                        .take_while(|(a, b)| a == b)
14702                        .count() as u32;
14703                    let end = Point::new(
14704                        start.row,
14705                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14706                    );
14707                    start..end
14708                } else {
14709                    start..start
14710                }
14711            }
14712
14713            fn comment_suffix_range(
14714                snapshot: &MultiBufferSnapshot,
14715                row: MultiBufferRow,
14716                comment_suffix: &str,
14717                comment_suffix_has_leading_space: bool,
14718            ) -> Range<Point> {
14719                let end = Point::new(row.0, snapshot.line_len(row));
14720                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14721
14722                let mut line_end_bytes = snapshot
14723                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14724                    .flatten()
14725                    .copied();
14726
14727                let leading_space_len = if suffix_start_column > 0
14728                    && line_end_bytes.next() == Some(b' ')
14729                    && comment_suffix_has_leading_space
14730                {
14731                    1
14732                } else {
14733                    0
14734                };
14735
14736                // If this line currently begins with the line comment prefix, then record
14737                // the range containing the prefix.
14738                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14739                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14740                    start..end
14741                } else {
14742                    end..end
14743                }
14744            }
14745
14746            // TODO: Handle selections that cross excerpts
14747            for selection in &mut selections {
14748                let start_column = snapshot
14749                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14750                    .len;
14751                let language = if let Some(language) =
14752                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14753                {
14754                    language
14755                } else {
14756                    continue;
14757                };
14758
14759                selection_edit_ranges.clear();
14760
14761                // If multiple selections contain a given row, avoid processing that
14762                // row more than once.
14763                let mut start_row = MultiBufferRow(selection.start.row);
14764                if last_toggled_row == Some(start_row) {
14765                    start_row = start_row.next_row();
14766                }
14767                let end_row =
14768                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14769                        MultiBufferRow(selection.end.row - 1)
14770                    } else {
14771                        MultiBufferRow(selection.end.row)
14772                    };
14773                last_toggled_row = Some(end_row);
14774
14775                if start_row > end_row {
14776                    continue;
14777                }
14778
14779                // If the language has line comments, toggle those.
14780                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14781
14782                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14783                if ignore_indent {
14784                    full_comment_prefixes = full_comment_prefixes
14785                        .into_iter()
14786                        .map(|s| Arc::from(s.trim_end()))
14787                        .collect();
14788                }
14789
14790                if !full_comment_prefixes.is_empty() {
14791                    let first_prefix = full_comment_prefixes
14792                        .first()
14793                        .expect("prefixes is non-empty");
14794                    let prefix_trimmed_lengths = full_comment_prefixes
14795                        .iter()
14796                        .map(|p| p.trim_end_matches(' ').len())
14797                        .collect::<SmallVec<[usize; 4]>>();
14798
14799                    let mut all_selection_lines_are_comments = true;
14800
14801                    for row in start_row.0..=end_row.0 {
14802                        let row = MultiBufferRow(row);
14803                        if start_row < end_row && snapshot.is_line_blank(row) {
14804                            continue;
14805                        }
14806
14807                        let prefix_range = full_comment_prefixes
14808                            .iter()
14809                            .zip(prefix_trimmed_lengths.iter().copied())
14810                            .map(|(prefix, trimmed_prefix_len)| {
14811                                comment_prefix_range(
14812                                    snapshot.deref(),
14813                                    row,
14814                                    &prefix[..trimmed_prefix_len],
14815                                    &prefix[trimmed_prefix_len..],
14816                                    ignore_indent,
14817                                )
14818                            })
14819                            .max_by_key(|range| range.end.column - range.start.column)
14820                            .expect("prefixes is non-empty");
14821
14822                        if prefix_range.is_empty() {
14823                            all_selection_lines_are_comments = false;
14824                        }
14825
14826                        selection_edit_ranges.push(prefix_range);
14827                    }
14828
14829                    if all_selection_lines_are_comments {
14830                        edits.extend(
14831                            selection_edit_ranges
14832                                .iter()
14833                                .cloned()
14834                                .map(|range| (range, empty_str.clone())),
14835                        );
14836                    } else {
14837                        let min_column = selection_edit_ranges
14838                            .iter()
14839                            .map(|range| range.start.column)
14840                            .min()
14841                            .unwrap_or(0);
14842                        edits.extend(selection_edit_ranges.iter().map(|range| {
14843                            let position = Point::new(range.start.row, min_column);
14844                            (position..position, first_prefix.clone())
14845                        }));
14846                    }
14847                } else if let Some(BlockCommentConfig {
14848                    start: full_comment_prefix,
14849                    end: comment_suffix,
14850                    ..
14851                }) = language.block_comment()
14852                {
14853                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14854                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14855                    let prefix_range = comment_prefix_range(
14856                        snapshot.deref(),
14857                        start_row,
14858                        comment_prefix,
14859                        comment_prefix_whitespace,
14860                        ignore_indent,
14861                    );
14862                    let suffix_range = comment_suffix_range(
14863                        snapshot.deref(),
14864                        end_row,
14865                        comment_suffix.trim_start_matches(' '),
14866                        comment_suffix.starts_with(' '),
14867                    );
14868
14869                    if prefix_range.is_empty() || suffix_range.is_empty() {
14870                        edits.push((
14871                            prefix_range.start..prefix_range.start,
14872                            full_comment_prefix.clone(),
14873                        ));
14874                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14875                        suffixes_inserted.push((end_row, comment_suffix.len()));
14876                    } else {
14877                        edits.push((prefix_range, empty_str.clone()));
14878                        edits.push((suffix_range, empty_str.clone()));
14879                    }
14880                } else {
14881                    continue;
14882                }
14883            }
14884
14885            drop(snapshot);
14886            this.buffer.update(cx, |buffer, cx| {
14887                buffer.edit(edits, None, cx);
14888            });
14889
14890            // Adjust selections so that they end before any comment suffixes that
14891            // were inserted.
14892            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14893            let mut selections = this.selections.all::<Point>(cx);
14894            let snapshot = this.buffer.read(cx).read(cx);
14895            for selection in &mut selections {
14896                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14897                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14898                        Ordering::Less => {
14899                            suffixes_inserted.next();
14900                            continue;
14901                        }
14902                        Ordering::Greater => break,
14903                        Ordering::Equal => {
14904                            if selection.end.column == snapshot.line_len(row) {
14905                                if selection.is_empty() {
14906                                    selection.start.column -= suffix_len as u32;
14907                                }
14908                                selection.end.column -= suffix_len as u32;
14909                            }
14910                            break;
14911                        }
14912                    }
14913                }
14914            }
14915
14916            drop(snapshot);
14917            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14918
14919            let selections = this.selections.all::<Point>(cx);
14920            let selections_on_single_row = selections.windows(2).all(|selections| {
14921                selections[0].start.row == selections[1].start.row
14922                    && selections[0].end.row == selections[1].end.row
14923                    && selections[0].start.row == selections[0].end.row
14924            });
14925            let selections_selecting = selections
14926                .iter()
14927                .any(|selection| selection.start != selection.end);
14928            let advance_downwards = action.advance_downwards
14929                && selections_on_single_row
14930                && !selections_selecting
14931                && !matches!(this.mode, EditorMode::SingleLine);
14932
14933            if advance_downwards {
14934                let snapshot = this.buffer.read(cx).snapshot(cx);
14935
14936                this.change_selections(Default::default(), window, cx, |s| {
14937                    s.move_cursors_with(|display_snapshot, display_point, _| {
14938                        let mut point = display_point.to_point(display_snapshot);
14939                        point.row += 1;
14940                        point = snapshot.clip_point(point, Bias::Left);
14941                        let display_point = point.to_display_point(display_snapshot);
14942                        let goal = SelectionGoal::HorizontalPosition(
14943                            display_snapshot
14944                                .x_for_display_point(display_point, text_layout_details)
14945                                .into(),
14946                        );
14947                        (display_point, goal)
14948                    })
14949                });
14950            }
14951        });
14952    }
14953
14954    pub fn select_enclosing_symbol(
14955        &mut self,
14956        _: &SelectEnclosingSymbol,
14957        window: &mut Window,
14958        cx: &mut Context<Self>,
14959    ) {
14960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14961
14962        let buffer = self.buffer.read(cx).snapshot(cx);
14963        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14964
14965        fn update_selection(
14966            selection: &Selection<usize>,
14967            buffer_snap: &MultiBufferSnapshot,
14968        ) -> Option<Selection<usize>> {
14969            let cursor = selection.head();
14970            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14971            for symbol in symbols.iter().rev() {
14972                let start = symbol.range.start.to_offset(buffer_snap);
14973                let end = symbol.range.end.to_offset(buffer_snap);
14974                let new_range = start..end;
14975                if start < selection.start || end > selection.end {
14976                    return Some(Selection {
14977                        id: selection.id,
14978                        start: new_range.start,
14979                        end: new_range.end,
14980                        goal: SelectionGoal::None,
14981                        reversed: selection.reversed,
14982                    });
14983                }
14984            }
14985            None
14986        }
14987
14988        let mut selected_larger_symbol = false;
14989        let new_selections = old_selections
14990            .iter()
14991            .map(|selection| match update_selection(selection, &buffer) {
14992                Some(new_selection) => {
14993                    if new_selection.range() != selection.range() {
14994                        selected_larger_symbol = true;
14995                    }
14996                    new_selection
14997                }
14998                None => selection.clone(),
14999            })
15000            .collect::<Vec<_>>();
15001
15002        if selected_larger_symbol {
15003            self.change_selections(Default::default(), window, cx, |s| {
15004                s.select(new_selections);
15005            });
15006        }
15007    }
15008
15009    pub fn select_larger_syntax_node(
15010        &mut self,
15011        _: &SelectLargerSyntaxNode,
15012        window: &mut Window,
15013        cx: &mut Context<Self>,
15014    ) {
15015        let Some(visible_row_count) = self.visible_row_count() else {
15016            return;
15017        };
15018        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15019        if old_selections.is_empty() {
15020            return;
15021        }
15022
15023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15024
15025        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15026        let buffer = self.buffer.read(cx).snapshot(cx);
15027
15028        let mut selected_larger_node = false;
15029        let mut new_selections = old_selections
15030            .iter()
15031            .map(|selection| {
15032                let old_range = selection.start..selection.end;
15033
15034                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15035                    // manually select word at selection
15036                    if ["string_content", "inline"].contains(&node.kind()) {
15037                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15038                        // ignore if word is already selected
15039                        if !word_range.is_empty() && old_range != word_range {
15040                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15041                            // only select word if start and end point belongs to same word
15042                            if word_range == last_word_range {
15043                                selected_larger_node = true;
15044                                return Selection {
15045                                    id: selection.id,
15046                                    start: word_range.start,
15047                                    end: word_range.end,
15048                                    goal: SelectionGoal::None,
15049                                    reversed: selection.reversed,
15050                                };
15051                            }
15052                        }
15053                    }
15054                }
15055
15056                let mut new_range = old_range.clone();
15057                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15058                {
15059                    new_range = match containing_range {
15060                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15061                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15062                    };
15063                    if !node.is_named() {
15064                        continue;
15065                    }
15066                    if !display_map.intersects_fold(new_range.start)
15067                        && !display_map.intersects_fold(new_range.end)
15068                    {
15069                        break;
15070                    }
15071                }
15072
15073                selected_larger_node |= new_range != old_range;
15074                Selection {
15075                    id: selection.id,
15076                    start: new_range.start,
15077                    end: new_range.end,
15078                    goal: SelectionGoal::None,
15079                    reversed: selection.reversed,
15080                }
15081            })
15082            .collect::<Vec<_>>();
15083
15084        if !selected_larger_node {
15085            return; // don't put this call in the history
15086        }
15087
15088        // scroll based on transformation done to the last selection created by the user
15089        let (last_old, last_new) = old_selections
15090            .last()
15091            .zip(new_selections.last().cloned())
15092            .expect("old_selections isn't empty");
15093
15094        // revert selection
15095        let is_selection_reversed = {
15096            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15097            new_selections.last_mut().expect("checked above").reversed =
15098                should_newest_selection_be_reversed;
15099            should_newest_selection_be_reversed
15100        };
15101
15102        if selected_larger_node {
15103            self.select_syntax_node_history.disable_clearing = true;
15104            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15105                s.select(new_selections.clone());
15106            });
15107            self.select_syntax_node_history.disable_clearing = false;
15108        }
15109
15110        let start_row = last_new.start.to_display_point(&display_map).row().0;
15111        let end_row = last_new.end.to_display_point(&display_map).row().0;
15112        let selection_height = end_row - start_row + 1;
15113        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15114
15115        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15116        let scroll_behavior = if fits_on_the_screen {
15117            self.request_autoscroll(Autoscroll::fit(), cx);
15118            SelectSyntaxNodeScrollBehavior::FitSelection
15119        } else if is_selection_reversed {
15120            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15121            SelectSyntaxNodeScrollBehavior::CursorTop
15122        } else {
15123            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15124            SelectSyntaxNodeScrollBehavior::CursorBottom
15125        };
15126
15127        self.select_syntax_node_history.push((
15128            old_selections,
15129            scroll_behavior,
15130            is_selection_reversed,
15131        ));
15132    }
15133
15134    pub fn select_smaller_syntax_node(
15135        &mut self,
15136        _: &SelectSmallerSyntaxNode,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) {
15140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15141
15142        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15143            self.select_syntax_node_history.pop()
15144        {
15145            if let Some(selection) = selections.last_mut() {
15146                selection.reversed = is_selection_reversed;
15147            }
15148
15149            self.select_syntax_node_history.disable_clearing = true;
15150            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15151                s.select(selections.to_vec());
15152            });
15153            self.select_syntax_node_history.disable_clearing = false;
15154
15155            match scroll_behavior {
15156                SelectSyntaxNodeScrollBehavior::CursorTop => {
15157                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15158                }
15159                SelectSyntaxNodeScrollBehavior::FitSelection => {
15160                    self.request_autoscroll(Autoscroll::fit(), cx);
15161                }
15162                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15163                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15164                }
15165            }
15166        }
15167    }
15168
15169    pub fn unwrap_syntax_node(
15170        &mut self,
15171        _: &UnwrapSyntaxNode,
15172        window: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15176
15177        let buffer = self.buffer.read(cx).snapshot(cx);
15178        let selections = self
15179            .selections
15180            .all::<usize>(cx)
15181            .into_iter()
15182            // subtracting the offset requires sorting
15183            .sorted_by_key(|i| i.start);
15184
15185        let full_edits = selections
15186            .into_iter()
15187            .filter_map(|selection| {
15188                let child = if selection.is_empty()
15189                    && let Some((_, ancestor_range)) =
15190                        buffer.syntax_ancestor(selection.start..selection.end)
15191                {
15192                    match ancestor_range {
15193                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15194                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15195                    }
15196                } else {
15197                    selection.range()
15198                };
15199
15200                let mut parent = child.clone();
15201                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15202                    parent = match ancestor_range {
15203                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15204                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15205                    };
15206                    if parent.start < child.start || parent.end > child.end {
15207                        break;
15208                    }
15209                }
15210
15211                if parent == child {
15212                    return None;
15213                }
15214                let text = buffer.text_for_range(child).collect::<String>();
15215                Some((selection.id, parent, text))
15216            })
15217            .collect::<Vec<_>>();
15218        if full_edits.is_empty() {
15219            return;
15220        }
15221
15222        self.transact(window, cx, |this, window, cx| {
15223            this.buffer.update(cx, |buffer, cx| {
15224                buffer.edit(
15225                    full_edits
15226                        .iter()
15227                        .map(|(_, p, t)| (p.clone(), t.clone()))
15228                        .collect::<Vec<_>>(),
15229                    None,
15230                    cx,
15231                );
15232            });
15233            this.change_selections(Default::default(), window, cx, |s| {
15234                let mut offset = 0;
15235                let mut selections = vec![];
15236                for (id, parent, text) in full_edits {
15237                    let start = parent.start - offset;
15238                    offset += parent.len() - text.len();
15239                    selections.push(Selection {
15240                        id,
15241                        start,
15242                        end: start + text.len(),
15243                        reversed: false,
15244                        goal: Default::default(),
15245                    });
15246                }
15247                s.select(selections);
15248            });
15249        });
15250    }
15251
15252    pub fn select_next_syntax_node(
15253        &mut self,
15254        _: &SelectNextSyntaxNode,
15255        window: &mut Window,
15256        cx: &mut Context<Self>,
15257    ) {
15258        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15259        if old_selections.is_empty() {
15260            return;
15261        }
15262
15263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15264
15265        let buffer = self.buffer.read(cx).snapshot(cx);
15266        let mut selected_sibling = false;
15267
15268        let new_selections = old_selections
15269            .iter()
15270            .map(|selection| {
15271                let old_range = selection.start..selection.end;
15272
15273                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15274                    let new_range = node.byte_range();
15275                    selected_sibling = true;
15276                    Selection {
15277                        id: selection.id,
15278                        start: new_range.start,
15279                        end: new_range.end,
15280                        goal: SelectionGoal::None,
15281                        reversed: selection.reversed,
15282                    }
15283                } else {
15284                    selection.clone()
15285                }
15286            })
15287            .collect::<Vec<_>>();
15288
15289        if selected_sibling {
15290            self.change_selections(
15291                SelectionEffects::scroll(Autoscroll::fit()),
15292                window,
15293                cx,
15294                |s| {
15295                    s.select(new_selections);
15296                },
15297            );
15298        }
15299    }
15300
15301    pub fn select_prev_syntax_node(
15302        &mut self,
15303        _: &SelectPreviousSyntaxNode,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) {
15307        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15308        if old_selections.is_empty() {
15309            return;
15310        }
15311
15312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15313
15314        let buffer = self.buffer.read(cx).snapshot(cx);
15315        let mut selected_sibling = false;
15316
15317        let new_selections = old_selections
15318            .iter()
15319            .map(|selection| {
15320                let old_range = selection.start..selection.end;
15321
15322                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15323                    let new_range = node.byte_range();
15324                    selected_sibling = true;
15325                    Selection {
15326                        id: selection.id,
15327                        start: new_range.start,
15328                        end: new_range.end,
15329                        goal: SelectionGoal::None,
15330                        reversed: selection.reversed,
15331                    }
15332                } else {
15333                    selection.clone()
15334                }
15335            })
15336            .collect::<Vec<_>>();
15337
15338        if selected_sibling {
15339            self.change_selections(
15340                SelectionEffects::scroll(Autoscroll::fit()),
15341                window,
15342                cx,
15343                |s| {
15344                    s.select(new_selections);
15345                },
15346            );
15347        }
15348    }
15349
15350    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15351        if !EditorSettings::get_global(cx).gutter.runnables {
15352            self.clear_tasks();
15353            return Task::ready(());
15354        }
15355        let project = self.project().map(Entity::downgrade);
15356        let task_sources = self.lsp_task_sources(cx);
15357        let multi_buffer = self.buffer.downgrade();
15358        cx.spawn_in(window, async move |editor, cx| {
15359            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15360            let Some(project) = project.and_then(|p| p.upgrade()) else {
15361                return;
15362            };
15363            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15364                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15365            }) else {
15366                return;
15367            };
15368
15369            let hide_runnables = project
15370                .update(cx, |project, _| project.is_via_collab())
15371                .unwrap_or(true);
15372            if hide_runnables {
15373                return;
15374            }
15375            let new_rows =
15376                cx.background_spawn({
15377                    let snapshot = display_snapshot.clone();
15378                    async move {
15379                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15380                    }
15381                })
15382                    .await;
15383            let Ok(lsp_tasks) =
15384                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15385            else {
15386                return;
15387            };
15388            let lsp_tasks = lsp_tasks.await;
15389
15390            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15391                lsp_tasks
15392                    .into_iter()
15393                    .flat_map(|(kind, tasks)| {
15394                        tasks.into_iter().filter_map(move |(location, task)| {
15395                            Some((kind.clone(), location?, task))
15396                        })
15397                    })
15398                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15399                        let buffer = location.target.buffer;
15400                        let buffer_snapshot = buffer.read(cx).snapshot();
15401                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15402                            |(excerpt_id, snapshot, _)| {
15403                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15404                                    display_snapshot
15405                                        .buffer_snapshot
15406                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15407                                } else {
15408                                    None
15409                                }
15410                            },
15411                        );
15412                        if let Some(offset) = offset {
15413                            let task_buffer_range =
15414                                location.target.range.to_point(&buffer_snapshot);
15415                            let context_buffer_range =
15416                                task_buffer_range.to_offset(&buffer_snapshot);
15417                            let context_range = BufferOffset(context_buffer_range.start)
15418                                ..BufferOffset(context_buffer_range.end);
15419
15420                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15421                                .or_insert_with(|| RunnableTasks {
15422                                    templates: Vec::new(),
15423                                    offset,
15424                                    column: task_buffer_range.start.column,
15425                                    extra_variables: HashMap::default(),
15426                                    context_range,
15427                                })
15428                                .templates
15429                                .push((kind, task.original_task().clone()));
15430                        }
15431
15432                        acc
15433                    })
15434            }) else {
15435                return;
15436            };
15437
15438            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15439                buffer.language_settings(cx).tasks.prefer_lsp
15440            }) else {
15441                return;
15442            };
15443
15444            let rows = Self::runnable_rows(
15445                project,
15446                display_snapshot,
15447                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15448                new_rows,
15449                cx.clone(),
15450            )
15451            .await;
15452            editor
15453                .update(cx, |editor, _| {
15454                    editor.clear_tasks();
15455                    for (key, mut value) in rows {
15456                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15457                            value.templates.extend(lsp_tasks.templates);
15458                        }
15459
15460                        editor.insert_tasks(key, value);
15461                    }
15462                    for (key, value) in lsp_tasks_by_rows {
15463                        editor.insert_tasks(key, value);
15464                    }
15465                })
15466                .ok();
15467        })
15468    }
15469    fn fetch_runnable_ranges(
15470        snapshot: &DisplaySnapshot,
15471        range: Range<Anchor>,
15472    ) -> Vec<language::RunnableRange> {
15473        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15474    }
15475
15476    fn runnable_rows(
15477        project: Entity<Project>,
15478        snapshot: DisplaySnapshot,
15479        prefer_lsp: bool,
15480        runnable_ranges: Vec<RunnableRange>,
15481        cx: AsyncWindowContext,
15482    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15483        cx.spawn(async move |cx| {
15484            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15485            for mut runnable in runnable_ranges {
15486                let Some(tasks) = cx
15487                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15488                    .ok()
15489                else {
15490                    continue;
15491                };
15492                let mut tasks = tasks.await;
15493
15494                if prefer_lsp {
15495                    tasks.retain(|(task_kind, _)| {
15496                        !matches!(task_kind, TaskSourceKind::Language { .. })
15497                    });
15498                }
15499                if tasks.is_empty() {
15500                    continue;
15501                }
15502
15503                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15504                let Some(row) = snapshot
15505                    .buffer_snapshot
15506                    .buffer_line_for_row(MultiBufferRow(point.row))
15507                    .map(|(_, range)| range.start.row)
15508                else {
15509                    continue;
15510                };
15511
15512                let context_range =
15513                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15514                runnable_rows.push((
15515                    (runnable.buffer_id, row),
15516                    RunnableTasks {
15517                        templates: tasks,
15518                        offset: snapshot
15519                            .buffer_snapshot
15520                            .anchor_before(runnable.run_range.start),
15521                        context_range,
15522                        column: point.column,
15523                        extra_variables: runnable.extra_captures,
15524                    },
15525                ));
15526            }
15527            runnable_rows
15528        })
15529    }
15530
15531    fn templates_with_tags(
15532        project: &Entity<Project>,
15533        runnable: &mut Runnable,
15534        cx: &mut App,
15535    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15536        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15537            let (worktree_id, file) = project
15538                .buffer_for_id(runnable.buffer, cx)
15539                .and_then(|buffer| buffer.read(cx).file())
15540                .map(|file| (file.worktree_id(cx), file.clone()))
15541                .unzip();
15542
15543            (
15544                project.task_store().read(cx).task_inventory().cloned(),
15545                worktree_id,
15546                file,
15547            )
15548        });
15549
15550        let tags = mem::take(&mut runnable.tags);
15551        let language = runnable.language.clone();
15552        cx.spawn(async move |cx| {
15553            let mut templates_with_tags = Vec::new();
15554            if let Some(inventory) = inventory {
15555                for RunnableTag(tag) in tags {
15556                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15557                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15558                    }) else {
15559                        return templates_with_tags;
15560                    };
15561                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15562                        move |(_, template)| {
15563                            template.tags.iter().any(|source_tag| source_tag == &tag)
15564                        },
15565                    ));
15566                }
15567            }
15568            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15569
15570            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15571                // Strongest source wins; if we have worktree tag binding, prefer that to
15572                // global and language bindings;
15573                // if we have a global binding, prefer that to language binding.
15574                let first_mismatch = templates_with_tags
15575                    .iter()
15576                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15577                if let Some(index) = first_mismatch {
15578                    templates_with_tags.truncate(index);
15579                }
15580            }
15581
15582            templates_with_tags
15583        })
15584    }
15585
15586    pub fn move_to_enclosing_bracket(
15587        &mut self,
15588        _: &MoveToEnclosingBracket,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591    ) {
15592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15593        self.change_selections(Default::default(), window, cx, |s| {
15594            s.move_offsets_with(|snapshot, selection| {
15595                let Some(enclosing_bracket_ranges) =
15596                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15597                else {
15598                    return;
15599                };
15600
15601                let mut best_length = usize::MAX;
15602                let mut best_inside = false;
15603                let mut best_in_bracket_range = false;
15604                let mut best_destination = None;
15605                for (open, close) in enclosing_bracket_ranges {
15606                    let close = close.to_inclusive();
15607                    let length = close.end() - open.start;
15608                    let inside = selection.start >= open.end && selection.end <= *close.start();
15609                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15610                        || close.contains(&selection.head());
15611
15612                    // If best is next to a bracket and current isn't, skip
15613                    if !in_bracket_range && best_in_bracket_range {
15614                        continue;
15615                    }
15616
15617                    // Prefer smaller lengths unless best is inside and current isn't
15618                    if length > best_length && (best_inside || !inside) {
15619                        continue;
15620                    }
15621
15622                    best_length = length;
15623                    best_inside = inside;
15624                    best_in_bracket_range = in_bracket_range;
15625                    best_destination = Some(
15626                        if close.contains(&selection.start) && close.contains(&selection.end) {
15627                            if inside { open.end } else { open.start }
15628                        } else if inside {
15629                            *close.start()
15630                        } else {
15631                            *close.end()
15632                        },
15633                    );
15634                }
15635
15636                if let Some(destination) = best_destination {
15637                    selection.collapse_to(destination, SelectionGoal::None);
15638                }
15639            })
15640        });
15641    }
15642
15643    pub fn undo_selection(
15644        &mut self,
15645        _: &UndoSelection,
15646        window: &mut Window,
15647        cx: &mut Context<Self>,
15648    ) {
15649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15650        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15651            self.selection_history.mode = SelectionHistoryMode::Undoing;
15652            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15653                this.end_selection(window, cx);
15654                this.change_selections(
15655                    SelectionEffects::scroll(Autoscroll::newest()),
15656                    window,
15657                    cx,
15658                    |s| s.select_anchors(entry.selections.to_vec()),
15659                );
15660            });
15661            self.selection_history.mode = SelectionHistoryMode::Normal;
15662
15663            self.select_next_state = entry.select_next_state;
15664            self.select_prev_state = entry.select_prev_state;
15665            self.add_selections_state = entry.add_selections_state;
15666        }
15667    }
15668
15669    pub fn redo_selection(
15670        &mut self,
15671        _: &RedoSelection,
15672        window: &mut Window,
15673        cx: &mut Context<Self>,
15674    ) {
15675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15676        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15677            self.selection_history.mode = SelectionHistoryMode::Redoing;
15678            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15679                this.end_selection(window, cx);
15680                this.change_selections(
15681                    SelectionEffects::scroll(Autoscroll::newest()),
15682                    window,
15683                    cx,
15684                    |s| s.select_anchors(entry.selections.to_vec()),
15685                );
15686            });
15687            self.selection_history.mode = SelectionHistoryMode::Normal;
15688
15689            self.select_next_state = entry.select_next_state;
15690            self.select_prev_state = entry.select_prev_state;
15691            self.add_selections_state = entry.add_selections_state;
15692        }
15693    }
15694
15695    pub fn expand_excerpts(
15696        &mut self,
15697        action: &ExpandExcerpts,
15698        _: &mut Window,
15699        cx: &mut Context<Self>,
15700    ) {
15701        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15702    }
15703
15704    pub fn expand_excerpts_down(
15705        &mut self,
15706        action: &ExpandExcerptsDown,
15707        _: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) {
15710        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15711    }
15712
15713    pub fn expand_excerpts_up(
15714        &mut self,
15715        action: &ExpandExcerptsUp,
15716        _: &mut Window,
15717        cx: &mut Context<Self>,
15718    ) {
15719        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15720    }
15721
15722    pub fn expand_excerpts_for_direction(
15723        &mut self,
15724        lines: u32,
15725        direction: ExpandExcerptDirection,
15726
15727        cx: &mut Context<Self>,
15728    ) {
15729        let selections = self.selections.disjoint_anchors_arc();
15730
15731        let lines = if lines == 0 {
15732            EditorSettings::get_global(cx).expand_excerpt_lines
15733        } else {
15734            lines
15735        };
15736
15737        self.buffer.update(cx, |buffer, cx| {
15738            let snapshot = buffer.snapshot(cx);
15739            let mut excerpt_ids = selections
15740                .iter()
15741                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15742                .collect::<Vec<_>>();
15743            excerpt_ids.sort();
15744            excerpt_ids.dedup();
15745            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15746        })
15747    }
15748
15749    pub fn expand_excerpt(
15750        &mut self,
15751        excerpt: ExcerptId,
15752        direction: ExpandExcerptDirection,
15753        window: &mut Window,
15754        cx: &mut Context<Self>,
15755    ) {
15756        let current_scroll_position = self.scroll_position(cx);
15757        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15758        let mut should_scroll_up = false;
15759
15760        if direction == ExpandExcerptDirection::Down {
15761            let multi_buffer = self.buffer.read(cx);
15762            let snapshot = multi_buffer.snapshot(cx);
15763            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15764                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15765                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15766            {
15767                let buffer_snapshot = buffer.read(cx).snapshot();
15768                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15769                let last_row = buffer_snapshot.max_point().row;
15770                let lines_below = last_row.saturating_sub(excerpt_end_row);
15771                should_scroll_up = lines_below >= lines_to_expand;
15772            }
15773        }
15774
15775        self.buffer.update(cx, |buffer, cx| {
15776            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15777        });
15778
15779        if should_scroll_up {
15780            let new_scroll_position =
15781                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15782            self.set_scroll_position(new_scroll_position, window, cx);
15783        }
15784    }
15785
15786    pub fn go_to_singleton_buffer_point(
15787        &mut self,
15788        point: Point,
15789        window: &mut Window,
15790        cx: &mut Context<Self>,
15791    ) {
15792        self.go_to_singleton_buffer_range(point..point, window, cx);
15793    }
15794
15795    pub fn go_to_singleton_buffer_range(
15796        &mut self,
15797        range: Range<Point>,
15798        window: &mut Window,
15799        cx: &mut Context<Self>,
15800    ) {
15801        let multibuffer = self.buffer().read(cx);
15802        let Some(buffer) = multibuffer.as_singleton() else {
15803            return;
15804        };
15805        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15806            return;
15807        };
15808        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15809            return;
15810        };
15811        self.change_selections(
15812            SelectionEffects::default().nav_history(true),
15813            window,
15814            cx,
15815            |s| s.select_anchor_ranges([start..end]),
15816        );
15817    }
15818
15819    pub fn go_to_diagnostic(
15820        &mut self,
15821        action: &GoToDiagnostic,
15822        window: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        if !self.diagnostics_enabled() {
15826            return;
15827        }
15828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15829        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15830    }
15831
15832    pub fn go_to_prev_diagnostic(
15833        &mut self,
15834        action: &GoToPreviousDiagnostic,
15835        window: &mut Window,
15836        cx: &mut Context<Self>,
15837    ) {
15838        if !self.diagnostics_enabled() {
15839            return;
15840        }
15841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15842        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15843    }
15844
15845    pub fn go_to_diagnostic_impl(
15846        &mut self,
15847        direction: Direction,
15848        severity: GoToDiagnosticSeverityFilter,
15849        window: &mut Window,
15850        cx: &mut Context<Self>,
15851    ) {
15852        let buffer = self.buffer.read(cx).snapshot(cx);
15853        let selection = self.selections.newest::<usize>(cx);
15854
15855        let mut active_group_id = None;
15856        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15857            && active_group.active_range.start.to_offset(&buffer) == selection.start
15858        {
15859            active_group_id = Some(active_group.group_id);
15860        }
15861
15862        fn filtered(
15863            snapshot: EditorSnapshot,
15864            severity: GoToDiagnosticSeverityFilter,
15865            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15866        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15867            diagnostics
15868                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15869                .filter(|entry| entry.range.start != entry.range.end)
15870                .filter(|entry| !entry.diagnostic.is_unnecessary)
15871                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15872        }
15873
15874        let snapshot = self.snapshot(window, cx);
15875        let before = filtered(
15876            snapshot.clone(),
15877            severity,
15878            buffer
15879                .diagnostics_in_range(0..selection.start)
15880                .filter(|entry| entry.range.start <= selection.start),
15881        );
15882        let after = filtered(
15883            snapshot,
15884            severity,
15885            buffer
15886                .diagnostics_in_range(selection.start..buffer.len())
15887                .filter(|entry| entry.range.start >= selection.start),
15888        );
15889
15890        let mut found: Option<DiagnosticEntry<usize>> = None;
15891        if direction == Direction::Prev {
15892            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15893            {
15894                for diagnostic in prev_diagnostics.into_iter().rev() {
15895                    if diagnostic.range.start != selection.start
15896                        || active_group_id
15897                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15898                    {
15899                        found = Some(diagnostic);
15900                        break 'outer;
15901                    }
15902                }
15903            }
15904        } else {
15905            for diagnostic in after.chain(before) {
15906                if diagnostic.range.start != selection.start
15907                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15908                {
15909                    found = Some(diagnostic);
15910                    break;
15911                }
15912            }
15913        }
15914        let Some(next_diagnostic) = found else {
15915            return;
15916        };
15917
15918        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15919        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15920            return;
15921        };
15922        self.change_selections(Default::default(), window, cx, |s| {
15923            s.select_ranges(vec![
15924                next_diagnostic.range.start..next_diagnostic.range.start,
15925            ])
15926        });
15927        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15928        self.refresh_edit_prediction(false, true, window, cx);
15929    }
15930
15931    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15933        let snapshot = self.snapshot(window, cx);
15934        let selection = self.selections.newest::<Point>(cx);
15935        self.go_to_hunk_before_or_after_position(
15936            &snapshot,
15937            selection.head(),
15938            Direction::Next,
15939            window,
15940            cx,
15941        );
15942    }
15943
15944    pub fn go_to_hunk_before_or_after_position(
15945        &mut self,
15946        snapshot: &EditorSnapshot,
15947        position: Point,
15948        direction: Direction,
15949        window: &mut Window,
15950        cx: &mut Context<Editor>,
15951    ) {
15952        let row = if direction == Direction::Next {
15953            self.hunk_after_position(snapshot, position)
15954                .map(|hunk| hunk.row_range.start)
15955        } else {
15956            self.hunk_before_position(snapshot, position)
15957        };
15958
15959        if let Some(row) = row {
15960            let destination = Point::new(row.0, 0);
15961            let autoscroll = Autoscroll::center();
15962
15963            self.unfold_ranges(&[destination..destination], false, false, cx);
15964            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15965                s.select_ranges([destination..destination]);
15966            });
15967        }
15968    }
15969
15970    fn hunk_after_position(
15971        &mut self,
15972        snapshot: &EditorSnapshot,
15973        position: Point,
15974    ) -> Option<MultiBufferDiffHunk> {
15975        snapshot
15976            .buffer_snapshot
15977            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15978            .find(|hunk| hunk.row_range.start.0 > position.row)
15979            .or_else(|| {
15980                snapshot
15981                    .buffer_snapshot
15982                    .diff_hunks_in_range(Point::zero()..position)
15983                    .find(|hunk| hunk.row_range.end.0 < position.row)
15984            })
15985    }
15986
15987    fn go_to_prev_hunk(
15988        &mut self,
15989        _: &GoToPreviousHunk,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15994        let snapshot = self.snapshot(window, cx);
15995        let selection = self.selections.newest::<Point>(cx);
15996        self.go_to_hunk_before_or_after_position(
15997            &snapshot,
15998            selection.head(),
15999            Direction::Prev,
16000            window,
16001            cx,
16002        );
16003    }
16004
16005    fn hunk_before_position(
16006        &mut self,
16007        snapshot: &EditorSnapshot,
16008        position: Point,
16009    ) -> Option<MultiBufferRow> {
16010        snapshot
16011            .buffer_snapshot
16012            .diff_hunk_before(position)
16013            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16014    }
16015
16016    fn go_to_next_change(
16017        &mut self,
16018        _: &GoToNextChange,
16019        window: &mut Window,
16020        cx: &mut Context<Self>,
16021    ) {
16022        if let Some(selections) = self
16023            .change_list
16024            .next_change(1, Direction::Next)
16025            .map(|s| s.to_vec())
16026        {
16027            self.change_selections(Default::default(), window, cx, |s| {
16028                let map = s.display_map();
16029                s.select_display_ranges(selections.iter().map(|a| {
16030                    let point = a.to_display_point(&map);
16031                    point..point
16032                }))
16033            })
16034        }
16035    }
16036
16037    fn go_to_previous_change(
16038        &mut self,
16039        _: &GoToPreviousChange,
16040        window: &mut Window,
16041        cx: &mut Context<Self>,
16042    ) {
16043        if let Some(selections) = self
16044            .change_list
16045            .next_change(1, Direction::Prev)
16046            .map(|s| s.to_vec())
16047        {
16048            self.change_selections(Default::default(), window, cx, |s| {
16049                let map = s.display_map();
16050                s.select_display_ranges(selections.iter().map(|a| {
16051                    let point = a.to_display_point(&map);
16052                    point..point
16053                }))
16054            })
16055        }
16056    }
16057
16058    pub fn go_to_next_document_highlight(
16059        &mut self,
16060        _: &GoToNextDocumentHighlight,
16061        window: &mut Window,
16062        cx: &mut Context<Self>,
16063    ) {
16064        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16065    }
16066
16067    pub fn go_to_prev_document_highlight(
16068        &mut self,
16069        _: &GoToPreviousDocumentHighlight,
16070        window: &mut Window,
16071        cx: &mut Context<Self>,
16072    ) {
16073        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16074    }
16075
16076    pub fn go_to_document_highlight_before_or_after_position(
16077        &mut self,
16078        direction: Direction,
16079        window: &mut Window,
16080        cx: &mut Context<Editor>,
16081    ) {
16082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16083        let snapshot = self.snapshot(window, cx);
16084        let buffer = &snapshot.buffer_snapshot;
16085        let position = self.selections.newest::<Point>(cx).head();
16086        let anchor_position = buffer.anchor_after(position);
16087
16088        // Get all document highlights (both read and write)
16089        let mut all_highlights = Vec::new();
16090
16091        if let Some((_, read_highlights)) = self
16092            .background_highlights
16093            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16094        {
16095            all_highlights.extend(read_highlights.iter());
16096        }
16097
16098        if let Some((_, write_highlights)) = self
16099            .background_highlights
16100            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16101        {
16102            all_highlights.extend(write_highlights.iter());
16103        }
16104
16105        if all_highlights.is_empty() {
16106            return;
16107        }
16108
16109        // Sort highlights by position
16110        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16111
16112        let target_highlight = match direction {
16113            Direction::Next => {
16114                // Find the first highlight after the current position
16115                all_highlights
16116                    .iter()
16117                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16118            }
16119            Direction::Prev => {
16120                // Find the last highlight before the current position
16121                all_highlights
16122                    .iter()
16123                    .rev()
16124                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16125            }
16126        };
16127
16128        if let Some(highlight) = target_highlight {
16129            let destination = highlight.start.to_point(buffer);
16130            let autoscroll = Autoscroll::center();
16131
16132            self.unfold_ranges(&[destination..destination], false, false, cx);
16133            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16134                s.select_ranges([destination..destination]);
16135            });
16136        }
16137    }
16138
16139    fn go_to_line<T: 'static>(
16140        &mut self,
16141        position: Anchor,
16142        highlight_color: Option<Hsla>,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) {
16146        let snapshot = self.snapshot(window, cx).display_snapshot;
16147        let position = position.to_point(&snapshot.buffer_snapshot);
16148        let start = snapshot
16149            .buffer_snapshot
16150            .clip_point(Point::new(position.row, 0), Bias::Left);
16151        let end = start + Point::new(1, 0);
16152        let start = snapshot.buffer_snapshot.anchor_before(start);
16153        let end = snapshot.buffer_snapshot.anchor_before(end);
16154
16155        self.highlight_rows::<T>(
16156            start..end,
16157            highlight_color
16158                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16159            Default::default(),
16160            cx,
16161        );
16162
16163        if self.buffer.read(cx).is_singleton() {
16164            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16165        }
16166    }
16167
16168    pub fn go_to_definition(
16169        &mut self,
16170        _: &GoToDefinition,
16171        window: &mut Window,
16172        cx: &mut Context<Self>,
16173    ) -> Task<Result<Navigated>> {
16174        let definition =
16175            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16176        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16177        cx.spawn_in(window, async move |editor, cx| {
16178            if definition.await? == Navigated::Yes {
16179                return Ok(Navigated::Yes);
16180            }
16181            match fallback_strategy {
16182                GoToDefinitionFallback::None => Ok(Navigated::No),
16183                GoToDefinitionFallback::FindAllReferences => {
16184                    match editor.update_in(cx, |editor, window, cx| {
16185                        editor.find_all_references(&FindAllReferences, window, cx)
16186                    })? {
16187                        Some(references) => references.await,
16188                        None => Ok(Navigated::No),
16189                    }
16190                }
16191            }
16192        })
16193    }
16194
16195    pub fn go_to_declaration(
16196        &mut self,
16197        _: &GoToDeclaration,
16198        window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) -> Task<Result<Navigated>> {
16201        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16202    }
16203
16204    pub fn go_to_declaration_split(
16205        &mut self,
16206        _: &GoToDeclaration,
16207        window: &mut Window,
16208        cx: &mut Context<Self>,
16209    ) -> Task<Result<Navigated>> {
16210        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16211    }
16212
16213    pub fn go_to_implementation(
16214        &mut self,
16215        _: &GoToImplementation,
16216        window: &mut Window,
16217        cx: &mut Context<Self>,
16218    ) -> Task<Result<Navigated>> {
16219        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16220    }
16221
16222    pub fn go_to_implementation_split(
16223        &mut self,
16224        _: &GoToImplementationSplit,
16225        window: &mut Window,
16226        cx: &mut Context<Self>,
16227    ) -> Task<Result<Navigated>> {
16228        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16229    }
16230
16231    pub fn go_to_type_definition(
16232        &mut self,
16233        _: &GoToTypeDefinition,
16234        window: &mut Window,
16235        cx: &mut Context<Self>,
16236    ) -> Task<Result<Navigated>> {
16237        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16238    }
16239
16240    pub fn go_to_definition_split(
16241        &mut self,
16242        _: &GoToDefinitionSplit,
16243        window: &mut Window,
16244        cx: &mut Context<Self>,
16245    ) -> Task<Result<Navigated>> {
16246        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16247    }
16248
16249    pub fn go_to_type_definition_split(
16250        &mut self,
16251        _: &GoToTypeDefinitionSplit,
16252        window: &mut Window,
16253        cx: &mut Context<Self>,
16254    ) -> Task<Result<Navigated>> {
16255        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16256    }
16257
16258    fn go_to_definition_of_kind(
16259        &mut self,
16260        kind: GotoDefinitionKind,
16261        split: bool,
16262        window: &mut Window,
16263        cx: &mut Context<Self>,
16264    ) -> Task<Result<Navigated>> {
16265        let Some(provider) = self.semantics_provider.clone() else {
16266            return Task::ready(Ok(Navigated::No));
16267        };
16268        let head = self.selections.newest::<usize>(cx).head();
16269        let buffer = self.buffer.read(cx);
16270        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16271            return Task::ready(Ok(Navigated::No));
16272        };
16273        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16274            return Task::ready(Ok(Navigated::No));
16275        };
16276
16277        cx.spawn_in(window, async move |editor, cx| {
16278            let Some(definitions) = definitions.await? else {
16279                return Ok(Navigated::No);
16280            };
16281            let navigated = editor
16282                .update_in(cx, |editor, window, cx| {
16283                    editor.navigate_to_hover_links(
16284                        Some(kind),
16285                        definitions
16286                            .into_iter()
16287                            .filter(|location| {
16288                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16289                            })
16290                            .map(HoverLink::Text)
16291                            .collect::<Vec<_>>(),
16292                        split,
16293                        window,
16294                        cx,
16295                    )
16296                })?
16297                .await?;
16298            anyhow::Ok(navigated)
16299        })
16300    }
16301
16302    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16303        let selection = self.selections.newest_anchor();
16304        let head = selection.head();
16305        let tail = selection.tail();
16306
16307        let Some((buffer, start_position)) =
16308            self.buffer.read(cx).text_anchor_for_position(head, cx)
16309        else {
16310            return;
16311        };
16312
16313        let end_position = if head != tail {
16314            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16315                return;
16316            };
16317            Some(pos)
16318        } else {
16319            None
16320        };
16321
16322        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16323            let url = if let Some(end_pos) = end_position {
16324                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16325            } else {
16326                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16327            };
16328
16329            if let Some(url) = url {
16330                editor.update(cx, |_, cx| {
16331                    cx.open_url(&url);
16332                })
16333            } else {
16334                Ok(())
16335            }
16336        });
16337
16338        url_finder.detach();
16339    }
16340
16341    pub fn open_selected_filename(
16342        &mut self,
16343        _: &OpenSelectedFilename,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        let Some(workspace) = self.workspace() else {
16348            return;
16349        };
16350
16351        let position = self.selections.newest_anchor().head();
16352
16353        let Some((buffer, buffer_position)) =
16354            self.buffer.read(cx).text_anchor_for_position(position, cx)
16355        else {
16356            return;
16357        };
16358
16359        let project = self.project.clone();
16360
16361        cx.spawn_in(window, async move |_, cx| {
16362            let result = find_file(&buffer, project, buffer_position, cx).await;
16363
16364            if let Some((_, path)) = result {
16365                workspace
16366                    .update_in(cx, |workspace, window, cx| {
16367                        workspace.open_resolved_path(path, window, cx)
16368                    })?
16369                    .await?;
16370            }
16371            anyhow::Ok(())
16372        })
16373        .detach();
16374    }
16375
16376    pub(crate) fn navigate_to_hover_links(
16377        &mut self,
16378        kind: Option<GotoDefinitionKind>,
16379        definitions: Vec<HoverLink>,
16380        split: bool,
16381        window: &mut Window,
16382        cx: &mut Context<Editor>,
16383    ) -> Task<Result<Navigated>> {
16384        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16385        let mut first_url_or_file = None;
16386        let definitions: Vec<_> = definitions
16387            .into_iter()
16388            .filter_map(|def| match def {
16389                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16390                HoverLink::InlayHint(lsp_location, server_id) => {
16391                    let computation =
16392                        self.compute_target_location(lsp_location, server_id, window, cx);
16393                    Some(cx.background_spawn(computation))
16394                }
16395                HoverLink::Url(url) => {
16396                    first_url_or_file = Some(Either::Left(url));
16397                    None
16398                }
16399                HoverLink::File(path) => {
16400                    first_url_or_file = Some(Either::Right(path));
16401                    None
16402                }
16403            })
16404            .collect();
16405
16406        let workspace = self.workspace();
16407
16408        cx.spawn_in(window, async move |editor, cx| {
16409            let locations: Vec<Location> = future::join_all(definitions)
16410                .await
16411                .into_iter()
16412                .filter_map(|location| location.transpose())
16413                .collect::<Result<_>>()
16414                .context("location tasks")?;
16415            let mut locations = cx.update(|_, cx| {
16416                locations
16417                    .into_iter()
16418                    .map(|location| {
16419                        let buffer = location.buffer.read(cx);
16420                        (location.buffer, location.range.to_point(buffer))
16421                    })
16422                    .into_group_map()
16423            })?;
16424            let mut num_locations = 0;
16425            for ranges in locations.values_mut() {
16426                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16427                ranges.dedup();
16428                num_locations += ranges.len();
16429            }
16430
16431            if num_locations > 1 {
16432                let Some(workspace) = workspace else {
16433                    return Ok(Navigated::No);
16434                };
16435
16436                let tab_kind = match kind {
16437                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16438                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16439                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16440                    Some(GotoDefinitionKind::Type) => "Types",
16441                };
16442                let title = editor
16443                    .update_in(cx, |_, _, cx| {
16444                        let target = locations
16445                            .iter()
16446                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16447                            .map(|(buffer, location)| {
16448                                buffer
16449                                    .read(cx)
16450                                    .text_for_range(location.clone())
16451                                    .collect::<String>()
16452                            })
16453                            .filter(|text| !text.contains('\n'))
16454                            .unique()
16455                            .take(3)
16456                            .join(", ");
16457                        if target.is_empty() {
16458                            tab_kind.to_owned()
16459                        } else {
16460                            format!("{tab_kind} for {target}")
16461                        }
16462                    })
16463                    .context("buffer title")?;
16464
16465                let opened = workspace
16466                    .update_in(cx, |workspace, window, cx| {
16467                        Self::open_locations_in_multibuffer(
16468                            workspace,
16469                            locations,
16470                            title,
16471                            split,
16472                            MultibufferSelectionMode::First,
16473                            window,
16474                            cx,
16475                        )
16476                    })
16477                    .is_ok();
16478
16479                anyhow::Ok(Navigated::from_bool(opened))
16480            } else if num_locations == 0 {
16481                // If there is one url or file, open it directly
16482                match first_url_or_file {
16483                    Some(Either::Left(url)) => {
16484                        cx.update(|_, cx| cx.open_url(&url))?;
16485                        Ok(Navigated::Yes)
16486                    }
16487                    Some(Either::Right(path)) => {
16488                        let Some(workspace) = workspace else {
16489                            return Ok(Navigated::No);
16490                        };
16491
16492                        workspace
16493                            .update_in(cx, |workspace, window, cx| {
16494                                workspace.open_resolved_path(path, window, cx)
16495                            })?
16496                            .await?;
16497                        Ok(Navigated::Yes)
16498                    }
16499                    None => Ok(Navigated::No),
16500                }
16501            } else {
16502                let Some(workspace) = workspace else {
16503                    return Ok(Navigated::No);
16504                };
16505
16506                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16507                let target_range = target_ranges.first().unwrap().clone();
16508
16509                editor.update_in(cx, |editor, window, cx| {
16510                    let range = target_range.to_point(target_buffer.read(cx));
16511                    let range = editor.range_for_match(&range);
16512                    let range = collapse_multiline_range(range);
16513
16514                    if !split
16515                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16516                    {
16517                        editor.go_to_singleton_buffer_range(range, window, cx);
16518                    } else {
16519                        let pane = workspace.read(cx).active_pane().clone();
16520                        window.defer(cx, move |window, cx| {
16521                            let target_editor: Entity<Self> =
16522                                workspace.update(cx, |workspace, cx| {
16523                                    let pane = if split {
16524                                        workspace.adjacent_pane(window, cx)
16525                                    } else {
16526                                        workspace.active_pane().clone()
16527                                    };
16528
16529                                    workspace.open_project_item(
16530                                        pane,
16531                                        target_buffer.clone(),
16532                                        true,
16533                                        true,
16534                                        window,
16535                                        cx,
16536                                    )
16537                                });
16538                            target_editor.update(cx, |target_editor, cx| {
16539                                // When selecting a definition in a different buffer, disable the nav history
16540                                // to avoid creating a history entry at the previous cursor location.
16541                                pane.update(cx, |pane, _| pane.disable_history());
16542                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16543                                pane.update(cx, |pane, _| pane.enable_history());
16544                            });
16545                        });
16546                    }
16547                    Navigated::Yes
16548                })
16549            }
16550        })
16551    }
16552
16553    fn compute_target_location(
16554        &self,
16555        lsp_location: lsp::Location,
16556        server_id: LanguageServerId,
16557        window: &mut Window,
16558        cx: &mut Context<Self>,
16559    ) -> Task<anyhow::Result<Option<Location>>> {
16560        let Some(project) = self.project.clone() else {
16561            return Task::ready(Ok(None));
16562        };
16563
16564        cx.spawn_in(window, async move |editor, cx| {
16565            let location_task = editor.update(cx, |_, cx| {
16566                project.update(cx, |project, cx| {
16567                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16568                })
16569            })?;
16570            let location = Some({
16571                let target_buffer_handle = location_task.await.context("open local buffer")?;
16572                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16573                    let target_start = target_buffer
16574                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16575                    let target_end = target_buffer
16576                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16577                    target_buffer.anchor_after(target_start)
16578                        ..target_buffer.anchor_before(target_end)
16579                })?;
16580                Location {
16581                    buffer: target_buffer_handle,
16582                    range,
16583                }
16584            });
16585            Ok(location)
16586        })
16587    }
16588
16589    pub fn find_all_references(
16590        &mut self,
16591        _: &FindAllReferences,
16592        window: &mut Window,
16593        cx: &mut Context<Self>,
16594    ) -> Option<Task<Result<Navigated>>> {
16595        let selection = self.selections.newest::<usize>(cx);
16596        let multi_buffer = self.buffer.read(cx);
16597        let head = selection.head();
16598
16599        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16600        let head_anchor = multi_buffer_snapshot.anchor_at(
16601            head,
16602            if head < selection.tail() {
16603                Bias::Right
16604            } else {
16605                Bias::Left
16606            },
16607        );
16608
16609        match self
16610            .find_all_references_task_sources
16611            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16612        {
16613            Ok(_) => {
16614                log::info!(
16615                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16616                );
16617                return None;
16618            }
16619            Err(i) => {
16620                self.find_all_references_task_sources.insert(i, head_anchor);
16621            }
16622        }
16623
16624        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16625        let workspace = self.workspace()?;
16626        let project = workspace.read(cx).project().clone();
16627        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16628        Some(cx.spawn_in(window, async move |editor, cx| {
16629            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16630                if let Ok(i) = editor
16631                    .find_all_references_task_sources
16632                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16633                {
16634                    editor.find_all_references_task_sources.remove(i);
16635                }
16636            });
16637
16638            let Some(locations) = references.await? else {
16639                return anyhow::Ok(Navigated::No);
16640            };
16641            let mut locations = cx.update(|_, cx| {
16642                locations
16643                    .into_iter()
16644                    .map(|location| {
16645                        let buffer = location.buffer.read(cx);
16646                        (location.buffer, location.range.to_point(buffer))
16647                    })
16648                    .into_group_map()
16649            })?;
16650            if locations.is_empty() {
16651                return anyhow::Ok(Navigated::No);
16652            }
16653            for ranges in locations.values_mut() {
16654                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16655                ranges.dedup();
16656            }
16657
16658            workspace.update_in(cx, |workspace, window, cx| {
16659                let target = locations
16660                    .iter()
16661                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16662                    .map(|(buffer, location)| {
16663                        buffer
16664                            .read(cx)
16665                            .text_for_range(location.clone())
16666                            .collect::<String>()
16667                    })
16668                    .filter(|text| !text.contains('\n'))
16669                    .unique()
16670                    .take(3)
16671                    .join(", ");
16672                let title = if target.is_empty() {
16673                    "References".to_owned()
16674                } else {
16675                    format!("References to {target}")
16676                };
16677                Self::open_locations_in_multibuffer(
16678                    workspace,
16679                    locations,
16680                    title,
16681                    false,
16682                    MultibufferSelectionMode::First,
16683                    window,
16684                    cx,
16685                );
16686                Navigated::Yes
16687            })
16688        }))
16689    }
16690
16691    /// Opens a multibuffer with the given project locations in it
16692    pub fn open_locations_in_multibuffer(
16693        workspace: &mut Workspace,
16694        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16695        title: String,
16696        split: bool,
16697        multibuffer_selection_mode: MultibufferSelectionMode,
16698        window: &mut Window,
16699        cx: &mut Context<Workspace>,
16700    ) {
16701        if locations.is_empty() {
16702            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16703            return;
16704        }
16705
16706        let capability = workspace.project().read(cx).capability();
16707        let mut ranges = <Vec<Range<Anchor>>>::new();
16708
16709        // a key to find existing multibuffer editors with the same set of locations
16710        // to prevent us from opening more and more multibuffer tabs for searches and the like
16711        let mut key = (title.clone(), vec![]);
16712        let excerpt_buffer = cx.new(|cx| {
16713            let key = &mut key.1;
16714            let mut multibuffer = MultiBuffer::new(capability);
16715            for (buffer, mut ranges_for_buffer) in locations {
16716                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16717                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16718                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16719                    PathKey::for_buffer(&buffer, cx),
16720                    buffer.clone(),
16721                    ranges_for_buffer,
16722                    multibuffer_context_lines(cx),
16723                    cx,
16724                );
16725                ranges.extend(new_ranges)
16726            }
16727
16728            multibuffer.with_title(title)
16729        });
16730        let existing = workspace.active_pane().update(cx, |pane, cx| {
16731            pane.items()
16732                .filter_map(|item| item.downcast::<Editor>())
16733                .find(|editor| {
16734                    editor
16735                        .read(cx)
16736                        .lookup_key
16737                        .as_ref()
16738                        .and_then(|it| {
16739                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16740                        })
16741                        .is_some_and(|it| *it == key)
16742                })
16743        });
16744        let editor = existing.unwrap_or_else(|| {
16745            cx.new(|cx| {
16746                let mut editor = Editor::for_multibuffer(
16747                    excerpt_buffer,
16748                    Some(workspace.project().clone()),
16749                    window,
16750                    cx,
16751                );
16752                editor.lookup_key = Some(Box::new(key));
16753                editor
16754            })
16755        });
16756        editor.update(cx, |editor, cx| {
16757            match multibuffer_selection_mode {
16758                MultibufferSelectionMode::First => {
16759                    if let Some(first_range) = ranges.first() {
16760                        editor.change_selections(
16761                            SelectionEffects::no_scroll(),
16762                            window,
16763                            cx,
16764                            |selections| {
16765                                selections.clear_disjoint();
16766                                selections
16767                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16768                            },
16769                        );
16770                    }
16771                    editor.highlight_background::<Self>(
16772                        &ranges,
16773                        |theme| theme.colors().editor_highlighted_line_background,
16774                        cx,
16775                    );
16776                }
16777                MultibufferSelectionMode::All => {
16778                    editor.change_selections(
16779                        SelectionEffects::no_scroll(),
16780                        window,
16781                        cx,
16782                        |selections| {
16783                            selections.clear_disjoint();
16784                            selections.select_anchor_ranges(ranges);
16785                        },
16786                    );
16787                }
16788            }
16789            editor.register_buffers_with_language_servers(cx);
16790        });
16791
16792        let item = Box::new(editor);
16793        let item_id = item.item_id();
16794
16795        if split {
16796            workspace.split_item(SplitDirection::Right, item, window, cx);
16797        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16798            let (preview_item_id, preview_item_idx) =
16799                workspace.active_pane().read_with(cx, |pane, _| {
16800                    (pane.preview_item_id(), pane.preview_item_idx())
16801                });
16802
16803            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16804
16805            if let Some(preview_item_id) = preview_item_id {
16806                workspace.active_pane().update(cx, |pane, cx| {
16807                    pane.remove_item(preview_item_id, false, false, window, cx);
16808                });
16809            }
16810        } else {
16811            workspace.add_item_to_active_pane(item, None, true, window, cx);
16812        }
16813        workspace.active_pane().update(cx, |pane, cx| {
16814            pane.set_preview_item_id(Some(item_id), cx);
16815        });
16816    }
16817
16818    pub fn rename(
16819        &mut self,
16820        _: &Rename,
16821        window: &mut Window,
16822        cx: &mut Context<Self>,
16823    ) -> Option<Task<Result<()>>> {
16824        use language::ToOffset as _;
16825
16826        let provider = self.semantics_provider.clone()?;
16827        let selection = self.selections.newest_anchor().clone();
16828        let (cursor_buffer, cursor_buffer_position) = self
16829            .buffer
16830            .read(cx)
16831            .text_anchor_for_position(selection.head(), cx)?;
16832        let (tail_buffer, cursor_buffer_position_end) = self
16833            .buffer
16834            .read(cx)
16835            .text_anchor_for_position(selection.tail(), cx)?;
16836        if tail_buffer != cursor_buffer {
16837            return None;
16838        }
16839
16840        let snapshot = cursor_buffer.read(cx).snapshot();
16841        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16842        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16843        let prepare_rename = provider
16844            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16845            .unwrap_or_else(|| Task::ready(Ok(None)));
16846        drop(snapshot);
16847
16848        Some(cx.spawn_in(window, async move |this, cx| {
16849            let rename_range = if let Some(range) = prepare_rename.await? {
16850                Some(range)
16851            } else {
16852                this.update(cx, |this, cx| {
16853                    let buffer = this.buffer.read(cx).snapshot(cx);
16854                    let mut buffer_highlights = this
16855                        .document_highlights_for_position(selection.head(), &buffer)
16856                        .filter(|highlight| {
16857                            highlight.start.excerpt_id == selection.head().excerpt_id
16858                                && highlight.end.excerpt_id == selection.head().excerpt_id
16859                        });
16860                    buffer_highlights
16861                        .next()
16862                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16863                })?
16864            };
16865            if let Some(rename_range) = rename_range {
16866                this.update_in(cx, |this, window, cx| {
16867                    let snapshot = cursor_buffer.read(cx).snapshot();
16868                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16869                    let cursor_offset_in_rename_range =
16870                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16871                    let cursor_offset_in_rename_range_end =
16872                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16873
16874                    this.take_rename(false, window, cx);
16875                    let buffer = this.buffer.read(cx).read(cx);
16876                    let cursor_offset = selection.head().to_offset(&buffer);
16877                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16878                    let rename_end = rename_start + rename_buffer_range.len();
16879                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16880                    let mut old_highlight_id = None;
16881                    let old_name: Arc<str> = buffer
16882                        .chunks(rename_start..rename_end, true)
16883                        .map(|chunk| {
16884                            if old_highlight_id.is_none() {
16885                                old_highlight_id = chunk.syntax_highlight_id;
16886                            }
16887                            chunk.text
16888                        })
16889                        .collect::<String>()
16890                        .into();
16891
16892                    drop(buffer);
16893
16894                    // Position the selection in the rename editor so that it matches the current selection.
16895                    this.show_local_selections = false;
16896                    let rename_editor = cx.new(|cx| {
16897                        let mut editor = Editor::single_line(window, cx);
16898                        editor.buffer.update(cx, |buffer, cx| {
16899                            buffer.edit([(0..0, old_name.clone())], None, cx)
16900                        });
16901                        let rename_selection_range = match cursor_offset_in_rename_range
16902                            .cmp(&cursor_offset_in_rename_range_end)
16903                        {
16904                            Ordering::Equal => {
16905                                editor.select_all(&SelectAll, window, cx);
16906                                return editor;
16907                            }
16908                            Ordering::Less => {
16909                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16910                            }
16911                            Ordering::Greater => {
16912                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16913                            }
16914                        };
16915                        if rename_selection_range.end > old_name.len() {
16916                            editor.select_all(&SelectAll, window, cx);
16917                        } else {
16918                            editor.change_selections(Default::default(), window, cx, |s| {
16919                                s.select_ranges([rename_selection_range]);
16920                            });
16921                        }
16922                        editor
16923                    });
16924                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16925                        if e == &EditorEvent::Focused {
16926                            cx.emit(EditorEvent::FocusedIn)
16927                        }
16928                    })
16929                    .detach();
16930
16931                    let write_highlights =
16932                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16933                    let read_highlights =
16934                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16935                    let ranges = write_highlights
16936                        .iter()
16937                        .flat_map(|(_, ranges)| ranges.iter())
16938                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16939                        .cloned()
16940                        .collect();
16941
16942                    this.highlight_text::<Rename>(
16943                        ranges,
16944                        HighlightStyle {
16945                            fade_out: Some(0.6),
16946                            ..Default::default()
16947                        },
16948                        cx,
16949                    );
16950                    let rename_focus_handle = rename_editor.focus_handle(cx);
16951                    window.focus(&rename_focus_handle);
16952                    let block_id = this.insert_blocks(
16953                        [BlockProperties {
16954                            style: BlockStyle::Flex,
16955                            placement: BlockPlacement::Below(range.start),
16956                            height: Some(1),
16957                            render: Arc::new({
16958                                let rename_editor = rename_editor.clone();
16959                                move |cx: &mut BlockContext| {
16960                                    let mut text_style = cx.editor_style.text.clone();
16961                                    if let Some(highlight_style) = old_highlight_id
16962                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16963                                    {
16964                                        text_style = text_style.highlight(highlight_style);
16965                                    }
16966                                    div()
16967                                        .block_mouse_except_scroll()
16968                                        .pl(cx.anchor_x)
16969                                        .child(EditorElement::new(
16970                                            &rename_editor,
16971                                            EditorStyle {
16972                                                background: cx.theme().system().transparent,
16973                                                local_player: cx.editor_style.local_player,
16974                                                text: text_style,
16975                                                scrollbar_width: cx.editor_style.scrollbar_width,
16976                                                syntax: cx.editor_style.syntax.clone(),
16977                                                status: cx.editor_style.status.clone(),
16978                                                inlay_hints_style: HighlightStyle {
16979                                                    font_weight: Some(FontWeight::BOLD),
16980                                                    ..make_inlay_hints_style(cx.app)
16981                                                },
16982                                                edit_prediction_styles: make_suggestion_styles(
16983                                                    cx.app,
16984                                                ),
16985                                                ..EditorStyle::default()
16986                                            },
16987                                        ))
16988                                        .into_any_element()
16989                                }
16990                            }),
16991                            priority: 0,
16992                        }],
16993                        Some(Autoscroll::fit()),
16994                        cx,
16995                    )[0];
16996                    this.pending_rename = Some(RenameState {
16997                        range,
16998                        old_name,
16999                        editor: rename_editor,
17000                        block_id,
17001                    });
17002                })?;
17003            }
17004
17005            Ok(())
17006        }))
17007    }
17008
17009    pub fn confirm_rename(
17010        &mut self,
17011        _: &ConfirmRename,
17012        window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) -> Option<Task<Result<()>>> {
17015        let rename = self.take_rename(false, window, cx)?;
17016        let workspace = self.workspace()?.downgrade();
17017        let (buffer, start) = self
17018            .buffer
17019            .read(cx)
17020            .text_anchor_for_position(rename.range.start, cx)?;
17021        let (end_buffer, _) = self
17022            .buffer
17023            .read(cx)
17024            .text_anchor_for_position(rename.range.end, cx)?;
17025        if buffer != end_buffer {
17026            return None;
17027        }
17028
17029        let old_name = rename.old_name;
17030        let new_name = rename.editor.read(cx).text(cx);
17031
17032        let rename = self.semantics_provider.as_ref()?.perform_rename(
17033            &buffer,
17034            start,
17035            new_name.clone(),
17036            cx,
17037        )?;
17038
17039        Some(cx.spawn_in(window, async move |editor, cx| {
17040            let project_transaction = rename.await?;
17041            Self::open_project_transaction(
17042                &editor,
17043                workspace,
17044                project_transaction,
17045                format!("Rename: {}{}", old_name, new_name),
17046                cx,
17047            )
17048            .await?;
17049
17050            editor.update(cx, |editor, cx| {
17051                editor.refresh_document_highlights(cx);
17052            })?;
17053            Ok(())
17054        }))
17055    }
17056
17057    fn take_rename(
17058        &mut self,
17059        moving_cursor: bool,
17060        window: &mut Window,
17061        cx: &mut Context<Self>,
17062    ) -> Option<RenameState> {
17063        let rename = self.pending_rename.take()?;
17064        if rename.editor.focus_handle(cx).is_focused(window) {
17065            window.focus(&self.focus_handle);
17066        }
17067
17068        self.remove_blocks(
17069            [rename.block_id].into_iter().collect(),
17070            Some(Autoscroll::fit()),
17071            cx,
17072        );
17073        self.clear_highlights::<Rename>(cx);
17074        self.show_local_selections = true;
17075
17076        if moving_cursor {
17077            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17078                editor.selections.newest::<usize>(cx).head()
17079            });
17080
17081            // Update the selection to match the position of the selection inside
17082            // the rename editor.
17083            let snapshot = self.buffer.read(cx).read(cx);
17084            let rename_range = rename.range.to_offset(&snapshot);
17085            let cursor_in_editor = snapshot
17086                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17087                .min(rename_range.end);
17088            drop(snapshot);
17089
17090            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17091                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17092            });
17093        } else {
17094            self.refresh_document_highlights(cx);
17095        }
17096
17097        Some(rename)
17098    }
17099
17100    pub fn pending_rename(&self) -> Option<&RenameState> {
17101        self.pending_rename.as_ref()
17102    }
17103
17104    fn format(
17105        &mut self,
17106        _: &Format,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) -> Option<Task<Result<()>>> {
17110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17111
17112        let project = match &self.project {
17113            Some(project) => project.clone(),
17114            None => return None,
17115        };
17116
17117        Some(self.perform_format(
17118            project,
17119            FormatTrigger::Manual,
17120            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17121            window,
17122            cx,
17123        ))
17124    }
17125
17126    fn format_selections(
17127        &mut self,
17128        _: &FormatSelections,
17129        window: &mut Window,
17130        cx: &mut Context<Self>,
17131    ) -> Option<Task<Result<()>>> {
17132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17133
17134        let project = match &self.project {
17135            Some(project) => project.clone(),
17136            None => return None,
17137        };
17138
17139        let ranges = self
17140            .selections
17141            .all_adjusted(cx)
17142            .into_iter()
17143            .map(|selection| selection.range())
17144            .collect_vec();
17145
17146        Some(self.perform_format(
17147            project,
17148            FormatTrigger::Manual,
17149            FormatTarget::Ranges(ranges),
17150            window,
17151            cx,
17152        ))
17153    }
17154
17155    fn perform_format(
17156        &mut self,
17157        project: Entity<Project>,
17158        trigger: FormatTrigger,
17159        target: FormatTarget,
17160        window: &mut Window,
17161        cx: &mut Context<Self>,
17162    ) -> Task<Result<()>> {
17163        let buffer = self.buffer.clone();
17164        let (buffers, target) = match target {
17165            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17166            FormatTarget::Ranges(selection_ranges) => {
17167                let multi_buffer = buffer.read(cx);
17168                let snapshot = multi_buffer.read(cx);
17169                let mut buffers = HashSet::default();
17170                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17171                    BTreeMap::new();
17172                for selection_range in selection_ranges {
17173                    for (buffer, buffer_range, _) in
17174                        snapshot.range_to_buffer_ranges(selection_range)
17175                    {
17176                        let buffer_id = buffer.remote_id();
17177                        let start = buffer.anchor_before(buffer_range.start);
17178                        let end = buffer.anchor_after(buffer_range.end);
17179                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17180                        buffer_id_to_ranges
17181                            .entry(buffer_id)
17182                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17183                            .or_insert_with(|| vec![start..end]);
17184                    }
17185                }
17186                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17187            }
17188        };
17189
17190        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17191        let selections_prev = transaction_id_prev
17192            .and_then(|transaction_id_prev| {
17193                // default to selections as they were after the last edit, if we have them,
17194                // instead of how they are now.
17195                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17196                // will take you back to where you made the last edit, instead of staying where you scrolled
17197                self.selection_history
17198                    .transaction(transaction_id_prev)
17199                    .map(|t| t.0.clone())
17200            })
17201            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17202
17203        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17204        let format = project.update(cx, |project, cx| {
17205            project.format(buffers, target, true, trigger, cx)
17206        });
17207
17208        cx.spawn_in(window, async move |editor, cx| {
17209            let transaction = futures::select_biased! {
17210                transaction = format.log_err().fuse() => transaction,
17211                () = timeout => {
17212                    log::warn!("timed out waiting for formatting");
17213                    None
17214                }
17215            };
17216
17217            buffer
17218                .update(cx, |buffer, cx| {
17219                    if let Some(transaction) = transaction
17220                        && !buffer.is_singleton()
17221                    {
17222                        buffer.push_transaction(&transaction.0, cx);
17223                    }
17224                    cx.notify();
17225                })
17226                .ok();
17227
17228            if let Some(transaction_id_now) =
17229                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17230            {
17231                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17232                if has_new_transaction {
17233                    _ = editor.update(cx, |editor, _| {
17234                        editor
17235                            .selection_history
17236                            .insert_transaction(transaction_id_now, selections_prev);
17237                    });
17238                }
17239            }
17240
17241            Ok(())
17242        })
17243    }
17244
17245    fn organize_imports(
17246        &mut self,
17247        _: &OrganizeImports,
17248        window: &mut Window,
17249        cx: &mut Context<Self>,
17250    ) -> Option<Task<Result<()>>> {
17251        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17252        let project = match &self.project {
17253            Some(project) => project.clone(),
17254            None => return None,
17255        };
17256        Some(self.perform_code_action_kind(
17257            project,
17258            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17259            window,
17260            cx,
17261        ))
17262    }
17263
17264    fn perform_code_action_kind(
17265        &mut self,
17266        project: Entity<Project>,
17267        kind: CodeActionKind,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270    ) -> Task<Result<()>> {
17271        let buffer = self.buffer.clone();
17272        let buffers = buffer.read(cx).all_buffers();
17273        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17274        let apply_action = project.update(cx, |project, cx| {
17275            project.apply_code_action_kind(buffers, kind, true, cx)
17276        });
17277        cx.spawn_in(window, async move |_, cx| {
17278            let transaction = futures::select_biased! {
17279                () = timeout => {
17280                    log::warn!("timed out waiting for executing code action");
17281                    None
17282                }
17283                transaction = apply_action.log_err().fuse() => transaction,
17284            };
17285            buffer
17286                .update(cx, |buffer, cx| {
17287                    // check if we need this
17288                    if let Some(transaction) = transaction
17289                        && !buffer.is_singleton()
17290                    {
17291                        buffer.push_transaction(&transaction.0, cx);
17292                    }
17293                    cx.notify();
17294                })
17295                .ok();
17296            Ok(())
17297        })
17298    }
17299
17300    pub fn restart_language_server(
17301        &mut self,
17302        _: &RestartLanguageServer,
17303        _: &mut Window,
17304        cx: &mut Context<Self>,
17305    ) {
17306        if let Some(project) = self.project.clone() {
17307            self.buffer.update(cx, |multi_buffer, cx| {
17308                project.update(cx, |project, cx| {
17309                    project.restart_language_servers_for_buffers(
17310                        multi_buffer.all_buffers().into_iter().collect(),
17311                        HashSet::default(),
17312                        cx,
17313                    );
17314                });
17315            })
17316        }
17317    }
17318
17319    pub fn stop_language_server(
17320        &mut self,
17321        _: &StopLanguageServer,
17322        _: &mut Window,
17323        cx: &mut Context<Self>,
17324    ) {
17325        if let Some(project) = self.project.clone() {
17326            self.buffer.update(cx, |multi_buffer, cx| {
17327                project.update(cx, |project, cx| {
17328                    project.stop_language_servers_for_buffers(
17329                        multi_buffer.all_buffers().into_iter().collect(),
17330                        HashSet::default(),
17331                        cx,
17332                    );
17333                    cx.emit(project::Event::RefreshInlayHints);
17334                });
17335            });
17336        }
17337    }
17338
17339    fn cancel_language_server_work(
17340        workspace: &mut Workspace,
17341        _: &actions::CancelLanguageServerWork,
17342        _: &mut Window,
17343        cx: &mut Context<Workspace>,
17344    ) {
17345        let project = workspace.project();
17346        let buffers = workspace
17347            .active_item(cx)
17348            .and_then(|item| item.act_as::<Editor>(cx))
17349            .map_or(HashSet::default(), |editor| {
17350                editor.read(cx).buffer.read(cx).all_buffers()
17351            });
17352        project.update(cx, |project, cx| {
17353            project.cancel_language_server_work_for_buffers(buffers, cx);
17354        });
17355    }
17356
17357    fn show_character_palette(
17358        &mut self,
17359        _: &ShowCharacterPalette,
17360        window: &mut Window,
17361        _: &mut Context<Self>,
17362    ) {
17363        window.show_character_palette();
17364    }
17365
17366    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17367        if !self.diagnostics_enabled() {
17368            return;
17369        }
17370
17371        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17372            let buffer = self.buffer.read(cx).snapshot(cx);
17373            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17374            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17375            let is_valid = buffer
17376                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17377                .any(|entry| {
17378                    entry.diagnostic.is_primary
17379                        && !entry.range.is_empty()
17380                        && entry.range.start == primary_range_start
17381                        && entry.diagnostic.message == active_diagnostics.active_message
17382                });
17383
17384            if !is_valid {
17385                self.dismiss_diagnostics(cx);
17386            }
17387        }
17388    }
17389
17390    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17391        match &self.active_diagnostics {
17392            ActiveDiagnostic::Group(group) => Some(group),
17393            _ => None,
17394        }
17395    }
17396
17397    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17398        if !self.diagnostics_enabled() {
17399            return;
17400        }
17401        self.dismiss_diagnostics(cx);
17402        self.active_diagnostics = ActiveDiagnostic::All;
17403    }
17404
17405    fn activate_diagnostics(
17406        &mut self,
17407        buffer_id: BufferId,
17408        diagnostic: DiagnosticEntry<usize>,
17409        window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17413            return;
17414        }
17415        self.dismiss_diagnostics(cx);
17416        let snapshot = self.snapshot(window, cx);
17417        let buffer = self.buffer.read(cx).snapshot(cx);
17418        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17419            return;
17420        };
17421
17422        let diagnostic_group = buffer
17423            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17424            .collect::<Vec<_>>();
17425
17426        let blocks =
17427            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17428
17429        let blocks = self.display_map.update(cx, |display_map, cx| {
17430            display_map.insert_blocks(blocks, cx).into_iter().collect()
17431        });
17432        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17433            active_range: buffer.anchor_before(diagnostic.range.start)
17434                ..buffer.anchor_after(diagnostic.range.end),
17435            active_message: diagnostic.diagnostic.message.clone(),
17436            group_id: diagnostic.diagnostic.group_id,
17437            blocks,
17438        });
17439        cx.notify();
17440    }
17441
17442    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17443        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17444            return;
17445        };
17446
17447        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17448        if let ActiveDiagnostic::Group(group) = prev {
17449            self.display_map.update(cx, |display_map, cx| {
17450                display_map.remove_blocks(group.blocks, cx);
17451            });
17452            cx.notify();
17453        }
17454    }
17455
17456    /// Disable inline diagnostics rendering for this editor.
17457    pub fn disable_inline_diagnostics(&mut self) {
17458        self.inline_diagnostics_enabled = false;
17459        self.inline_diagnostics_update = Task::ready(());
17460        self.inline_diagnostics.clear();
17461    }
17462
17463    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17464        self.diagnostics_enabled = false;
17465        self.dismiss_diagnostics(cx);
17466        self.inline_diagnostics_update = Task::ready(());
17467        self.inline_diagnostics.clear();
17468    }
17469
17470    pub fn disable_word_completions(&mut self) {
17471        self.word_completions_enabled = false;
17472    }
17473
17474    pub fn diagnostics_enabled(&self) -> bool {
17475        self.diagnostics_enabled && self.mode.is_full()
17476    }
17477
17478    pub fn inline_diagnostics_enabled(&self) -> bool {
17479        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17480    }
17481
17482    pub fn show_inline_diagnostics(&self) -> bool {
17483        self.show_inline_diagnostics
17484    }
17485
17486    pub fn toggle_inline_diagnostics(
17487        &mut self,
17488        _: &ToggleInlineDiagnostics,
17489        window: &mut Window,
17490        cx: &mut Context<Editor>,
17491    ) {
17492        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17493        self.refresh_inline_diagnostics(false, window, cx);
17494    }
17495
17496    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17497        self.diagnostics_max_severity = severity;
17498        self.display_map.update(cx, |display_map, _| {
17499            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17500        });
17501    }
17502
17503    pub fn toggle_diagnostics(
17504        &mut self,
17505        _: &ToggleDiagnostics,
17506        window: &mut Window,
17507        cx: &mut Context<Editor>,
17508    ) {
17509        if !self.diagnostics_enabled() {
17510            return;
17511        }
17512
17513        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17514            EditorSettings::get_global(cx)
17515                .diagnostics_max_severity
17516                .filter(|severity| severity != &DiagnosticSeverity::Off)
17517                .unwrap_or(DiagnosticSeverity::Hint)
17518        } else {
17519            DiagnosticSeverity::Off
17520        };
17521        self.set_max_diagnostics_severity(new_severity, cx);
17522        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17523            self.active_diagnostics = ActiveDiagnostic::None;
17524            self.inline_diagnostics_update = Task::ready(());
17525            self.inline_diagnostics.clear();
17526        } else {
17527            self.refresh_inline_diagnostics(false, window, cx);
17528        }
17529
17530        cx.notify();
17531    }
17532
17533    pub fn toggle_minimap(
17534        &mut self,
17535        _: &ToggleMinimap,
17536        window: &mut Window,
17537        cx: &mut Context<Editor>,
17538    ) {
17539        if self.supports_minimap(cx) {
17540            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17541        }
17542    }
17543
17544    fn refresh_inline_diagnostics(
17545        &mut self,
17546        debounce: bool,
17547        window: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) {
17550        let max_severity = ProjectSettings::get_global(cx)
17551            .diagnostics
17552            .inline
17553            .max_severity
17554            .unwrap_or(self.diagnostics_max_severity);
17555
17556        if !self.inline_diagnostics_enabled()
17557            || !self.show_inline_diagnostics
17558            || max_severity == DiagnosticSeverity::Off
17559        {
17560            self.inline_diagnostics_update = Task::ready(());
17561            self.inline_diagnostics.clear();
17562            return;
17563        }
17564
17565        let debounce_ms = ProjectSettings::get_global(cx)
17566            .diagnostics
17567            .inline
17568            .update_debounce_ms;
17569        let debounce = if debounce && debounce_ms > 0 {
17570            Some(Duration::from_millis(debounce_ms))
17571        } else {
17572            None
17573        };
17574        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17575            if let Some(debounce) = debounce {
17576                cx.background_executor().timer(debounce).await;
17577            }
17578            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17579                editor
17580                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17581                    .ok()
17582            }) else {
17583                return;
17584            };
17585
17586            let new_inline_diagnostics = cx
17587                .background_spawn(async move {
17588                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17589                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17590                        let message = diagnostic_entry
17591                            .diagnostic
17592                            .message
17593                            .split_once('\n')
17594                            .map(|(line, _)| line)
17595                            .map(SharedString::new)
17596                            .unwrap_or_else(|| {
17597                                SharedString::from(diagnostic_entry.diagnostic.message)
17598                            });
17599                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17600                        let (Ok(i) | Err(i)) = inline_diagnostics
17601                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17602                        inline_diagnostics.insert(
17603                            i,
17604                            (
17605                                start_anchor,
17606                                InlineDiagnostic {
17607                                    message,
17608                                    group_id: diagnostic_entry.diagnostic.group_id,
17609                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17610                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17611                                    severity: diagnostic_entry.diagnostic.severity,
17612                                },
17613                            ),
17614                        );
17615                    }
17616                    inline_diagnostics
17617                })
17618                .await;
17619
17620            editor
17621                .update(cx, |editor, cx| {
17622                    editor.inline_diagnostics = new_inline_diagnostics;
17623                    cx.notify();
17624                })
17625                .ok();
17626        });
17627    }
17628
17629    fn pull_diagnostics(
17630        &mut self,
17631        buffer_id: Option<BufferId>,
17632        window: &Window,
17633        cx: &mut Context<Self>,
17634    ) -> Option<()> {
17635        if !self.mode().is_full() {
17636            return None;
17637        }
17638        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17639            .diagnostics
17640            .lsp_pull_diagnostics;
17641        if !pull_diagnostics_settings.enabled {
17642            return None;
17643        }
17644        let project = self.project()?.downgrade();
17645        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17646        let mut buffers = self.buffer.read(cx).all_buffers();
17647        if let Some(buffer_id) = buffer_id {
17648            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17649        }
17650
17651        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17652            cx.background_executor().timer(debounce).await;
17653
17654            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17655                buffers
17656                    .into_iter()
17657                    .filter_map(|buffer| {
17658                        project
17659                            .update(cx, |project, cx| {
17660                                project.lsp_store().update(cx, |lsp_store, cx| {
17661                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17662                                })
17663                            })
17664                            .ok()
17665                    })
17666                    .collect::<FuturesUnordered<_>>()
17667            }) else {
17668                return;
17669            };
17670
17671            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17672                match pull_task {
17673                    Ok(()) => {
17674                        if editor
17675                            .update_in(cx, |editor, window, cx| {
17676                                editor.update_diagnostics_state(window, cx);
17677                            })
17678                            .is_err()
17679                        {
17680                            return;
17681                        }
17682                    }
17683                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17684                }
17685            }
17686        });
17687
17688        Some(())
17689    }
17690
17691    pub fn set_selections_from_remote(
17692        &mut self,
17693        selections: Vec<Selection<Anchor>>,
17694        pending_selection: Option<Selection<Anchor>>,
17695        window: &mut Window,
17696        cx: &mut Context<Self>,
17697    ) {
17698        let old_cursor_position = self.selections.newest_anchor().head();
17699        self.selections.change_with(cx, |s| {
17700            s.select_anchors(selections);
17701            if let Some(pending_selection) = pending_selection {
17702                s.set_pending(pending_selection, SelectMode::Character);
17703            } else {
17704                s.clear_pending();
17705            }
17706        });
17707        self.selections_did_change(
17708            false,
17709            &old_cursor_position,
17710            SelectionEffects::default(),
17711            window,
17712            cx,
17713        );
17714    }
17715
17716    pub fn transact(
17717        &mut self,
17718        window: &mut Window,
17719        cx: &mut Context<Self>,
17720        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17721    ) -> Option<TransactionId> {
17722        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17723            this.start_transaction_at(Instant::now(), window, cx);
17724            update(this, window, cx);
17725            this.end_transaction_at(Instant::now(), cx)
17726        })
17727    }
17728
17729    pub fn start_transaction_at(
17730        &mut self,
17731        now: Instant,
17732        window: &mut Window,
17733        cx: &mut Context<Self>,
17734    ) -> Option<TransactionId> {
17735        self.end_selection(window, cx);
17736        if let Some(tx_id) = self
17737            .buffer
17738            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17739        {
17740            self.selection_history
17741                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17742            cx.emit(EditorEvent::TransactionBegun {
17743                transaction_id: tx_id,
17744            });
17745            Some(tx_id)
17746        } else {
17747            None
17748        }
17749    }
17750
17751    pub fn end_transaction_at(
17752        &mut self,
17753        now: Instant,
17754        cx: &mut Context<Self>,
17755    ) -> Option<TransactionId> {
17756        if let Some(transaction_id) = self
17757            .buffer
17758            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17759        {
17760            if let Some((_, end_selections)) =
17761                self.selection_history.transaction_mut(transaction_id)
17762            {
17763                *end_selections = Some(self.selections.disjoint_anchors_arc());
17764            } else {
17765                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17766            }
17767
17768            cx.emit(EditorEvent::Edited { transaction_id });
17769            Some(transaction_id)
17770        } else {
17771            None
17772        }
17773    }
17774
17775    pub fn modify_transaction_selection_history(
17776        &mut self,
17777        transaction_id: TransactionId,
17778        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17779    ) -> bool {
17780        self.selection_history
17781            .transaction_mut(transaction_id)
17782            .map(modify)
17783            .is_some()
17784    }
17785
17786    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17787        if self.selection_mark_mode {
17788            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17789                s.move_with(|_, sel| {
17790                    sel.collapse_to(sel.head(), SelectionGoal::None);
17791                });
17792            })
17793        }
17794        self.selection_mark_mode = true;
17795        cx.notify();
17796    }
17797
17798    pub fn swap_selection_ends(
17799        &mut self,
17800        _: &actions::SwapSelectionEnds,
17801        window: &mut Window,
17802        cx: &mut Context<Self>,
17803    ) {
17804        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17805            s.move_with(|_, sel| {
17806                if sel.start != sel.end {
17807                    sel.reversed = !sel.reversed
17808                }
17809            });
17810        });
17811        self.request_autoscroll(Autoscroll::newest(), cx);
17812        cx.notify();
17813    }
17814
17815    pub fn toggle_focus(
17816        workspace: &mut Workspace,
17817        _: &actions::ToggleFocus,
17818        window: &mut Window,
17819        cx: &mut Context<Workspace>,
17820    ) {
17821        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17822            return;
17823        };
17824        workspace.activate_item(&item, true, true, window, cx);
17825    }
17826
17827    pub fn toggle_fold(
17828        &mut self,
17829        _: &actions::ToggleFold,
17830        window: &mut Window,
17831        cx: &mut Context<Self>,
17832    ) {
17833        if self.is_singleton(cx) {
17834            let selection = self.selections.newest::<Point>(cx);
17835
17836            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17837            let range = if selection.is_empty() {
17838                let point = selection.head().to_display_point(&display_map);
17839                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17840                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17841                    .to_point(&display_map);
17842                start..end
17843            } else {
17844                selection.range()
17845            };
17846            if display_map.folds_in_range(range).next().is_some() {
17847                self.unfold_lines(&Default::default(), window, cx)
17848            } else {
17849                self.fold(&Default::default(), window, cx)
17850            }
17851        } else {
17852            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17853            let buffer_ids: HashSet<_> = self
17854                .selections
17855                .disjoint_anchor_ranges()
17856                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17857                .collect();
17858
17859            let should_unfold = buffer_ids
17860                .iter()
17861                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17862
17863            for buffer_id in buffer_ids {
17864                if should_unfold {
17865                    self.unfold_buffer(buffer_id, cx);
17866                } else {
17867                    self.fold_buffer(buffer_id, cx);
17868                }
17869            }
17870        }
17871    }
17872
17873    pub fn toggle_fold_recursive(
17874        &mut self,
17875        _: &actions::ToggleFoldRecursive,
17876        window: &mut Window,
17877        cx: &mut Context<Self>,
17878    ) {
17879        let selection = self.selections.newest::<Point>(cx);
17880
17881        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17882        let range = if selection.is_empty() {
17883            let point = selection.head().to_display_point(&display_map);
17884            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17885            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17886                .to_point(&display_map);
17887            start..end
17888        } else {
17889            selection.range()
17890        };
17891        if display_map.folds_in_range(range).next().is_some() {
17892            self.unfold_recursive(&Default::default(), window, cx)
17893        } else {
17894            self.fold_recursive(&Default::default(), window, cx)
17895        }
17896    }
17897
17898    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17899        if self.is_singleton(cx) {
17900            let mut to_fold = Vec::new();
17901            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17902            let selections = self.selections.all_adjusted(cx);
17903
17904            for selection in selections {
17905                let range = selection.range().sorted();
17906                let buffer_start_row = range.start.row;
17907
17908                if range.start.row != range.end.row {
17909                    let mut found = false;
17910                    let mut row = range.start.row;
17911                    while row <= range.end.row {
17912                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17913                        {
17914                            found = true;
17915                            row = crease.range().end.row + 1;
17916                            to_fold.push(crease);
17917                        } else {
17918                            row += 1
17919                        }
17920                    }
17921                    if found {
17922                        continue;
17923                    }
17924                }
17925
17926                for row in (0..=range.start.row).rev() {
17927                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17928                        && crease.range().end.row >= buffer_start_row
17929                    {
17930                        to_fold.push(crease);
17931                        if row <= range.start.row {
17932                            break;
17933                        }
17934                    }
17935                }
17936            }
17937
17938            self.fold_creases(to_fold, true, window, cx);
17939        } else {
17940            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17941            let buffer_ids = self
17942                .selections
17943                .disjoint_anchor_ranges()
17944                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17945                .collect::<HashSet<_>>();
17946            for buffer_id in buffer_ids {
17947                self.fold_buffer(buffer_id, cx);
17948            }
17949        }
17950    }
17951
17952    pub fn toggle_fold_all(
17953        &mut self,
17954        _: &actions::ToggleFoldAll,
17955        window: &mut Window,
17956        cx: &mut Context<Self>,
17957    ) {
17958        if self.buffer.read(cx).is_singleton() {
17959            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17960            let has_folds = display_map
17961                .folds_in_range(0..display_map.buffer_snapshot.len())
17962                .next()
17963                .is_some();
17964
17965            if has_folds {
17966                self.unfold_all(&actions::UnfoldAll, window, cx);
17967            } else {
17968                self.fold_all(&actions::FoldAll, window, cx);
17969            }
17970        } else {
17971            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17972            let should_unfold = buffer_ids
17973                .iter()
17974                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17975
17976            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17977                editor
17978                    .update_in(cx, |editor, _, cx| {
17979                        for buffer_id in buffer_ids {
17980                            if should_unfold {
17981                                editor.unfold_buffer(buffer_id, cx);
17982                            } else {
17983                                editor.fold_buffer(buffer_id, cx);
17984                            }
17985                        }
17986                    })
17987                    .ok();
17988            });
17989        }
17990    }
17991
17992    fn fold_at_level(
17993        &mut self,
17994        fold_at: &FoldAtLevel,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) {
17998        if !self.buffer.read(cx).is_singleton() {
17999            return;
18000        }
18001
18002        let fold_at_level = fold_at.0;
18003        let snapshot = self.buffer.read(cx).snapshot(cx);
18004        let mut to_fold = Vec::new();
18005        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18006
18007        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18008            while start_row < end_row {
18009                match self
18010                    .snapshot(window, cx)
18011                    .crease_for_buffer_row(MultiBufferRow(start_row))
18012                {
18013                    Some(crease) => {
18014                        let nested_start_row = crease.range().start.row + 1;
18015                        let nested_end_row = crease.range().end.row;
18016
18017                        if current_level < fold_at_level {
18018                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18019                        } else if current_level == fold_at_level {
18020                            to_fold.push(crease);
18021                        }
18022
18023                        start_row = nested_end_row + 1;
18024                    }
18025                    None => start_row += 1,
18026                }
18027            }
18028        }
18029
18030        self.fold_creases(to_fold, true, window, cx);
18031    }
18032
18033    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18034        if self.buffer.read(cx).is_singleton() {
18035            let mut fold_ranges = Vec::new();
18036            let snapshot = self.buffer.read(cx).snapshot(cx);
18037
18038            for row in 0..snapshot.max_row().0 {
18039                if let Some(foldable_range) = self
18040                    .snapshot(window, cx)
18041                    .crease_for_buffer_row(MultiBufferRow(row))
18042                {
18043                    fold_ranges.push(foldable_range);
18044                }
18045            }
18046
18047            self.fold_creases(fold_ranges, true, window, cx);
18048        } else {
18049            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18050                editor
18051                    .update_in(cx, |editor, _, cx| {
18052                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18053                            editor.fold_buffer(buffer_id, cx);
18054                        }
18055                    })
18056                    .ok();
18057            });
18058        }
18059    }
18060
18061    pub fn fold_function_bodies(
18062        &mut self,
18063        _: &actions::FoldFunctionBodies,
18064        window: &mut Window,
18065        cx: &mut Context<Self>,
18066    ) {
18067        let snapshot = self.buffer.read(cx).snapshot(cx);
18068
18069        let ranges = snapshot
18070            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18071            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18072            .collect::<Vec<_>>();
18073
18074        let creases = ranges
18075            .into_iter()
18076            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18077            .collect();
18078
18079        self.fold_creases(creases, true, window, cx);
18080    }
18081
18082    pub fn fold_recursive(
18083        &mut self,
18084        _: &actions::FoldRecursive,
18085        window: &mut Window,
18086        cx: &mut Context<Self>,
18087    ) {
18088        let mut to_fold = Vec::new();
18089        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18090        let selections = self.selections.all_adjusted(cx);
18091
18092        for selection in selections {
18093            let range = selection.range().sorted();
18094            let buffer_start_row = range.start.row;
18095
18096            if range.start.row != range.end.row {
18097                let mut found = false;
18098                for row in range.start.row..=range.end.row {
18099                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18100                        found = true;
18101                        to_fold.push(crease);
18102                    }
18103                }
18104                if found {
18105                    continue;
18106                }
18107            }
18108
18109            for row in (0..=range.start.row).rev() {
18110                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18111                    if crease.range().end.row >= buffer_start_row {
18112                        to_fold.push(crease);
18113                    } else {
18114                        break;
18115                    }
18116                }
18117            }
18118        }
18119
18120        self.fold_creases(to_fold, true, window, cx);
18121    }
18122
18123    pub fn fold_at(
18124        &mut self,
18125        buffer_row: MultiBufferRow,
18126        window: &mut Window,
18127        cx: &mut Context<Self>,
18128    ) {
18129        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18130
18131        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18132            let autoscroll = self
18133                .selections
18134                .all::<Point>(cx)
18135                .iter()
18136                .any(|selection| crease.range().overlaps(&selection.range()));
18137
18138            self.fold_creases(vec![crease], autoscroll, window, cx);
18139        }
18140    }
18141
18142    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18143        if self.is_singleton(cx) {
18144            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18145            let buffer = &display_map.buffer_snapshot;
18146            let selections = self.selections.all::<Point>(cx);
18147            let ranges = selections
18148                .iter()
18149                .map(|s| {
18150                    let range = s.display_range(&display_map).sorted();
18151                    let mut start = range.start.to_point(&display_map);
18152                    let mut end = range.end.to_point(&display_map);
18153                    start.column = 0;
18154                    end.column = buffer.line_len(MultiBufferRow(end.row));
18155                    start..end
18156                })
18157                .collect::<Vec<_>>();
18158
18159            self.unfold_ranges(&ranges, true, true, cx);
18160        } else {
18161            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18162            let buffer_ids = self
18163                .selections
18164                .disjoint_anchor_ranges()
18165                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18166                .collect::<HashSet<_>>();
18167            for buffer_id in buffer_ids {
18168                self.unfold_buffer(buffer_id, cx);
18169            }
18170        }
18171    }
18172
18173    pub fn unfold_recursive(
18174        &mut self,
18175        _: &UnfoldRecursive,
18176        _window: &mut Window,
18177        cx: &mut Context<Self>,
18178    ) {
18179        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18180        let selections = self.selections.all::<Point>(cx);
18181        let ranges = selections
18182            .iter()
18183            .map(|s| {
18184                let mut range = s.display_range(&display_map).sorted();
18185                *range.start.column_mut() = 0;
18186                *range.end.column_mut() = display_map.line_len(range.end.row());
18187                let start = range.start.to_point(&display_map);
18188                let end = range.end.to_point(&display_map);
18189                start..end
18190            })
18191            .collect::<Vec<_>>();
18192
18193        self.unfold_ranges(&ranges, true, true, cx);
18194    }
18195
18196    pub fn unfold_at(
18197        &mut self,
18198        buffer_row: MultiBufferRow,
18199        _window: &mut Window,
18200        cx: &mut Context<Self>,
18201    ) {
18202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18203
18204        let intersection_range = Point::new(buffer_row.0, 0)
18205            ..Point::new(
18206                buffer_row.0,
18207                display_map.buffer_snapshot.line_len(buffer_row),
18208            );
18209
18210        let autoscroll = self
18211            .selections
18212            .all::<Point>(cx)
18213            .iter()
18214            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18215
18216        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18217    }
18218
18219    pub fn unfold_all(
18220        &mut self,
18221        _: &actions::UnfoldAll,
18222        _window: &mut Window,
18223        cx: &mut Context<Self>,
18224    ) {
18225        if self.buffer.read(cx).is_singleton() {
18226            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18227            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18228        } else {
18229            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18230                editor
18231                    .update(cx, |editor, cx| {
18232                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18233                            editor.unfold_buffer(buffer_id, cx);
18234                        }
18235                    })
18236                    .ok();
18237            });
18238        }
18239    }
18240
18241    pub fn fold_selected_ranges(
18242        &mut self,
18243        _: &FoldSelectedRanges,
18244        window: &mut Window,
18245        cx: &mut Context<Self>,
18246    ) {
18247        let selections = self.selections.all_adjusted(cx);
18248        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18249        let ranges = selections
18250            .into_iter()
18251            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18252            .collect::<Vec<_>>();
18253        self.fold_creases(ranges, true, window, cx);
18254    }
18255
18256    pub fn fold_ranges<T: ToOffset + Clone>(
18257        &mut self,
18258        ranges: Vec<Range<T>>,
18259        auto_scroll: bool,
18260        window: &mut Window,
18261        cx: &mut Context<Self>,
18262    ) {
18263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18264        let ranges = ranges
18265            .into_iter()
18266            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18267            .collect::<Vec<_>>();
18268        self.fold_creases(ranges, auto_scroll, window, cx);
18269    }
18270
18271    pub fn fold_creases<T: ToOffset + Clone>(
18272        &mut self,
18273        creases: Vec<Crease<T>>,
18274        auto_scroll: bool,
18275        _window: &mut Window,
18276        cx: &mut Context<Self>,
18277    ) {
18278        if creases.is_empty() {
18279            return;
18280        }
18281
18282        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18283
18284        if auto_scroll {
18285            self.request_autoscroll(Autoscroll::fit(), cx);
18286        }
18287
18288        cx.notify();
18289
18290        self.scrollbar_marker_state.dirty = true;
18291        self.folds_did_change(cx);
18292    }
18293
18294    /// Removes any folds whose ranges intersect any of the given ranges.
18295    pub fn unfold_ranges<T: ToOffset + Clone>(
18296        &mut self,
18297        ranges: &[Range<T>],
18298        inclusive: bool,
18299        auto_scroll: bool,
18300        cx: &mut Context<Self>,
18301    ) {
18302        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18303            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18304        });
18305        self.folds_did_change(cx);
18306    }
18307
18308    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18309        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18310            return;
18311        }
18312        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18313        self.display_map.update(cx, |display_map, cx| {
18314            display_map.fold_buffers([buffer_id], cx)
18315        });
18316        cx.emit(EditorEvent::BufferFoldToggled {
18317            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18318            folded: true,
18319        });
18320        cx.notify();
18321    }
18322
18323    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18324        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18325            return;
18326        }
18327        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18328        self.display_map.update(cx, |display_map, cx| {
18329            display_map.unfold_buffers([buffer_id], cx);
18330        });
18331        cx.emit(EditorEvent::BufferFoldToggled {
18332            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18333            folded: false,
18334        });
18335        cx.notify();
18336    }
18337
18338    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18339        self.display_map.read(cx).is_buffer_folded(buffer)
18340    }
18341
18342    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18343        self.display_map.read(cx).folded_buffers()
18344    }
18345
18346    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18347        self.display_map.update(cx, |display_map, cx| {
18348            display_map.disable_header_for_buffer(buffer_id, cx);
18349        });
18350        cx.notify();
18351    }
18352
18353    /// Removes any folds with the given ranges.
18354    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18355        &mut self,
18356        ranges: &[Range<T>],
18357        type_id: TypeId,
18358        auto_scroll: bool,
18359        cx: &mut Context<Self>,
18360    ) {
18361        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18362            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18363        });
18364        self.folds_did_change(cx);
18365    }
18366
18367    fn remove_folds_with<T: ToOffset + Clone>(
18368        &mut self,
18369        ranges: &[Range<T>],
18370        auto_scroll: bool,
18371        cx: &mut Context<Self>,
18372        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18373    ) {
18374        if ranges.is_empty() {
18375            return;
18376        }
18377
18378        let mut buffers_affected = HashSet::default();
18379        let multi_buffer = self.buffer().read(cx);
18380        for range in ranges {
18381            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18382                buffers_affected.insert(buffer.read(cx).remote_id());
18383            };
18384        }
18385
18386        self.display_map.update(cx, update);
18387
18388        if auto_scroll {
18389            self.request_autoscroll(Autoscroll::fit(), cx);
18390        }
18391
18392        cx.notify();
18393        self.scrollbar_marker_state.dirty = true;
18394        self.active_indent_guides_state.dirty = true;
18395    }
18396
18397    pub fn update_renderer_widths(
18398        &mut self,
18399        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18400        cx: &mut Context<Self>,
18401    ) -> bool {
18402        self.display_map
18403            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18404    }
18405
18406    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18407        self.display_map.read(cx).fold_placeholder.clone()
18408    }
18409
18410    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18411        self.buffer.update(cx, |buffer, cx| {
18412            buffer.set_all_diff_hunks_expanded(cx);
18413        });
18414    }
18415
18416    pub fn expand_all_diff_hunks(
18417        &mut self,
18418        _: &ExpandAllDiffHunks,
18419        _window: &mut Window,
18420        cx: &mut Context<Self>,
18421    ) {
18422        self.buffer.update(cx, |buffer, cx| {
18423            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18424        });
18425    }
18426
18427    pub fn toggle_selected_diff_hunks(
18428        &mut self,
18429        _: &ToggleSelectedDiffHunks,
18430        _window: &mut Window,
18431        cx: &mut Context<Self>,
18432    ) {
18433        let ranges: Vec<_> = self
18434            .selections
18435            .disjoint_anchors()
18436            .iter()
18437            .map(|s| s.range())
18438            .collect();
18439        self.toggle_diff_hunks_in_ranges(ranges, cx);
18440    }
18441
18442    pub fn diff_hunks_in_ranges<'a>(
18443        &'a self,
18444        ranges: &'a [Range<Anchor>],
18445        buffer: &'a MultiBufferSnapshot,
18446    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18447        ranges.iter().flat_map(move |range| {
18448            let end_excerpt_id = range.end.excerpt_id;
18449            let range = range.to_point(buffer);
18450            let mut peek_end = range.end;
18451            if range.end.row < buffer.max_row().0 {
18452                peek_end = Point::new(range.end.row + 1, 0);
18453            }
18454            buffer
18455                .diff_hunks_in_range(range.start..peek_end)
18456                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18457        })
18458    }
18459
18460    pub fn has_stageable_diff_hunks_in_ranges(
18461        &self,
18462        ranges: &[Range<Anchor>],
18463        snapshot: &MultiBufferSnapshot,
18464    ) -> bool {
18465        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18466        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18467    }
18468
18469    pub fn toggle_staged_selected_diff_hunks(
18470        &mut self,
18471        _: &::git::ToggleStaged,
18472        _: &mut Window,
18473        cx: &mut Context<Self>,
18474    ) {
18475        let snapshot = self.buffer.read(cx).snapshot(cx);
18476        let ranges: Vec<_> = self
18477            .selections
18478            .disjoint_anchors()
18479            .iter()
18480            .map(|s| s.range())
18481            .collect();
18482        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18483        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18484    }
18485
18486    pub fn set_render_diff_hunk_controls(
18487        &mut self,
18488        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18489        cx: &mut Context<Self>,
18490    ) {
18491        self.render_diff_hunk_controls = render_diff_hunk_controls;
18492        cx.notify();
18493    }
18494
18495    pub fn stage_and_next(
18496        &mut self,
18497        _: &::git::StageAndNext,
18498        window: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        self.do_stage_or_unstage_and_next(true, window, cx);
18502    }
18503
18504    pub fn unstage_and_next(
18505        &mut self,
18506        _: &::git::UnstageAndNext,
18507        window: &mut Window,
18508        cx: &mut Context<Self>,
18509    ) {
18510        self.do_stage_or_unstage_and_next(false, window, cx);
18511    }
18512
18513    pub fn stage_or_unstage_diff_hunks(
18514        &mut self,
18515        stage: bool,
18516        ranges: Vec<Range<Anchor>>,
18517        cx: &mut Context<Self>,
18518    ) {
18519        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18520        cx.spawn(async move |this, cx| {
18521            task.await?;
18522            this.update(cx, |this, cx| {
18523                let snapshot = this.buffer.read(cx).snapshot(cx);
18524                let chunk_by = this
18525                    .diff_hunks_in_ranges(&ranges, &snapshot)
18526                    .chunk_by(|hunk| hunk.buffer_id);
18527                for (buffer_id, hunks) in &chunk_by {
18528                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18529                }
18530            })
18531        })
18532        .detach_and_log_err(cx);
18533    }
18534
18535    fn save_buffers_for_ranges_if_needed(
18536        &mut self,
18537        ranges: &[Range<Anchor>],
18538        cx: &mut Context<Editor>,
18539    ) -> Task<Result<()>> {
18540        let multibuffer = self.buffer.read(cx);
18541        let snapshot = multibuffer.read(cx);
18542        let buffer_ids: HashSet<_> = ranges
18543            .iter()
18544            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18545            .collect();
18546        drop(snapshot);
18547
18548        let mut buffers = HashSet::default();
18549        for buffer_id in buffer_ids {
18550            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18551                let buffer = buffer_entity.read(cx);
18552                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18553                {
18554                    buffers.insert(buffer_entity);
18555                }
18556            }
18557        }
18558
18559        if let Some(project) = &self.project {
18560            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18561        } else {
18562            Task::ready(Ok(()))
18563        }
18564    }
18565
18566    fn do_stage_or_unstage_and_next(
18567        &mut self,
18568        stage: bool,
18569        window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18573
18574        if ranges.iter().any(|range| range.start != range.end) {
18575            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18576            return;
18577        }
18578
18579        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18580        let snapshot = self.snapshot(window, cx);
18581        let position = self.selections.newest::<Point>(cx).head();
18582        let mut row = snapshot
18583            .buffer_snapshot
18584            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18585            .find(|hunk| hunk.row_range.start.0 > position.row)
18586            .map(|hunk| hunk.row_range.start);
18587
18588        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18589        // Outside of the project diff editor, wrap around to the beginning.
18590        if !all_diff_hunks_expanded {
18591            row = row.or_else(|| {
18592                snapshot
18593                    .buffer_snapshot
18594                    .diff_hunks_in_range(Point::zero()..position)
18595                    .find(|hunk| hunk.row_range.end.0 < position.row)
18596                    .map(|hunk| hunk.row_range.start)
18597            });
18598        }
18599
18600        if let Some(row) = row {
18601            let destination = Point::new(row.0, 0);
18602            let autoscroll = Autoscroll::center();
18603
18604            self.unfold_ranges(&[destination..destination], false, false, cx);
18605            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18606                s.select_ranges([destination..destination]);
18607            });
18608        }
18609    }
18610
18611    fn do_stage_or_unstage(
18612        &self,
18613        stage: bool,
18614        buffer_id: BufferId,
18615        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18616        cx: &mut App,
18617    ) -> Option<()> {
18618        let project = self.project()?;
18619        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18620        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18621        let buffer_snapshot = buffer.read(cx).snapshot();
18622        let file_exists = buffer_snapshot
18623            .file()
18624            .is_some_and(|file| file.disk_state().exists());
18625        diff.update(cx, |diff, cx| {
18626            diff.stage_or_unstage_hunks(
18627                stage,
18628                &hunks
18629                    .map(|hunk| buffer_diff::DiffHunk {
18630                        buffer_range: hunk.buffer_range,
18631                        diff_base_byte_range: hunk.diff_base_byte_range,
18632                        secondary_status: hunk.secondary_status,
18633                        range: Point::zero()..Point::zero(), // unused
18634                    })
18635                    .collect::<Vec<_>>(),
18636                &buffer_snapshot,
18637                file_exists,
18638                cx,
18639            )
18640        });
18641        None
18642    }
18643
18644    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18645        let ranges: Vec<_> = self
18646            .selections
18647            .disjoint_anchors()
18648            .iter()
18649            .map(|s| s.range())
18650            .collect();
18651        self.buffer
18652            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18653    }
18654
18655    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18656        self.buffer.update(cx, |buffer, cx| {
18657            let ranges = vec![Anchor::min()..Anchor::max()];
18658            if !buffer.all_diff_hunks_expanded()
18659                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18660            {
18661                buffer.collapse_diff_hunks(ranges, cx);
18662                true
18663            } else {
18664                false
18665            }
18666        })
18667    }
18668
18669    fn toggle_diff_hunks_in_ranges(
18670        &mut self,
18671        ranges: Vec<Range<Anchor>>,
18672        cx: &mut Context<Editor>,
18673    ) {
18674        self.buffer.update(cx, |buffer, cx| {
18675            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18676            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18677        })
18678    }
18679
18680    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18681        self.buffer.update(cx, |buffer, cx| {
18682            let snapshot = buffer.snapshot(cx);
18683            let excerpt_id = range.end.excerpt_id;
18684            let point_range = range.to_point(&snapshot);
18685            let expand = !buffer.single_hunk_is_expanded(range, cx);
18686            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18687        })
18688    }
18689
18690    pub(crate) fn apply_all_diff_hunks(
18691        &mut self,
18692        _: &ApplyAllDiffHunks,
18693        window: &mut Window,
18694        cx: &mut Context<Self>,
18695    ) {
18696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18697
18698        let buffers = self.buffer.read(cx).all_buffers();
18699        for branch_buffer in buffers {
18700            branch_buffer.update(cx, |branch_buffer, cx| {
18701                branch_buffer.merge_into_base(Vec::new(), cx);
18702            });
18703        }
18704
18705        if let Some(project) = self.project.clone() {
18706            self.save(
18707                SaveOptions {
18708                    format: true,
18709                    autosave: false,
18710                },
18711                project,
18712                window,
18713                cx,
18714            )
18715            .detach_and_log_err(cx);
18716        }
18717    }
18718
18719    pub(crate) fn apply_selected_diff_hunks(
18720        &mut self,
18721        _: &ApplyDiffHunk,
18722        window: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18726        let snapshot = self.snapshot(window, cx);
18727        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18728        let mut ranges_by_buffer = HashMap::default();
18729        self.transact(window, cx, |editor, _window, cx| {
18730            for hunk in hunks {
18731                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18732                    ranges_by_buffer
18733                        .entry(buffer.clone())
18734                        .or_insert_with(Vec::new)
18735                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18736                }
18737            }
18738
18739            for (buffer, ranges) in ranges_by_buffer {
18740                buffer.update(cx, |buffer, cx| {
18741                    buffer.merge_into_base(ranges, cx);
18742                });
18743            }
18744        });
18745
18746        if let Some(project) = self.project.clone() {
18747            self.save(
18748                SaveOptions {
18749                    format: true,
18750                    autosave: false,
18751                },
18752                project,
18753                window,
18754                cx,
18755            )
18756            .detach_and_log_err(cx);
18757        }
18758    }
18759
18760    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18761        if hovered != self.gutter_hovered {
18762            self.gutter_hovered = hovered;
18763            cx.notify();
18764        }
18765    }
18766
18767    pub fn insert_blocks(
18768        &mut self,
18769        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18770        autoscroll: Option<Autoscroll>,
18771        cx: &mut Context<Self>,
18772    ) -> Vec<CustomBlockId> {
18773        let blocks = self
18774            .display_map
18775            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18776        if let Some(autoscroll) = autoscroll {
18777            self.request_autoscroll(autoscroll, cx);
18778        }
18779        cx.notify();
18780        blocks
18781    }
18782
18783    pub fn resize_blocks(
18784        &mut self,
18785        heights: HashMap<CustomBlockId, u32>,
18786        autoscroll: Option<Autoscroll>,
18787        cx: &mut Context<Self>,
18788    ) {
18789        self.display_map
18790            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18791        if let Some(autoscroll) = autoscroll {
18792            self.request_autoscroll(autoscroll, cx);
18793        }
18794        cx.notify();
18795    }
18796
18797    pub fn replace_blocks(
18798        &mut self,
18799        renderers: HashMap<CustomBlockId, RenderBlock>,
18800        autoscroll: Option<Autoscroll>,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.display_map
18804            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18805        if let Some(autoscroll) = autoscroll {
18806            self.request_autoscroll(autoscroll, cx);
18807        }
18808        cx.notify();
18809    }
18810
18811    pub fn remove_blocks(
18812        &mut self,
18813        block_ids: HashSet<CustomBlockId>,
18814        autoscroll: Option<Autoscroll>,
18815        cx: &mut Context<Self>,
18816    ) {
18817        self.display_map.update(cx, |display_map, cx| {
18818            display_map.remove_blocks(block_ids, cx)
18819        });
18820        if let Some(autoscroll) = autoscroll {
18821            self.request_autoscroll(autoscroll, cx);
18822        }
18823        cx.notify();
18824    }
18825
18826    pub fn row_for_block(
18827        &self,
18828        block_id: CustomBlockId,
18829        cx: &mut Context<Self>,
18830    ) -> Option<DisplayRow> {
18831        self.display_map
18832            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18833    }
18834
18835    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18836        self.focused_block = Some(focused_block);
18837    }
18838
18839    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18840        self.focused_block.take()
18841    }
18842
18843    pub fn insert_creases(
18844        &mut self,
18845        creases: impl IntoIterator<Item = Crease<Anchor>>,
18846        cx: &mut Context<Self>,
18847    ) -> Vec<CreaseId> {
18848        self.display_map
18849            .update(cx, |map, cx| map.insert_creases(creases, cx))
18850    }
18851
18852    pub fn remove_creases(
18853        &mut self,
18854        ids: impl IntoIterator<Item = CreaseId>,
18855        cx: &mut Context<Self>,
18856    ) -> Vec<(CreaseId, Range<Anchor>)> {
18857        self.display_map
18858            .update(cx, |map, cx| map.remove_creases(ids, cx))
18859    }
18860
18861    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18862        self.display_map
18863            .update(cx, |map, cx| map.snapshot(cx))
18864            .longest_row()
18865    }
18866
18867    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18868        self.display_map
18869            .update(cx, |map, cx| map.snapshot(cx))
18870            .max_point()
18871    }
18872
18873    pub fn text(&self, cx: &App) -> String {
18874        self.buffer.read(cx).read(cx).text()
18875    }
18876
18877    pub fn is_empty(&self, cx: &App) -> bool {
18878        self.buffer.read(cx).read(cx).is_empty()
18879    }
18880
18881    pub fn text_option(&self, cx: &App) -> Option<String> {
18882        let text = self.text(cx);
18883        let text = text.trim();
18884
18885        if text.is_empty() {
18886            return None;
18887        }
18888
18889        Some(text.to_string())
18890    }
18891
18892    pub fn set_text(
18893        &mut self,
18894        text: impl Into<Arc<str>>,
18895        window: &mut Window,
18896        cx: &mut Context<Self>,
18897    ) {
18898        self.transact(window, cx, |this, _, cx| {
18899            this.buffer
18900                .read(cx)
18901                .as_singleton()
18902                .expect("you can only call set_text on editors for singleton buffers")
18903                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18904        });
18905    }
18906
18907    pub fn display_text(&self, cx: &mut App) -> String {
18908        self.display_map
18909            .update(cx, |map, cx| map.snapshot(cx))
18910            .text()
18911    }
18912
18913    fn create_minimap(
18914        &self,
18915        minimap_settings: MinimapSettings,
18916        window: &mut Window,
18917        cx: &mut Context<Self>,
18918    ) -> Option<Entity<Self>> {
18919        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18920            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18921    }
18922
18923    fn initialize_new_minimap(
18924        &self,
18925        minimap_settings: MinimapSettings,
18926        window: &mut Window,
18927        cx: &mut Context<Self>,
18928    ) -> Entity<Self> {
18929        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18930
18931        let mut minimap = Editor::new_internal(
18932            EditorMode::Minimap {
18933                parent: cx.weak_entity(),
18934            },
18935            self.buffer.clone(),
18936            None,
18937            Some(self.display_map.clone()),
18938            window,
18939            cx,
18940        );
18941        minimap.scroll_manager.clone_state(&self.scroll_manager);
18942        minimap.set_text_style_refinement(TextStyleRefinement {
18943            font_size: Some(MINIMAP_FONT_SIZE),
18944            font_weight: Some(MINIMAP_FONT_WEIGHT),
18945            ..Default::default()
18946        });
18947        minimap.update_minimap_configuration(minimap_settings, cx);
18948        cx.new(|_| minimap)
18949    }
18950
18951    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18952        let current_line_highlight = minimap_settings
18953            .current_line_highlight
18954            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18955        self.set_current_line_highlight(Some(current_line_highlight));
18956    }
18957
18958    pub fn minimap(&self) -> Option<&Entity<Self>> {
18959        self.minimap
18960            .as_ref()
18961            .filter(|_| self.minimap_visibility.visible())
18962    }
18963
18964    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18965        let mut wrap_guides = smallvec![];
18966
18967        if self.show_wrap_guides == Some(false) {
18968            return wrap_guides;
18969        }
18970
18971        let settings = self.buffer.read(cx).language_settings(cx);
18972        if settings.show_wrap_guides {
18973            match self.soft_wrap_mode(cx) {
18974                SoftWrap::Column(soft_wrap) => {
18975                    wrap_guides.push((soft_wrap as usize, true));
18976                }
18977                SoftWrap::Bounded(soft_wrap) => {
18978                    wrap_guides.push((soft_wrap as usize, true));
18979                }
18980                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18981            }
18982            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18983        }
18984
18985        wrap_guides
18986    }
18987
18988    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18989        let settings = self.buffer.read(cx).language_settings(cx);
18990        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18991        match mode {
18992            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18993                SoftWrap::None
18994            }
18995            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18996            language_settings::SoftWrap::PreferredLineLength => {
18997                SoftWrap::Column(settings.preferred_line_length)
18998            }
18999            language_settings::SoftWrap::Bounded => {
19000                SoftWrap::Bounded(settings.preferred_line_length)
19001            }
19002        }
19003    }
19004
19005    pub fn set_soft_wrap_mode(
19006        &mut self,
19007        mode: language_settings::SoftWrap,
19008
19009        cx: &mut Context<Self>,
19010    ) {
19011        self.soft_wrap_mode_override = Some(mode);
19012        cx.notify();
19013    }
19014
19015    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19016        self.hard_wrap = hard_wrap;
19017        cx.notify();
19018    }
19019
19020    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19021        self.text_style_refinement = Some(style);
19022    }
19023
19024    /// called by the Element so we know what style we were most recently rendered with.
19025    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19026        // We intentionally do not inform the display map about the minimap style
19027        // so that wrapping is not recalculated and stays consistent for the editor
19028        // and its linked minimap.
19029        if !self.mode.is_minimap() {
19030            let font = style.text.font();
19031            let font_size = style.text.font_size.to_pixels(window.rem_size());
19032            let display_map = self
19033                .placeholder_display_map
19034                .as_ref()
19035                .filter(|_| self.is_empty(cx))
19036                .unwrap_or(&self.display_map);
19037
19038            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19039        }
19040        self.style = Some(style);
19041    }
19042
19043    pub fn style(&self) -> Option<&EditorStyle> {
19044        self.style.as_ref()
19045    }
19046
19047    // Called by the element. This method is not designed to be called outside of the editor
19048    // element's layout code because it does not notify when rewrapping is computed synchronously.
19049    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19050        if self.is_empty(cx) {
19051            self.placeholder_display_map
19052                .as_ref()
19053                .map_or(false, |display_map| {
19054                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19055                })
19056        } else {
19057            self.display_map
19058                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19059        }
19060    }
19061
19062    pub fn set_soft_wrap(&mut self) {
19063        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19064    }
19065
19066    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19067        if self.soft_wrap_mode_override.is_some() {
19068            self.soft_wrap_mode_override.take();
19069        } else {
19070            let soft_wrap = match self.soft_wrap_mode(cx) {
19071                SoftWrap::GitDiff => return,
19072                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19073                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19074                    language_settings::SoftWrap::None
19075                }
19076            };
19077            self.soft_wrap_mode_override = Some(soft_wrap);
19078        }
19079        cx.notify();
19080    }
19081
19082    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19083        let Some(workspace) = self.workspace() else {
19084            return;
19085        };
19086        let fs = workspace.read(cx).app_state().fs.clone();
19087        let current_show = TabBarSettings::get_global(cx).show;
19088        update_settings_file(fs, cx, move |setting, _| {
19089            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19090        });
19091    }
19092
19093    pub fn toggle_indent_guides(
19094        &mut self,
19095        _: &ToggleIndentGuides,
19096        _: &mut Window,
19097        cx: &mut Context<Self>,
19098    ) {
19099        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19100            self.buffer
19101                .read(cx)
19102                .language_settings(cx)
19103                .indent_guides
19104                .enabled
19105        });
19106        self.show_indent_guides = Some(!currently_enabled);
19107        cx.notify();
19108    }
19109
19110    fn should_show_indent_guides(&self) -> Option<bool> {
19111        self.show_indent_guides
19112    }
19113
19114    pub fn toggle_line_numbers(
19115        &mut self,
19116        _: &ToggleLineNumbers,
19117        _: &mut Window,
19118        cx: &mut Context<Self>,
19119    ) {
19120        let mut editor_settings = EditorSettings::get_global(cx).clone();
19121        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19122        EditorSettings::override_global(editor_settings, cx);
19123    }
19124
19125    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19126        if let Some(show_line_numbers) = self.show_line_numbers {
19127            return show_line_numbers;
19128        }
19129        EditorSettings::get_global(cx).gutter.line_numbers
19130    }
19131
19132    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19133        self.use_relative_line_numbers
19134            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19135    }
19136
19137    pub fn toggle_relative_line_numbers(
19138        &mut self,
19139        _: &ToggleRelativeLineNumbers,
19140        _: &mut Window,
19141        cx: &mut Context<Self>,
19142    ) {
19143        let is_relative = self.should_use_relative_line_numbers(cx);
19144        self.set_relative_line_number(Some(!is_relative), cx)
19145    }
19146
19147    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19148        self.use_relative_line_numbers = is_relative;
19149        cx.notify();
19150    }
19151
19152    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19153        self.show_gutter = show_gutter;
19154        cx.notify();
19155    }
19156
19157    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19158        self.show_scrollbars = ScrollbarAxes {
19159            horizontal: show,
19160            vertical: show,
19161        };
19162        cx.notify();
19163    }
19164
19165    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19166        self.show_scrollbars.vertical = show;
19167        cx.notify();
19168    }
19169
19170    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19171        self.show_scrollbars.horizontal = show;
19172        cx.notify();
19173    }
19174
19175    pub fn set_minimap_visibility(
19176        &mut self,
19177        minimap_visibility: MinimapVisibility,
19178        window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) {
19181        if self.minimap_visibility != minimap_visibility {
19182            if minimap_visibility.visible() && self.minimap.is_none() {
19183                let minimap_settings = EditorSettings::get_global(cx).minimap;
19184                self.minimap =
19185                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19186            }
19187            self.minimap_visibility = minimap_visibility;
19188            cx.notify();
19189        }
19190    }
19191
19192    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19193        self.set_show_scrollbars(false, cx);
19194        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19195    }
19196
19197    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19198        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19199    }
19200
19201    /// Normally the text in full mode and auto height editors is padded on the
19202    /// left side by roughly half a character width for improved hit testing.
19203    ///
19204    /// Use this method to disable this for cases where this is not wanted (e.g.
19205    /// if you want to align the editor text with some other text above or below)
19206    /// or if you want to add this padding to single-line editors.
19207    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19208        self.offset_content = offset_content;
19209        cx.notify();
19210    }
19211
19212    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19213        self.show_line_numbers = Some(show_line_numbers);
19214        cx.notify();
19215    }
19216
19217    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19218        self.disable_expand_excerpt_buttons = true;
19219        cx.notify();
19220    }
19221
19222    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19223        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19224        cx.notify();
19225    }
19226
19227    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19228        self.show_code_actions = Some(show_code_actions);
19229        cx.notify();
19230    }
19231
19232    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19233        self.show_runnables = Some(show_runnables);
19234        cx.notify();
19235    }
19236
19237    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19238        self.show_breakpoints = Some(show_breakpoints);
19239        cx.notify();
19240    }
19241
19242    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19243        if self.display_map.read(cx).masked != masked {
19244            self.display_map.update(cx, |map, _| map.masked = masked);
19245        }
19246        cx.notify()
19247    }
19248
19249    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19250        self.show_wrap_guides = Some(show_wrap_guides);
19251        cx.notify();
19252    }
19253
19254    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19255        self.show_indent_guides = Some(show_indent_guides);
19256        cx.notify();
19257    }
19258
19259    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19260        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19261            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19262                && let Some(dir) = file.abs_path(cx).parent()
19263            {
19264                return Some(dir.to_owned());
19265            }
19266
19267            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19268                return Some(project_path.path.to_path_buf());
19269            }
19270        }
19271
19272        None
19273    }
19274
19275    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19276        self.active_excerpt(cx)?
19277            .1
19278            .read(cx)
19279            .file()
19280            .and_then(|f| f.as_local())
19281    }
19282
19283    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19284        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19285            let buffer = buffer.read(cx);
19286            if let Some(project_path) = buffer.project_path(cx) {
19287                let project = self.project()?.read(cx);
19288                project.absolute_path(&project_path, cx)
19289            } else {
19290                buffer
19291                    .file()
19292                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19293            }
19294        })
19295    }
19296
19297    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19298        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19299            let project_path = buffer.read(cx).project_path(cx)?;
19300            let project = self.project()?.read(cx);
19301            let entry = project.entry_for_path(&project_path, cx)?;
19302            let path = entry.path.to_path_buf();
19303            Some(path)
19304        })
19305    }
19306
19307    pub fn reveal_in_finder(
19308        &mut self,
19309        _: &RevealInFileManager,
19310        _window: &mut Window,
19311        cx: &mut Context<Self>,
19312    ) {
19313        if let Some(target) = self.target_file(cx) {
19314            cx.reveal_path(&target.abs_path(cx));
19315        }
19316    }
19317
19318    pub fn copy_path(
19319        &mut self,
19320        _: &zed_actions::workspace::CopyPath,
19321        _window: &mut Window,
19322        cx: &mut Context<Self>,
19323    ) {
19324        if let Some(path) = self.target_file_abs_path(cx)
19325            && let Some(path) = path.to_str()
19326        {
19327            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19328        } else {
19329            cx.propagate();
19330        }
19331    }
19332
19333    pub fn copy_relative_path(
19334        &mut self,
19335        _: &zed_actions::workspace::CopyRelativePath,
19336        _window: &mut Window,
19337        cx: &mut Context<Self>,
19338    ) {
19339        if let Some(path) = self.target_file_path(cx)
19340            && let Some(path) = path.to_str()
19341        {
19342            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19343        } else {
19344            cx.propagate();
19345        }
19346    }
19347
19348    /// Returns the project path for the editor's buffer, if any buffer is
19349    /// opened in the editor.
19350    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19351        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19352            buffer.read(cx).project_path(cx)
19353        } else {
19354            None
19355        }
19356    }
19357
19358    // Returns true if the editor handled a go-to-line request
19359    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19360        maybe!({
19361            let breakpoint_store = self.breakpoint_store.as_ref()?;
19362
19363            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19364            else {
19365                self.clear_row_highlights::<ActiveDebugLine>();
19366                return None;
19367            };
19368
19369            let position = active_stack_frame.position;
19370            let buffer_id = position.buffer_id?;
19371            let snapshot = self
19372                .project
19373                .as_ref()?
19374                .read(cx)
19375                .buffer_for_id(buffer_id, cx)?
19376                .read(cx)
19377                .snapshot();
19378
19379            let mut handled = false;
19380            for (id, ExcerptRange { context, .. }) in
19381                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19382            {
19383                if context.start.cmp(&position, &snapshot).is_ge()
19384                    || context.end.cmp(&position, &snapshot).is_lt()
19385                {
19386                    continue;
19387                }
19388                let snapshot = self.buffer.read(cx).snapshot(cx);
19389                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19390
19391                handled = true;
19392                self.clear_row_highlights::<ActiveDebugLine>();
19393
19394                self.go_to_line::<ActiveDebugLine>(
19395                    multibuffer_anchor,
19396                    Some(cx.theme().colors().editor_debugger_active_line_background),
19397                    window,
19398                    cx,
19399                );
19400
19401                cx.notify();
19402            }
19403
19404            handled.then_some(())
19405        })
19406        .is_some()
19407    }
19408
19409    pub fn copy_file_name_without_extension(
19410        &mut self,
19411        _: &CopyFileNameWithoutExtension,
19412        _: &mut Window,
19413        cx: &mut Context<Self>,
19414    ) {
19415        if let Some(file) = self.target_file(cx)
19416            && let Some(file_stem) = file.path().file_stem()
19417            && let Some(name) = file_stem.to_str()
19418        {
19419            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19420        }
19421    }
19422
19423    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19424        if let Some(file) = self.target_file(cx)
19425            && let Some(file_name) = file.path().file_name()
19426            && let Some(name) = file_name.to_str()
19427        {
19428            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19429        }
19430    }
19431
19432    pub fn toggle_git_blame(
19433        &mut self,
19434        _: &::git::Blame,
19435        window: &mut Window,
19436        cx: &mut Context<Self>,
19437    ) {
19438        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19439
19440        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19441            self.start_git_blame(true, window, cx);
19442        }
19443
19444        cx.notify();
19445    }
19446
19447    pub fn toggle_git_blame_inline(
19448        &mut self,
19449        _: &ToggleGitBlameInline,
19450        window: &mut Window,
19451        cx: &mut Context<Self>,
19452    ) {
19453        self.toggle_git_blame_inline_internal(true, window, cx);
19454        cx.notify();
19455    }
19456
19457    pub fn open_git_blame_commit(
19458        &mut self,
19459        _: &OpenGitBlameCommit,
19460        window: &mut Window,
19461        cx: &mut Context<Self>,
19462    ) {
19463        self.open_git_blame_commit_internal(window, cx);
19464    }
19465
19466    fn open_git_blame_commit_internal(
19467        &mut self,
19468        window: &mut Window,
19469        cx: &mut Context<Self>,
19470    ) -> Option<()> {
19471        let blame = self.blame.as_ref()?;
19472        let snapshot = self.snapshot(window, cx);
19473        let cursor = self.selections.newest::<Point>(cx).head();
19474        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19475        let (_, blame_entry) = blame
19476            .update(cx, |blame, cx| {
19477                blame
19478                    .blame_for_rows(
19479                        &[RowInfo {
19480                            buffer_id: Some(buffer.remote_id()),
19481                            buffer_row: Some(point.row),
19482                            ..Default::default()
19483                        }],
19484                        cx,
19485                    )
19486                    .next()
19487            })
19488            .flatten()?;
19489        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19490        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19491        let workspace = self.workspace()?.downgrade();
19492        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19493        None
19494    }
19495
19496    pub fn git_blame_inline_enabled(&self) -> bool {
19497        self.git_blame_inline_enabled
19498    }
19499
19500    pub fn toggle_selection_menu(
19501        &mut self,
19502        _: &ToggleSelectionMenu,
19503        _: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        self.show_selection_menu = self
19507            .show_selection_menu
19508            .map(|show_selections_menu| !show_selections_menu)
19509            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19510
19511        cx.notify();
19512    }
19513
19514    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19515        self.show_selection_menu
19516            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19517    }
19518
19519    fn start_git_blame(
19520        &mut self,
19521        user_triggered: bool,
19522        window: &mut Window,
19523        cx: &mut Context<Self>,
19524    ) {
19525        if let Some(project) = self.project() {
19526            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19527                && buffer.read(cx).file().is_none()
19528            {
19529                return;
19530            }
19531
19532            let focused = self.focus_handle(cx).contains_focused(window, cx);
19533
19534            let project = project.clone();
19535            let blame = cx
19536                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19537            self.blame_subscription =
19538                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19539            self.blame = Some(blame);
19540        }
19541    }
19542
19543    fn toggle_git_blame_inline_internal(
19544        &mut self,
19545        user_triggered: bool,
19546        window: &mut Window,
19547        cx: &mut Context<Self>,
19548    ) {
19549        if self.git_blame_inline_enabled {
19550            self.git_blame_inline_enabled = false;
19551            self.show_git_blame_inline = false;
19552            self.show_git_blame_inline_delay_task.take();
19553        } else {
19554            self.git_blame_inline_enabled = true;
19555            self.start_git_blame_inline(user_triggered, window, cx);
19556        }
19557
19558        cx.notify();
19559    }
19560
19561    fn start_git_blame_inline(
19562        &mut self,
19563        user_triggered: bool,
19564        window: &mut Window,
19565        cx: &mut Context<Self>,
19566    ) {
19567        self.start_git_blame(user_triggered, window, cx);
19568
19569        if ProjectSettings::get_global(cx)
19570            .git
19571            .inline_blame_delay()
19572            .is_some()
19573        {
19574            self.start_inline_blame_timer(window, cx);
19575        } else {
19576            self.show_git_blame_inline = true
19577        }
19578    }
19579
19580    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19581        self.blame.as_ref()
19582    }
19583
19584    pub fn show_git_blame_gutter(&self) -> bool {
19585        self.show_git_blame_gutter
19586    }
19587
19588    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19589        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19590    }
19591
19592    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19593        self.show_git_blame_inline
19594            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19595            && !self.newest_selection_head_on_empty_line(cx)
19596            && self.has_blame_entries(cx)
19597    }
19598
19599    fn has_blame_entries(&self, cx: &App) -> bool {
19600        self.blame()
19601            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19602    }
19603
19604    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19605        let cursor_anchor = self.selections.newest_anchor().head();
19606
19607        let snapshot = self.buffer.read(cx).snapshot(cx);
19608        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19609
19610        snapshot.line_len(buffer_row) == 0
19611    }
19612
19613    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19614        let buffer_and_selection = maybe!({
19615            let selection = self.selections.newest::<Point>(cx);
19616            let selection_range = selection.range();
19617
19618            let multi_buffer = self.buffer().read(cx);
19619            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19620            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19621
19622            let (buffer, range, _) = if selection.reversed {
19623                buffer_ranges.first()
19624            } else {
19625                buffer_ranges.last()
19626            }?;
19627
19628            let selection = text::ToPoint::to_point(&range.start, buffer).row
19629                ..text::ToPoint::to_point(&range.end, buffer).row;
19630            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19631        });
19632
19633        let Some((buffer, selection)) = buffer_and_selection else {
19634            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19635        };
19636
19637        let Some(project) = self.project() else {
19638            return Task::ready(Err(anyhow!("editor does not have project")));
19639        };
19640
19641        project.update(cx, |project, cx| {
19642            project.get_permalink_to_line(&buffer, selection, cx)
19643        })
19644    }
19645
19646    pub fn copy_permalink_to_line(
19647        &mut self,
19648        _: &CopyPermalinkToLine,
19649        window: &mut Window,
19650        cx: &mut Context<Self>,
19651    ) {
19652        let permalink_task = self.get_permalink_to_line(cx);
19653        let workspace = self.workspace();
19654
19655        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19656            Ok(permalink) => {
19657                cx.update(|_, cx| {
19658                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19659                })
19660                .ok();
19661            }
19662            Err(err) => {
19663                let message = format!("Failed to copy permalink: {err}");
19664
19665                anyhow::Result::<()>::Err(err).log_err();
19666
19667                if let Some(workspace) = workspace {
19668                    workspace
19669                        .update_in(cx, |workspace, _, cx| {
19670                            struct CopyPermalinkToLine;
19671
19672                            workspace.show_toast(
19673                                Toast::new(
19674                                    NotificationId::unique::<CopyPermalinkToLine>(),
19675                                    message,
19676                                ),
19677                                cx,
19678                            )
19679                        })
19680                        .ok();
19681                }
19682            }
19683        })
19684        .detach();
19685    }
19686
19687    pub fn copy_file_location(
19688        &mut self,
19689        _: &CopyFileLocation,
19690        _: &mut Window,
19691        cx: &mut Context<Self>,
19692    ) {
19693        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19694        if let Some(file) = self.target_file(cx)
19695            && let Some(path) = file.path().to_str()
19696        {
19697            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19698        }
19699    }
19700
19701    pub fn open_permalink_to_line(
19702        &mut self,
19703        _: &OpenPermalinkToLine,
19704        window: &mut Window,
19705        cx: &mut Context<Self>,
19706    ) {
19707        let permalink_task = self.get_permalink_to_line(cx);
19708        let workspace = self.workspace();
19709
19710        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19711            Ok(permalink) => {
19712                cx.update(|_, cx| {
19713                    cx.open_url(permalink.as_ref());
19714                })
19715                .ok();
19716            }
19717            Err(err) => {
19718                let message = format!("Failed to open permalink: {err}");
19719
19720                anyhow::Result::<()>::Err(err).log_err();
19721
19722                if let Some(workspace) = workspace {
19723                    workspace
19724                        .update(cx, |workspace, cx| {
19725                            struct OpenPermalinkToLine;
19726
19727                            workspace.show_toast(
19728                                Toast::new(
19729                                    NotificationId::unique::<OpenPermalinkToLine>(),
19730                                    message,
19731                                ),
19732                                cx,
19733                            )
19734                        })
19735                        .ok();
19736                }
19737            }
19738        })
19739        .detach();
19740    }
19741
19742    pub fn insert_uuid_v4(
19743        &mut self,
19744        _: &InsertUuidV4,
19745        window: &mut Window,
19746        cx: &mut Context<Self>,
19747    ) {
19748        self.insert_uuid(UuidVersion::V4, window, cx);
19749    }
19750
19751    pub fn insert_uuid_v7(
19752        &mut self,
19753        _: &InsertUuidV7,
19754        window: &mut Window,
19755        cx: &mut Context<Self>,
19756    ) {
19757        self.insert_uuid(UuidVersion::V7, window, cx);
19758    }
19759
19760    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19762        self.transact(window, cx, |this, window, cx| {
19763            let edits = this
19764                .selections
19765                .all::<Point>(cx)
19766                .into_iter()
19767                .map(|selection| {
19768                    let uuid = match version {
19769                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19770                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19771                    };
19772
19773                    (selection.range(), uuid.to_string())
19774                });
19775            this.edit(edits, cx);
19776            this.refresh_edit_prediction(true, false, window, cx);
19777        });
19778    }
19779
19780    pub fn open_selections_in_multibuffer(
19781        &mut self,
19782        _: &OpenSelectionsInMultibuffer,
19783        window: &mut Window,
19784        cx: &mut Context<Self>,
19785    ) {
19786        let multibuffer = self.buffer.read(cx);
19787
19788        let Some(buffer) = multibuffer.as_singleton() else {
19789            return;
19790        };
19791
19792        let Some(workspace) = self.workspace() else {
19793            return;
19794        };
19795
19796        let title = multibuffer.title(cx).to_string();
19797
19798        let locations = self
19799            .selections
19800            .all_anchors(cx)
19801            .iter()
19802            .map(|selection| {
19803                (
19804                    buffer.clone(),
19805                    (selection.start.text_anchor..selection.end.text_anchor)
19806                        .to_point(buffer.read(cx)),
19807                )
19808            })
19809            .into_group_map();
19810
19811        cx.spawn_in(window, async move |_, cx| {
19812            workspace.update_in(cx, |workspace, window, cx| {
19813                Self::open_locations_in_multibuffer(
19814                    workspace,
19815                    locations,
19816                    format!("Selections for '{title}'"),
19817                    false,
19818                    MultibufferSelectionMode::All,
19819                    window,
19820                    cx,
19821                );
19822            })
19823        })
19824        .detach();
19825    }
19826
19827    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19828    /// last highlight added will be used.
19829    ///
19830    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19831    pub fn highlight_rows<T: 'static>(
19832        &mut self,
19833        range: Range<Anchor>,
19834        color: Hsla,
19835        options: RowHighlightOptions,
19836        cx: &mut Context<Self>,
19837    ) {
19838        let snapshot = self.buffer().read(cx).snapshot(cx);
19839        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19840        let ix = row_highlights.binary_search_by(|highlight| {
19841            Ordering::Equal
19842                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19843                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19844        });
19845
19846        if let Err(mut ix) = ix {
19847            let index = post_inc(&mut self.highlight_order);
19848
19849            // If this range intersects with the preceding highlight, then merge it with
19850            // the preceding highlight. Otherwise insert a new highlight.
19851            let mut merged = false;
19852            if ix > 0 {
19853                let prev_highlight = &mut row_highlights[ix - 1];
19854                if prev_highlight
19855                    .range
19856                    .end
19857                    .cmp(&range.start, &snapshot)
19858                    .is_ge()
19859                {
19860                    ix -= 1;
19861                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19862                        prev_highlight.range.end = range.end;
19863                    }
19864                    merged = true;
19865                    prev_highlight.index = index;
19866                    prev_highlight.color = color;
19867                    prev_highlight.options = options;
19868                }
19869            }
19870
19871            if !merged {
19872                row_highlights.insert(
19873                    ix,
19874                    RowHighlight {
19875                        range,
19876                        index,
19877                        color,
19878                        options,
19879                        type_id: TypeId::of::<T>(),
19880                    },
19881                );
19882            }
19883
19884            // If any of the following highlights intersect with this one, merge them.
19885            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19886                let highlight = &row_highlights[ix];
19887                if next_highlight
19888                    .range
19889                    .start
19890                    .cmp(&highlight.range.end, &snapshot)
19891                    .is_le()
19892                {
19893                    if next_highlight
19894                        .range
19895                        .end
19896                        .cmp(&highlight.range.end, &snapshot)
19897                        .is_gt()
19898                    {
19899                        row_highlights[ix].range.end = next_highlight.range.end;
19900                    }
19901                    row_highlights.remove(ix + 1);
19902                } else {
19903                    break;
19904                }
19905            }
19906        }
19907    }
19908
19909    /// Remove any highlighted row ranges of the given type that intersect the
19910    /// given ranges.
19911    pub fn remove_highlighted_rows<T: 'static>(
19912        &mut self,
19913        ranges_to_remove: Vec<Range<Anchor>>,
19914        cx: &mut Context<Self>,
19915    ) {
19916        let snapshot = self.buffer().read(cx).snapshot(cx);
19917        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19918        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19919        row_highlights.retain(|highlight| {
19920            while let Some(range_to_remove) = ranges_to_remove.peek() {
19921                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19922                    Ordering::Less | Ordering::Equal => {
19923                        ranges_to_remove.next();
19924                    }
19925                    Ordering::Greater => {
19926                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19927                            Ordering::Less | Ordering::Equal => {
19928                                return false;
19929                            }
19930                            Ordering::Greater => break,
19931                        }
19932                    }
19933                }
19934            }
19935
19936            true
19937        })
19938    }
19939
19940    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19941    pub fn clear_row_highlights<T: 'static>(&mut self) {
19942        self.highlighted_rows.remove(&TypeId::of::<T>());
19943    }
19944
19945    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19946    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19947        self.highlighted_rows
19948            .get(&TypeId::of::<T>())
19949            .map_or(&[] as &[_], |vec| vec.as_slice())
19950            .iter()
19951            .map(|highlight| (highlight.range.clone(), highlight.color))
19952    }
19953
19954    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19955    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19956    /// Allows to ignore certain kinds of highlights.
19957    pub fn highlighted_display_rows(
19958        &self,
19959        window: &mut Window,
19960        cx: &mut App,
19961    ) -> BTreeMap<DisplayRow, LineHighlight> {
19962        let snapshot = self.snapshot(window, cx);
19963        let mut used_highlight_orders = HashMap::default();
19964        self.highlighted_rows
19965            .iter()
19966            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19967            .fold(
19968                BTreeMap::<DisplayRow, LineHighlight>::new(),
19969                |mut unique_rows, highlight| {
19970                    let start = highlight.range.start.to_display_point(&snapshot);
19971                    let end = highlight.range.end.to_display_point(&snapshot);
19972                    let start_row = start.row().0;
19973                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19974                        && end.column() == 0
19975                    {
19976                        end.row().0.saturating_sub(1)
19977                    } else {
19978                        end.row().0
19979                    };
19980                    for row in start_row..=end_row {
19981                        let used_index =
19982                            used_highlight_orders.entry(row).or_insert(highlight.index);
19983                        if highlight.index >= *used_index {
19984                            *used_index = highlight.index;
19985                            unique_rows.insert(
19986                                DisplayRow(row),
19987                                LineHighlight {
19988                                    include_gutter: highlight.options.include_gutter,
19989                                    border: None,
19990                                    background: highlight.color.into(),
19991                                    type_id: Some(highlight.type_id),
19992                                },
19993                            );
19994                        }
19995                    }
19996                    unique_rows
19997                },
19998            )
19999    }
20000
20001    pub fn highlighted_display_row_for_autoscroll(
20002        &self,
20003        snapshot: &DisplaySnapshot,
20004    ) -> Option<DisplayRow> {
20005        self.highlighted_rows
20006            .values()
20007            .flat_map(|highlighted_rows| highlighted_rows.iter())
20008            .filter_map(|highlight| {
20009                if highlight.options.autoscroll {
20010                    Some(highlight.range.start.to_display_point(snapshot).row())
20011                } else {
20012                    None
20013                }
20014            })
20015            .min()
20016    }
20017
20018    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20019        self.highlight_background::<SearchWithinRange>(
20020            ranges,
20021            |colors| colors.colors().editor_document_highlight_read_background,
20022            cx,
20023        )
20024    }
20025
20026    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20027        self.breadcrumb_header = Some(new_header);
20028    }
20029
20030    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20031        self.clear_background_highlights::<SearchWithinRange>(cx);
20032    }
20033
20034    pub fn highlight_background<T: 'static>(
20035        &mut self,
20036        ranges: &[Range<Anchor>],
20037        color_fetcher: fn(&Theme) -> Hsla,
20038        cx: &mut Context<Self>,
20039    ) {
20040        self.background_highlights.insert(
20041            HighlightKey::Type(TypeId::of::<T>()),
20042            (color_fetcher, Arc::from(ranges)),
20043        );
20044        self.scrollbar_marker_state.dirty = true;
20045        cx.notify();
20046    }
20047
20048    pub fn highlight_background_key<T: 'static>(
20049        &mut self,
20050        key: usize,
20051        ranges: &[Range<Anchor>],
20052        color_fetcher: fn(&Theme) -> Hsla,
20053        cx: &mut Context<Self>,
20054    ) {
20055        self.background_highlights.insert(
20056            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20057            (color_fetcher, Arc::from(ranges)),
20058        );
20059        self.scrollbar_marker_state.dirty = true;
20060        cx.notify();
20061    }
20062
20063    pub fn clear_background_highlights<T: 'static>(
20064        &mut self,
20065        cx: &mut Context<Self>,
20066    ) -> Option<BackgroundHighlight> {
20067        let text_highlights = self
20068            .background_highlights
20069            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20070        if !text_highlights.1.is_empty() {
20071            self.scrollbar_marker_state.dirty = true;
20072            cx.notify();
20073        }
20074        Some(text_highlights)
20075    }
20076
20077    pub fn highlight_gutter<T: 'static>(
20078        &mut self,
20079        ranges: impl Into<Vec<Range<Anchor>>>,
20080        color_fetcher: fn(&App) -> Hsla,
20081        cx: &mut Context<Self>,
20082    ) {
20083        self.gutter_highlights
20084            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20085        cx.notify();
20086    }
20087
20088    pub fn clear_gutter_highlights<T: 'static>(
20089        &mut self,
20090        cx: &mut Context<Self>,
20091    ) -> Option<GutterHighlight> {
20092        cx.notify();
20093        self.gutter_highlights.remove(&TypeId::of::<T>())
20094    }
20095
20096    pub fn insert_gutter_highlight<T: 'static>(
20097        &mut self,
20098        range: Range<Anchor>,
20099        color_fetcher: fn(&App) -> Hsla,
20100        cx: &mut Context<Self>,
20101    ) {
20102        let snapshot = self.buffer().read(cx).snapshot(cx);
20103        let mut highlights = self
20104            .gutter_highlights
20105            .remove(&TypeId::of::<T>())
20106            .map(|(_, highlights)| highlights)
20107            .unwrap_or_default();
20108        let ix = highlights.binary_search_by(|highlight| {
20109            Ordering::Equal
20110                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20111                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20112        });
20113        if let Err(ix) = ix {
20114            highlights.insert(ix, range);
20115        }
20116        self.gutter_highlights
20117            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20118    }
20119
20120    pub fn remove_gutter_highlights<T: 'static>(
20121        &mut self,
20122        ranges_to_remove: Vec<Range<Anchor>>,
20123        cx: &mut Context<Self>,
20124    ) {
20125        let snapshot = self.buffer().read(cx).snapshot(cx);
20126        let Some((color_fetcher, mut gutter_highlights)) =
20127            self.gutter_highlights.remove(&TypeId::of::<T>())
20128        else {
20129            return;
20130        };
20131        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20132        gutter_highlights.retain(|highlight| {
20133            while let Some(range_to_remove) = ranges_to_remove.peek() {
20134                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20135                    Ordering::Less | Ordering::Equal => {
20136                        ranges_to_remove.next();
20137                    }
20138                    Ordering::Greater => {
20139                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20140                            Ordering::Less | Ordering::Equal => {
20141                                return false;
20142                            }
20143                            Ordering::Greater => break,
20144                        }
20145                    }
20146                }
20147            }
20148
20149            true
20150        });
20151        self.gutter_highlights
20152            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20153    }
20154
20155    #[cfg(feature = "test-support")]
20156    pub fn all_text_highlights(
20157        &self,
20158        window: &mut Window,
20159        cx: &mut Context<Self>,
20160    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20161        let snapshot = self.snapshot(window, cx);
20162        self.display_map.update(cx, |display_map, _| {
20163            display_map
20164                .all_text_highlights()
20165                .map(|highlight| {
20166                    let (style, ranges) = highlight.as_ref();
20167                    (
20168                        *style,
20169                        ranges
20170                            .iter()
20171                            .map(|range| range.clone().to_display_points(&snapshot))
20172                            .collect(),
20173                    )
20174                })
20175                .collect()
20176        })
20177    }
20178
20179    #[cfg(feature = "test-support")]
20180    pub fn all_text_background_highlights(
20181        &self,
20182        window: &mut Window,
20183        cx: &mut Context<Self>,
20184    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20185        let snapshot = self.snapshot(window, cx);
20186        let buffer = &snapshot.buffer_snapshot;
20187        let start = buffer.anchor_before(0);
20188        let end = buffer.anchor_after(buffer.len());
20189        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20190    }
20191
20192    #[cfg(any(test, feature = "test-support"))]
20193    pub fn sorted_background_highlights_in_range(
20194        &self,
20195        search_range: Range<Anchor>,
20196        display_snapshot: &DisplaySnapshot,
20197        theme: &Theme,
20198    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20199        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20200        res.sort_by(|a, b| {
20201            a.0.start
20202                .cmp(&b.0.start)
20203                .then_with(|| a.0.end.cmp(&b.0.end))
20204                .then_with(|| a.1.cmp(&b.1))
20205        });
20206        res
20207    }
20208
20209    #[cfg(feature = "test-support")]
20210    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20211        let snapshot = self.buffer().read(cx).snapshot(cx);
20212
20213        let highlights = self
20214            .background_highlights
20215            .get(&HighlightKey::Type(TypeId::of::<
20216                items::BufferSearchHighlights,
20217            >()));
20218
20219        if let Some((_color, ranges)) = highlights {
20220            ranges
20221                .iter()
20222                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20223                .collect_vec()
20224        } else {
20225            vec![]
20226        }
20227    }
20228
20229    fn document_highlights_for_position<'a>(
20230        &'a self,
20231        position: Anchor,
20232        buffer: &'a MultiBufferSnapshot,
20233    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20234        let read_highlights = self
20235            .background_highlights
20236            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20237            .map(|h| &h.1);
20238        let write_highlights = self
20239            .background_highlights
20240            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20241            .map(|h| &h.1);
20242        let left_position = position.bias_left(buffer);
20243        let right_position = position.bias_right(buffer);
20244        read_highlights
20245            .into_iter()
20246            .chain(write_highlights)
20247            .flat_map(move |ranges| {
20248                let start_ix = match ranges.binary_search_by(|probe| {
20249                    let cmp = probe.end.cmp(&left_position, buffer);
20250                    if cmp.is_ge() {
20251                        Ordering::Greater
20252                    } else {
20253                        Ordering::Less
20254                    }
20255                }) {
20256                    Ok(i) | Err(i) => i,
20257                };
20258
20259                ranges[start_ix..]
20260                    .iter()
20261                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20262            })
20263    }
20264
20265    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20266        self.background_highlights
20267            .get(&HighlightKey::Type(TypeId::of::<T>()))
20268            .is_some_and(|(_, highlights)| !highlights.is_empty())
20269    }
20270
20271    /// Returns all background highlights for a given range.
20272    ///
20273    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20274    pub fn background_highlights_in_range(
20275        &self,
20276        search_range: Range<Anchor>,
20277        display_snapshot: &DisplaySnapshot,
20278        theme: &Theme,
20279    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20280        let mut results = Vec::new();
20281        for (color_fetcher, ranges) in self.background_highlights.values() {
20282            let color = color_fetcher(theme);
20283            let start_ix = match ranges.binary_search_by(|probe| {
20284                let cmp = probe
20285                    .end
20286                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20287                if cmp.is_gt() {
20288                    Ordering::Greater
20289                } else {
20290                    Ordering::Less
20291                }
20292            }) {
20293                Ok(i) | Err(i) => i,
20294            };
20295            for range in &ranges[start_ix..] {
20296                if range
20297                    .start
20298                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20299                    .is_ge()
20300                {
20301                    break;
20302                }
20303
20304                let start = range.start.to_display_point(display_snapshot);
20305                let end = range.end.to_display_point(display_snapshot);
20306                results.push((start..end, color))
20307            }
20308        }
20309        results
20310    }
20311
20312    pub fn gutter_highlights_in_range(
20313        &self,
20314        search_range: Range<Anchor>,
20315        display_snapshot: &DisplaySnapshot,
20316        cx: &App,
20317    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20318        let mut results = Vec::new();
20319        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20320            let color = color_fetcher(cx);
20321            let start_ix = match ranges.binary_search_by(|probe| {
20322                let cmp = probe
20323                    .end
20324                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20325                if cmp.is_gt() {
20326                    Ordering::Greater
20327                } else {
20328                    Ordering::Less
20329                }
20330            }) {
20331                Ok(i) | Err(i) => i,
20332            };
20333            for range in &ranges[start_ix..] {
20334                if range
20335                    .start
20336                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20337                    .is_ge()
20338                {
20339                    break;
20340                }
20341
20342                let start = range.start.to_display_point(display_snapshot);
20343                let end = range.end.to_display_point(display_snapshot);
20344                results.push((start..end, color))
20345            }
20346        }
20347        results
20348    }
20349
20350    /// Get the text ranges corresponding to the redaction query
20351    pub fn redacted_ranges(
20352        &self,
20353        search_range: Range<Anchor>,
20354        display_snapshot: &DisplaySnapshot,
20355        cx: &App,
20356    ) -> Vec<Range<DisplayPoint>> {
20357        display_snapshot
20358            .buffer_snapshot
20359            .redacted_ranges(search_range, |file| {
20360                if let Some(file) = file {
20361                    file.is_private()
20362                        && EditorSettings::get(
20363                            Some(SettingsLocation {
20364                                worktree_id: file.worktree_id(cx),
20365                                path: file.path().as_ref(),
20366                            }),
20367                            cx,
20368                        )
20369                        .redact_private_values
20370                } else {
20371                    false
20372                }
20373            })
20374            .map(|range| {
20375                range.start.to_display_point(display_snapshot)
20376                    ..range.end.to_display_point(display_snapshot)
20377            })
20378            .collect()
20379    }
20380
20381    pub fn highlight_text_key<T: 'static>(
20382        &mut self,
20383        key: usize,
20384        ranges: Vec<Range<Anchor>>,
20385        style: HighlightStyle,
20386        cx: &mut Context<Self>,
20387    ) {
20388        self.display_map.update(cx, |map, _| {
20389            map.highlight_text(
20390                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20391                ranges,
20392                style,
20393            );
20394        });
20395        cx.notify();
20396    }
20397
20398    pub fn highlight_text<T: 'static>(
20399        &mut self,
20400        ranges: Vec<Range<Anchor>>,
20401        style: HighlightStyle,
20402        cx: &mut Context<Self>,
20403    ) {
20404        self.display_map.update(cx, |map, _| {
20405            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20406        });
20407        cx.notify();
20408    }
20409
20410    pub(crate) fn highlight_inlays<T: 'static>(
20411        &mut self,
20412        highlights: Vec<InlayHighlight>,
20413        style: HighlightStyle,
20414        cx: &mut Context<Self>,
20415    ) {
20416        self.display_map.update(cx, |map, _| {
20417            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20418        });
20419        cx.notify();
20420    }
20421
20422    pub fn text_highlights<'a, T: 'static>(
20423        &'a self,
20424        cx: &'a App,
20425    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20426        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20427    }
20428
20429    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20430        let cleared = self
20431            .display_map
20432            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20433        if cleared {
20434            cx.notify();
20435        }
20436    }
20437
20438    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20439        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20440            && self.focus_handle.is_focused(window)
20441    }
20442
20443    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20444        self.show_cursor_when_unfocused = is_enabled;
20445        cx.notify();
20446    }
20447
20448    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20449        cx.notify();
20450    }
20451
20452    fn on_debug_session_event(
20453        &mut self,
20454        _session: Entity<Session>,
20455        event: &SessionEvent,
20456        cx: &mut Context<Self>,
20457    ) {
20458        if let SessionEvent::InvalidateInlineValue = event {
20459            self.refresh_inline_values(cx);
20460        }
20461    }
20462
20463    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20464        let Some(project) = self.project.clone() else {
20465            return;
20466        };
20467
20468        if !self.inline_value_cache.enabled {
20469            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20470            self.splice_inlays(&inlays, Vec::new(), cx);
20471            return;
20472        }
20473
20474        let current_execution_position = self
20475            .highlighted_rows
20476            .get(&TypeId::of::<ActiveDebugLine>())
20477            .and_then(|lines| lines.last().map(|line| line.range.end));
20478
20479        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20480            let inline_values = editor
20481                .update(cx, |editor, cx| {
20482                    let Some(current_execution_position) = current_execution_position else {
20483                        return Some(Task::ready(Ok(Vec::new())));
20484                    };
20485
20486                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20487                        let snapshot = buffer.snapshot(cx);
20488
20489                        let excerpt = snapshot.excerpt_containing(
20490                            current_execution_position..current_execution_position,
20491                        )?;
20492
20493                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20494                    })?;
20495
20496                    let range =
20497                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20498
20499                    project.inline_values(buffer, range, cx)
20500                })
20501                .ok()
20502                .flatten()?
20503                .await
20504                .context("refreshing debugger inlays")
20505                .log_err()?;
20506
20507            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20508
20509            for (buffer_id, inline_value) in inline_values
20510                .into_iter()
20511                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20512            {
20513                buffer_inline_values
20514                    .entry(buffer_id)
20515                    .or_default()
20516                    .push(inline_value);
20517            }
20518
20519            editor
20520                .update(cx, |editor, cx| {
20521                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20522                    let mut new_inlays = Vec::default();
20523
20524                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20525                        let buffer_id = buffer_snapshot.remote_id();
20526                        buffer_inline_values
20527                            .get(&buffer_id)
20528                            .into_iter()
20529                            .flatten()
20530                            .for_each(|hint| {
20531                                let inlay = Inlay::debugger(
20532                                    post_inc(&mut editor.next_inlay_id),
20533                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20534                                    hint.text(),
20535                                );
20536                                if !inlay.text.chars().contains(&'\n') {
20537                                    new_inlays.push(inlay);
20538                                }
20539                            });
20540                    }
20541
20542                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20543                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20544
20545                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20546                })
20547                .ok()?;
20548            Some(())
20549        });
20550    }
20551
20552    fn on_buffer_event(
20553        &mut self,
20554        multibuffer: &Entity<MultiBuffer>,
20555        event: &multi_buffer::Event,
20556        window: &mut Window,
20557        cx: &mut Context<Self>,
20558    ) {
20559        match event {
20560            multi_buffer::Event::Edited {
20561                singleton_buffer_edited,
20562                edited_buffer,
20563            } => {
20564                self.scrollbar_marker_state.dirty = true;
20565                self.active_indent_guides_state.dirty = true;
20566                self.refresh_active_diagnostics(cx);
20567                self.refresh_code_actions(window, cx);
20568                self.refresh_selected_text_highlights(true, window, cx);
20569                self.refresh_single_line_folds(window, cx);
20570                refresh_matching_bracket_highlights(self, window, cx);
20571                if self.has_active_edit_prediction() {
20572                    self.update_visible_edit_prediction(window, cx);
20573                }
20574                if let Some(project) = self.project.as_ref()
20575                    && let Some(edited_buffer) = edited_buffer
20576                {
20577                    project.update(cx, |project, cx| {
20578                        self.registered_buffers
20579                            .entry(edited_buffer.read(cx).remote_id())
20580                            .or_insert_with(|| {
20581                                project.register_buffer_with_language_servers(edited_buffer, cx)
20582                            });
20583                    });
20584                }
20585                cx.emit(EditorEvent::BufferEdited);
20586                cx.emit(SearchEvent::MatchesInvalidated);
20587
20588                if let Some(buffer) = edited_buffer {
20589                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20590                }
20591
20592                if *singleton_buffer_edited {
20593                    if let Some(buffer) = edited_buffer
20594                        && buffer.read(cx).file().is_none()
20595                    {
20596                        cx.emit(EditorEvent::TitleChanged);
20597                    }
20598                    if let Some(project) = &self.project {
20599                        #[allow(clippy::mutable_key_type)]
20600                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20601                            multibuffer
20602                                .all_buffers()
20603                                .into_iter()
20604                                .filter_map(|buffer| {
20605                                    buffer.update(cx, |buffer, cx| {
20606                                        let language = buffer.language()?;
20607                                        let should_discard = project.update(cx, |project, cx| {
20608                                            project.is_local()
20609                                                && !project.has_language_servers_for(buffer, cx)
20610                                        });
20611                                        should_discard.not().then_some(language.clone())
20612                                    })
20613                                })
20614                                .collect::<HashSet<_>>()
20615                        });
20616                        if !languages_affected.is_empty() {
20617                            self.refresh_inlay_hints(
20618                                InlayHintRefreshReason::BufferEdited(languages_affected),
20619                                cx,
20620                            );
20621                        }
20622                    }
20623                }
20624
20625                let Some(project) = &self.project else { return };
20626                let (telemetry, is_via_ssh) = {
20627                    let project = project.read(cx);
20628                    let telemetry = project.client().telemetry().clone();
20629                    let is_via_ssh = project.is_via_remote_server();
20630                    (telemetry, is_via_ssh)
20631                };
20632                refresh_linked_ranges(self, window, cx);
20633                telemetry.log_edit_event("editor", is_via_ssh);
20634            }
20635            multi_buffer::Event::ExcerptsAdded {
20636                buffer,
20637                predecessor,
20638                excerpts,
20639            } => {
20640                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20641                let buffer_id = buffer.read(cx).remote_id();
20642                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20643                    && let Some(project) = &self.project
20644                {
20645                    update_uncommitted_diff_for_buffer(
20646                        cx.entity(),
20647                        project,
20648                        [buffer.clone()],
20649                        self.buffer.clone(),
20650                        cx,
20651                    )
20652                    .detach();
20653                }
20654                if self.active_diagnostics != ActiveDiagnostic::All {
20655                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20656                }
20657                cx.emit(EditorEvent::ExcerptsAdded {
20658                    buffer: buffer.clone(),
20659                    predecessor: *predecessor,
20660                    excerpts: excerpts.clone(),
20661                });
20662                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20663            }
20664            multi_buffer::Event::ExcerptsRemoved {
20665                ids,
20666                removed_buffer_ids,
20667            } => {
20668                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20669                let buffer = self.buffer.read(cx);
20670                self.registered_buffers
20671                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20672                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20673                cx.emit(EditorEvent::ExcerptsRemoved {
20674                    ids: ids.clone(),
20675                    removed_buffer_ids: removed_buffer_ids.clone(),
20676                });
20677            }
20678            multi_buffer::Event::ExcerptsEdited {
20679                excerpt_ids,
20680                buffer_ids,
20681            } => {
20682                self.display_map.update(cx, |map, cx| {
20683                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20684                });
20685                cx.emit(EditorEvent::ExcerptsEdited {
20686                    ids: excerpt_ids.clone(),
20687                });
20688            }
20689            multi_buffer::Event::ExcerptsExpanded { ids } => {
20690                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20691                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20692            }
20693            multi_buffer::Event::Reparsed(buffer_id) => {
20694                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20695                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20696
20697                cx.emit(EditorEvent::Reparsed(*buffer_id));
20698            }
20699            multi_buffer::Event::DiffHunksToggled => {
20700                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20701            }
20702            multi_buffer::Event::LanguageChanged(buffer_id) => {
20703                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20704                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20705                cx.emit(EditorEvent::Reparsed(*buffer_id));
20706                cx.notify();
20707            }
20708            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20709            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20710            multi_buffer::Event::FileHandleChanged
20711            | multi_buffer::Event::Reloaded
20712            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20713            multi_buffer::Event::DiagnosticsUpdated => {
20714                self.update_diagnostics_state(window, cx);
20715            }
20716            _ => {}
20717        };
20718    }
20719
20720    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20721        if !self.diagnostics_enabled() {
20722            return;
20723        }
20724        self.refresh_active_diagnostics(cx);
20725        self.refresh_inline_diagnostics(true, window, cx);
20726        self.scrollbar_marker_state.dirty = true;
20727        cx.notify();
20728    }
20729
20730    pub fn start_temporary_diff_override(&mut self) {
20731        self.load_diff_task.take();
20732        self.temporary_diff_override = true;
20733    }
20734
20735    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20736        self.temporary_diff_override = false;
20737        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20738        self.buffer.update(cx, |buffer, cx| {
20739            buffer.set_all_diff_hunks_collapsed(cx);
20740        });
20741
20742        if let Some(project) = self.project.clone() {
20743            self.load_diff_task = Some(
20744                update_uncommitted_diff_for_buffer(
20745                    cx.entity(),
20746                    &project,
20747                    self.buffer.read(cx).all_buffers(),
20748                    self.buffer.clone(),
20749                    cx,
20750                )
20751                .shared(),
20752            );
20753        }
20754    }
20755
20756    fn on_display_map_changed(
20757        &mut self,
20758        _: Entity<DisplayMap>,
20759        _: &mut Window,
20760        cx: &mut Context<Self>,
20761    ) {
20762        cx.notify();
20763    }
20764
20765    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20766        if self.diagnostics_enabled() {
20767            let new_severity = EditorSettings::get_global(cx)
20768                .diagnostics_max_severity
20769                .unwrap_or(DiagnosticSeverity::Hint);
20770            self.set_max_diagnostics_severity(new_severity, cx);
20771        }
20772        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20773        self.update_edit_prediction_settings(cx);
20774        self.refresh_edit_prediction(true, false, window, cx);
20775        self.refresh_inline_values(cx);
20776        self.refresh_inlay_hints(
20777            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20778                self.selections.newest_anchor().head(),
20779                &self.buffer.read(cx).snapshot(cx),
20780                cx,
20781            )),
20782            cx,
20783        );
20784
20785        let old_cursor_shape = self.cursor_shape;
20786        let old_show_breadcrumbs = self.show_breadcrumbs;
20787
20788        {
20789            let editor_settings = EditorSettings::get_global(cx);
20790            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20791            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20792            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20793            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20794        }
20795
20796        if old_cursor_shape != self.cursor_shape {
20797            cx.emit(EditorEvent::CursorShapeChanged);
20798        }
20799
20800        if old_show_breadcrumbs != self.show_breadcrumbs {
20801            cx.emit(EditorEvent::BreadcrumbsChanged);
20802        }
20803
20804        let project_settings = ProjectSettings::get_global(cx);
20805        self.serialize_dirty_buffers =
20806            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20807
20808        if self.mode.is_full() {
20809            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20810            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20811            if self.show_inline_diagnostics != show_inline_diagnostics {
20812                self.show_inline_diagnostics = show_inline_diagnostics;
20813                self.refresh_inline_diagnostics(false, window, cx);
20814            }
20815
20816            if self.git_blame_inline_enabled != inline_blame_enabled {
20817                self.toggle_git_blame_inline_internal(false, window, cx);
20818            }
20819
20820            let minimap_settings = EditorSettings::get_global(cx).minimap;
20821            if self.minimap_visibility != MinimapVisibility::Disabled {
20822                if self.minimap_visibility.settings_visibility()
20823                    != minimap_settings.minimap_enabled()
20824                {
20825                    self.set_minimap_visibility(
20826                        MinimapVisibility::for_mode(self.mode(), cx),
20827                        window,
20828                        cx,
20829                    );
20830                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20831                    minimap_entity.update(cx, |minimap_editor, cx| {
20832                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20833                    })
20834                }
20835            }
20836        }
20837
20838        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20839            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20840        }) {
20841            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20842                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20843            }
20844            self.refresh_colors(false, None, window, cx);
20845        }
20846
20847        cx.notify();
20848    }
20849
20850    pub fn set_searchable(&mut self, searchable: bool) {
20851        self.searchable = searchable;
20852    }
20853
20854    pub fn searchable(&self) -> bool {
20855        self.searchable
20856    }
20857
20858    fn open_proposed_changes_editor(
20859        &mut self,
20860        _: &OpenProposedChangesEditor,
20861        window: &mut Window,
20862        cx: &mut Context<Self>,
20863    ) {
20864        let Some(workspace) = self.workspace() else {
20865            cx.propagate();
20866            return;
20867        };
20868
20869        let selections = self.selections.all::<usize>(cx);
20870        let multi_buffer = self.buffer.read(cx);
20871        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20872        let mut new_selections_by_buffer = HashMap::default();
20873        for selection in selections {
20874            for (buffer, range, _) in
20875                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20876            {
20877                let mut range = range.to_point(buffer);
20878                range.start.column = 0;
20879                range.end.column = buffer.line_len(range.end.row);
20880                new_selections_by_buffer
20881                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20882                    .or_insert(Vec::new())
20883                    .push(range)
20884            }
20885        }
20886
20887        let proposed_changes_buffers = new_selections_by_buffer
20888            .into_iter()
20889            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20890            .collect::<Vec<_>>();
20891        let proposed_changes_editor = cx.new(|cx| {
20892            ProposedChangesEditor::new(
20893                "Proposed changes",
20894                proposed_changes_buffers,
20895                self.project.clone(),
20896                window,
20897                cx,
20898            )
20899        });
20900
20901        window.defer(cx, move |window, cx| {
20902            workspace.update(cx, |workspace, cx| {
20903                workspace.active_pane().update(cx, |pane, cx| {
20904                    pane.add_item(
20905                        Box::new(proposed_changes_editor),
20906                        true,
20907                        true,
20908                        None,
20909                        window,
20910                        cx,
20911                    );
20912                });
20913            });
20914        });
20915    }
20916
20917    pub fn open_excerpts_in_split(
20918        &mut self,
20919        _: &OpenExcerptsSplit,
20920        window: &mut Window,
20921        cx: &mut Context<Self>,
20922    ) {
20923        self.open_excerpts_common(None, true, window, cx)
20924    }
20925
20926    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20927        self.open_excerpts_common(None, false, window, cx)
20928    }
20929
20930    fn open_excerpts_common(
20931        &mut self,
20932        jump_data: Option<JumpData>,
20933        split: bool,
20934        window: &mut Window,
20935        cx: &mut Context<Self>,
20936    ) {
20937        let Some(workspace) = self.workspace() else {
20938            cx.propagate();
20939            return;
20940        };
20941
20942        if self.buffer.read(cx).is_singleton() {
20943            cx.propagate();
20944            return;
20945        }
20946
20947        let mut new_selections_by_buffer = HashMap::default();
20948        match &jump_data {
20949            Some(JumpData::MultiBufferPoint {
20950                excerpt_id,
20951                position,
20952                anchor,
20953                line_offset_from_top,
20954            }) => {
20955                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20956                if let Some(buffer) = multi_buffer_snapshot
20957                    .buffer_id_for_excerpt(*excerpt_id)
20958                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20959                {
20960                    let buffer_snapshot = buffer.read(cx).snapshot();
20961                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20962                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20963                    } else {
20964                        buffer_snapshot.clip_point(*position, Bias::Left)
20965                    };
20966                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20967                    new_selections_by_buffer.insert(
20968                        buffer,
20969                        (
20970                            vec![jump_to_offset..jump_to_offset],
20971                            Some(*line_offset_from_top),
20972                        ),
20973                    );
20974                }
20975            }
20976            Some(JumpData::MultiBufferRow {
20977                row,
20978                line_offset_from_top,
20979            }) => {
20980                let point = MultiBufferPoint::new(row.0, 0);
20981                if let Some((buffer, buffer_point, _)) =
20982                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20983                {
20984                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20985                    new_selections_by_buffer
20986                        .entry(buffer)
20987                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20988                        .0
20989                        .push(buffer_offset..buffer_offset)
20990                }
20991            }
20992            None => {
20993                let selections = self.selections.all::<usize>(cx);
20994                let multi_buffer = self.buffer.read(cx);
20995                for selection in selections {
20996                    for (snapshot, range, _, anchor) in multi_buffer
20997                        .snapshot(cx)
20998                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20999                    {
21000                        if let Some(anchor) = anchor {
21001                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21002                            else {
21003                                continue;
21004                            };
21005                            let offset = text::ToOffset::to_offset(
21006                                &anchor.text_anchor,
21007                                &buffer_handle.read(cx).snapshot(),
21008                            );
21009                            let range = offset..offset;
21010                            new_selections_by_buffer
21011                                .entry(buffer_handle)
21012                                .or_insert((Vec::new(), None))
21013                                .0
21014                                .push(range)
21015                        } else {
21016                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21017                            else {
21018                                continue;
21019                            };
21020                            new_selections_by_buffer
21021                                .entry(buffer_handle)
21022                                .or_insert((Vec::new(), None))
21023                                .0
21024                                .push(range)
21025                        }
21026                    }
21027                }
21028            }
21029        }
21030
21031        new_selections_by_buffer
21032            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21033
21034        if new_selections_by_buffer.is_empty() {
21035            return;
21036        }
21037
21038        // We defer the pane interaction because we ourselves are a workspace item
21039        // and activating a new item causes the pane to call a method on us reentrantly,
21040        // which panics if we're on the stack.
21041        window.defer(cx, move |window, cx| {
21042            workspace.update(cx, |workspace, cx| {
21043                let pane = if split {
21044                    workspace.adjacent_pane(window, cx)
21045                } else {
21046                    workspace.active_pane().clone()
21047                };
21048
21049                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21050                    let editor = buffer
21051                        .read(cx)
21052                        .file()
21053                        .is_none()
21054                        .then(|| {
21055                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21056                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21057                            // Instead, we try to activate the existing editor in the pane first.
21058                            let (editor, pane_item_index) =
21059                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21060                                    let editor = item.downcast::<Editor>()?;
21061                                    let singleton_buffer =
21062                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21063                                    if singleton_buffer == buffer {
21064                                        Some((editor, i))
21065                                    } else {
21066                                        None
21067                                    }
21068                                })?;
21069                            pane.update(cx, |pane, cx| {
21070                                pane.activate_item(pane_item_index, true, true, window, cx)
21071                            });
21072                            Some(editor)
21073                        })
21074                        .flatten()
21075                        .unwrap_or_else(|| {
21076                            workspace.open_project_item::<Self>(
21077                                pane.clone(),
21078                                buffer,
21079                                true,
21080                                true,
21081                                window,
21082                                cx,
21083                            )
21084                        });
21085
21086                    editor.update(cx, |editor, cx| {
21087                        let autoscroll = match scroll_offset {
21088                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21089                            None => Autoscroll::newest(),
21090                        };
21091                        let nav_history = editor.nav_history.take();
21092                        editor.change_selections(
21093                            SelectionEffects::scroll(autoscroll),
21094                            window,
21095                            cx,
21096                            |s| {
21097                                s.select_ranges(ranges);
21098                            },
21099                        );
21100                        editor.nav_history = nav_history;
21101                    });
21102                }
21103            })
21104        });
21105    }
21106
21107    // For now, don't allow opening excerpts in buffers that aren't backed by
21108    // regular project files.
21109    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21110        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21111    }
21112
21113    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21114        let snapshot = self.buffer.read(cx).read(cx);
21115        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21116        Some(
21117            ranges
21118                .iter()
21119                .map(move |range| {
21120                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21121                })
21122                .collect(),
21123        )
21124    }
21125
21126    fn selection_replacement_ranges(
21127        &self,
21128        range: Range<OffsetUtf16>,
21129        cx: &mut App,
21130    ) -> Vec<Range<OffsetUtf16>> {
21131        let selections = self.selections.all::<OffsetUtf16>(cx);
21132        let newest_selection = selections
21133            .iter()
21134            .max_by_key(|selection| selection.id)
21135            .unwrap();
21136        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21137        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21138        let snapshot = self.buffer.read(cx).read(cx);
21139        selections
21140            .into_iter()
21141            .map(|mut selection| {
21142                selection.start.0 =
21143                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21144                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21145                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21146                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21147            })
21148            .collect()
21149    }
21150
21151    fn report_editor_event(
21152        &self,
21153        reported_event: ReportEditorEvent,
21154        file_extension: Option<String>,
21155        cx: &App,
21156    ) {
21157        if cfg!(any(test, feature = "test-support")) {
21158            return;
21159        }
21160
21161        let Some(project) = &self.project else { return };
21162
21163        // If None, we are in a file without an extension
21164        let file = self
21165            .buffer
21166            .read(cx)
21167            .as_singleton()
21168            .and_then(|b| b.read(cx).file());
21169        let file_extension = file_extension.or(file
21170            .as_ref()
21171            .and_then(|file| Path::new(file.file_name(cx)).extension())
21172            .and_then(|e| e.to_str())
21173            .map(|a| a.to_string()));
21174
21175        let vim_mode = vim_enabled(cx);
21176
21177        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21178        let copilot_enabled = edit_predictions_provider
21179            == language::language_settings::EditPredictionProvider::Copilot;
21180        let copilot_enabled_for_language = self
21181            .buffer
21182            .read(cx)
21183            .language_settings(cx)
21184            .show_edit_predictions;
21185
21186        let project = project.read(cx);
21187        let event_type = reported_event.event_type();
21188
21189        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21190            telemetry::event!(
21191                event_type,
21192                type = if auto_saved {"autosave"} else {"manual"},
21193                file_extension,
21194                vim_mode,
21195                copilot_enabled,
21196                copilot_enabled_for_language,
21197                edit_predictions_provider,
21198                is_via_ssh = project.is_via_remote_server(),
21199            );
21200        } else {
21201            telemetry::event!(
21202                event_type,
21203                file_extension,
21204                vim_mode,
21205                copilot_enabled,
21206                copilot_enabled_for_language,
21207                edit_predictions_provider,
21208                is_via_ssh = project.is_via_remote_server(),
21209            );
21210        };
21211    }
21212
21213    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21214    /// with each line being an array of {text, highlight} objects.
21215    fn copy_highlight_json(
21216        &mut self,
21217        _: &CopyHighlightJson,
21218        window: &mut Window,
21219        cx: &mut Context<Self>,
21220    ) {
21221        #[derive(Serialize)]
21222        struct Chunk<'a> {
21223            text: String,
21224            highlight: Option<&'a str>,
21225        }
21226
21227        let snapshot = self.buffer.read(cx).snapshot(cx);
21228        let range = self
21229            .selected_text_range(false, window, cx)
21230            .and_then(|selection| {
21231                if selection.range.is_empty() {
21232                    None
21233                } else {
21234                    Some(selection.range)
21235                }
21236            })
21237            .unwrap_or_else(|| 0..snapshot.len());
21238
21239        let chunks = snapshot.chunks(range, true);
21240        let mut lines = Vec::new();
21241        let mut line: VecDeque<Chunk> = VecDeque::new();
21242
21243        let Some(style) = self.style.as_ref() else {
21244            return;
21245        };
21246
21247        for chunk in chunks {
21248            let highlight = chunk
21249                .syntax_highlight_id
21250                .and_then(|id| id.name(&style.syntax));
21251            let mut chunk_lines = chunk.text.split('\n').peekable();
21252            while let Some(text) = chunk_lines.next() {
21253                let mut merged_with_last_token = false;
21254                if let Some(last_token) = line.back_mut()
21255                    && last_token.highlight == highlight
21256                {
21257                    last_token.text.push_str(text);
21258                    merged_with_last_token = true;
21259                }
21260
21261                if !merged_with_last_token {
21262                    line.push_back(Chunk {
21263                        text: text.into(),
21264                        highlight,
21265                    });
21266                }
21267
21268                if chunk_lines.peek().is_some() {
21269                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21270                        line.pop_front();
21271                    }
21272                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21273                        line.pop_back();
21274                    }
21275
21276                    lines.push(mem::take(&mut line));
21277                }
21278            }
21279        }
21280
21281        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21282            return;
21283        };
21284        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21285    }
21286
21287    pub fn open_context_menu(
21288        &mut self,
21289        _: &OpenContextMenu,
21290        window: &mut Window,
21291        cx: &mut Context<Self>,
21292    ) {
21293        self.request_autoscroll(Autoscroll::newest(), cx);
21294        let position = self.selections.newest_display(cx).start;
21295        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21296    }
21297
21298    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21299        &self.inlay_hint_cache
21300    }
21301
21302    pub fn replay_insert_event(
21303        &mut self,
21304        text: &str,
21305        relative_utf16_range: Option<Range<isize>>,
21306        window: &mut Window,
21307        cx: &mut Context<Self>,
21308    ) {
21309        if !self.input_enabled {
21310            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21311            return;
21312        }
21313        if let Some(relative_utf16_range) = relative_utf16_range {
21314            let selections = self.selections.all::<OffsetUtf16>(cx);
21315            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21316                let new_ranges = selections.into_iter().map(|range| {
21317                    let start = OffsetUtf16(
21318                        range
21319                            .head()
21320                            .0
21321                            .saturating_add_signed(relative_utf16_range.start),
21322                    );
21323                    let end = OffsetUtf16(
21324                        range
21325                            .head()
21326                            .0
21327                            .saturating_add_signed(relative_utf16_range.end),
21328                    );
21329                    start..end
21330                });
21331                s.select_ranges(new_ranges);
21332            });
21333        }
21334
21335        self.handle_input(text, window, cx);
21336    }
21337
21338    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21339        let Some(provider) = self.semantics_provider.as_ref() else {
21340            return false;
21341        };
21342
21343        let mut supports = false;
21344        self.buffer().update(cx, |this, cx| {
21345            this.for_each_buffer(|buffer| {
21346                supports |= provider.supports_inlay_hints(buffer, cx);
21347            });
21348        });
21349
21350        supports
21351    }
21352
21353    pub fn is_focused(&self, window: &Window) -> bool {
21354        self.focus_handle.is_focused(window)
21355    }
21356
21357    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21358        cx.emit(EditorEvent::Focused);
21359
21360        if let Some(descendant) = self
21361            .last_focused_descendant
21362            .take()
21363            .and_then(|descendant| descendant.upgrade())
21364        {
21365            window.focus(&descendant);
21366        } else {
21367            if let Some(blame) = self.blame.as_ref() {
21368                blame.update(cx, GitBlame::focus)
21369            }
21370
21371            self.blink_manager.update(cx, BlinkManager::enable);
21372            self.show_cursor_names(window, cx);
21373            self.buffer.update(cx, |buffer, cx| {
21374                buffer.finalize_last_transaction(cx);
21375                if self.leader_id.is_none() {
21376                    buffer.set_active_selections(
21377                        &self.selections.disjoint_anchors_arc(),
21378                        self.selections.line_mode,
21379                        self.cursor_shape,
21380                        cx,
21381                    );
21382                }
21383            });
21384        }
21385    }
21386
21387    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21388        cx.emit(EditorEvent::FocusedIn)
21389    }
21390
21391    fn handle_focus_out(
21392        &mut self,
21393        event: FocusOutEvent,
21394        _window: &mut Window,
21395        cx: &mut Context<Self>,
21396    ) {
21397        if event.blurred != self.focus_handle {
21398            self.last_focused_descendant = Some(event.blurred);
21399        }
21400        self.selection_drag_state = SelectionDragState::None;
21401        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21402    }
21403
21404    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21405        self.blink_manager.update(cx, BlinkManager::disable);
21406        self.buffer
21407            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21408
21409        if let Some(blame) = self.blame.as_ref() {
21410            blame.update(cx, GitBlame::blur)
21411        }
21412        if !self.hover_state.focused(window, cx) {
21413            hide_hover(self, cx);
21414        }
21415        if !self
21416            .context_menu
21417            .borrow()
21418            .as_ref()
21419            .is_some_and(|context_menu| context_menu.focused(window, cx))
21420        {
21421            self.hide_context_menu(window, cx);
21422        }
21423        self.discard_edit_prediction(false, cx);
21424        cx.emit(EditorEvent::Blurred);
21425        cx.notify();
21426    }
21427
21428    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21429        let mut pending: String = window
21430            .pending_input_keystrokes()
21431            .into_iter()
21432            .flatten()
21433            .filter_map(|keystroke| {
21434                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21435                    keystroke.key_char.clone()
21436                } else {
21437                    None
21438                }
21439            })
21440            .collect();
21441
21442        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21443            pending = "".to_string();
21444        }
21445
21446        let existing_pending = self
21447            .text_highlights::<PendingInput>(cx)
21448            .map(|(_, ranges)| ranges.to_vec());
21449        if existing_pending.is_none() && pending.is_empty() {
21450            return;
21451        }
21452        let transaction =
21453            self.transact(window, cx, |this, window, cx| {
21454                let selections = this.selections.all::<usize>(cx);
21455                let edits = selections
21456                    .iter()
21457                    .map(|selection| (selection.end..selection.end, pending.clone()));
21458                this.edit(edits, cx);
21459                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21460                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21461                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21462                    }));
21463                });
21464                if let Some(existing_ranges) = existing_pending {
21465                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21466                    this.edit(edits, cx);
21467                }
21468            });
21469
21470        let snapshot = self.snapshot(window, cx);
21471        let ranges = self
21472            .selections
21473            .all::<usize>(cx)
21474            .into_iter()
21475            .map(|selection| {
21476                snapshot.buffer_snapshot.anchor_after(selection.end)
21477                    ..snapshot
21478                        .buffer_snapshot
21479                        .anchor_before(selection.end + pending.len())
21480            })
21481            .collect();
21482
21483        if pending.is_empty() {
21484            self.clear_highlights::<PendingInput>(cx);
21485        } else {
21486            self.highlight_text::<PendingInput>(
21487                ranges,
21488                HighlightStyle {
21489                    underline: Some(UnderlineStyle {
21490                        thickness: px(1.),
21491                        color: None,
21492                        wavy: false,
21493                    }),
21494                    ..Default::default()
21495                },
21496                cx,
21497            );
21498        }
21499
21500        self.ime_transaction = self.ime_transaction.or(transaction);
21501        if let Some(transaction) = self.ime_transaction {
21502            self.buffer.update(cx, |buffer, cx| {
21503                buffer.group_until_transaction(transaction, cx);
21504            });
21505        }
21506
21507        if self.text_highlights::<PendingInput>(cx).is_none() {
21508            self.ime_transaction.take();
21509        }
21510    }
21511
21512    pub fn register_action_renderer(
21513        &mut self,
21514        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21515    ) -> Subscription {
21516        let id = self.next_editor_action_id.post_inc();
21517        self.editor_actions
21518            .borrow_mut()
21519            .insert(id, Box::new(listener));
21520
21521        let editor_actions = self.editor_actions.clone();
21522        Subscription::new(move || {
21523            editor_actions.borrow_mut().remove(&id);
21524        })
21525    }
21526
21527    pub fn register_action<A: Action>(
21528        &mut self,
21529        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21530    ) -> Subscription {
21531        let id = self.next_editor_action_id.post_inc();
21532        let listener = Arc::new(listener);
21533        self.editor_actions.borrow_mut().insert(
21534            id,
21535            Box::new(move |_, window, _| {
21536                let listener = listener.clone();
21537                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21538                    let action = action.downcast_ref().unwrap();
21539                    if phase == DispatchPhase::Bubble {
21540                        listener(action, window, cx)
21541                    }
21542                })
21543            }),
21544        );
21545
21546        let editor_actions = self.editor_actions.clone();
21547        Subscription::new(move || {
21548            editor_actions.borrow_mut().remove(&id);
21549        })
21550    }
21551
21552    pub fn file_header_size(&self) -> u32 {
21553        FILE_HEADER_HEIGHT
21554    }
21555
21556    pub fn restore(
21557        &mut self,
21558        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21559        window: &mut Window,
21560        cx: &mut Context<Self>,
21561    ) {
21562        let workspace = self.workspace();
21563        let project = self.project();
21564        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21565            let mut tasks = Vec::new();
21566            for (buffer_id, changes) in revert_changes {
21567                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21568                    buffer.update(cx, |buffer, cx| {
21569                        buffer.edit(
21570                            changes
21571                                .into_iter()
21572                                .map(|(range, text)| (range, text.to_string())),
21573                            None,
21574                            cx,
21575                        );
21576                    });
21577
21578                    if let Some(project) =
21579                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21580                    {
21581                        project.update(cx, |project, cx| {
21582                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21583                        })
21584                    }
21585                }
21586            }
21587            tasks
21588        });
21589        cx.spawn_in(window, async move |_, cx| {
21590            for (buffer, task) in save_tasks {
21591                let result = task.await;
21592                if result.is_err() {
21593                    let Some(path) = buffer
21594                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21595                        .ok()
21596                    else {
21597                        continue;
21598                    };
21599                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21600                        let Some(task) = cx
21601                            .update_window_entity(workspace, |workspace, window, cx| {
21602                                workspace
21603                                    .open_path_preview(path, None, false, false, false, window, cx)
21604                            })
21605                            .ok()
21606                        else {
21607                            continue;
21608                        };
21609                        task.await.log_err();
21610                    }
21611                }
21612            }
21613        })
21614        .detach();
21615        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21616            selections.refresh()
21617        });
21618    }
21619
21620    pub fn to_pixel_point(
21621        &self,
21622        source: multi_buffer::Anchor,
21623        editor_snapshot: &EditorSnapshot,
21624        window: &mut Window,
21625    ) -> Option<gpui::Point<Pixels>> {
21626        let source_point = source.to_display_point(editor_snapshot);
21627        self.display_to_pixel_point(source_point, editor_snapshot, window)
21628    }
21629
21630    pub fn display_to_pixel_point(
21631        &self,
21632        source: DisplayPoint,
21633        editor_snapshot: &EditorSnapshot,
21634        window: &mut Window,
21635    ) -> Option<gpui::Point<Pixels>> {
21636        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21637        let text_layout_details = self.text_layout_details(window);
21638        let scroll_top = text_layout_details
21639            .scroll_anchor
21640            .scroll_position(editor_snapshot)
21641            .y;
21642
21643        if source.row().as_f32() < scroll_top.floor() {
21644            return None;
21645        }
21646        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21647        let source_y = line_height * (source.row().as_f32() - scroll_top);
21648        Some(gpui::Point::new(source_x, source_y))
21649    }
21650
21651    pub fn has_visible_completions_menu(&self) -> bool {
21652        !self.edit_prediction_preview_is_active()
21653            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21654                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21655            })
21656    }
21657
21658    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21659        if self.mode.is_minimap() {
21660            return;
21661        }
21662        self.addons
21663            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21664    }
21665
21666    pub fn unregister_addon<T: Addon>(&mut self) {
21667        self.addons.remove(&std::any::TypeId::of::<T>());
21668    }
21669
21670    pub fn addon<T: Addon>(&self) -> Option<&T> {
21671        let type_id = std::any::TypeId::of::<T>();
21672        self.addons
21673            .get(&type_id)
21674            .and_then(|item| item.to_any().downcast_ref::<T>())
21675    }
21676
21677    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21678        let type_id = std::any::TypeId::of::<T>();
21679        self.addons
21680            .get_mut(&type_id)
21681            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21682    }
21683
21684    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21685        let text_layout_details = self.text_layout_details(window);
21686        let style = &text_layout_details.editor_style;
21687        let font_id = window.text_system().resolve_font(&style.text.font());
21688        let font_size = style.text.font_size.to_pixels(window.rem_size());
21689        let line_height = style.text.line_height_in_pixels(window.rem_size());
21690        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21691        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21692
21693        CharacterDimensions {
21694            em_width,
21695            em_advance,
21696            line_height,
21697        }
21698    }
21699
21700    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21701        self.load_diff_task.clone()
21702    }
21703
21704    fn read_metadata_from_db(
21705        &mut self,
21706        item_id: u64,
21707        workspace_id: WorkspaceId,
21708        window: &mut Window,
21709        cx: &mut Context<Editor>,
21710    ) {
21711        if self.is_singleton(cx)
21712            && !self.mode.is_minimap()
21713            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21714        {
21715            let buffer_snapshot = OnceCell::new();
21716
21717            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21718                && !folds.is_empty()
21719            {
21720                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21721                self.fold_ranges(
21722                    folds
21723                        .into_iter()
21724                        .map(|(start, end)| {
21725                            snapshot.clip_offset(start, Bias::Left)
21726                                ..snapshot.clip_offset(end, Bias::Right)
21727                        })
21728                        .collect(),
21729                    false,
21730                    window,
21731                    cx,
21732                );
21733            }
21734
21735            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21736                && !selections.is_empty()
21737            {
21738                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21739                // skip adding the initial selection to selection history
21740                self.selection_history.mode = SelectionHistoryMode::Skipping;
21741                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21742                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21743                        snapshot.clip_offset(start, Bias::Left)
21744                            ..snapshot.clip_offset(end, Bias::Right)
21745                    }));
21746                });
21747                self.selection_history.mode = SelectionHistoryMode::Normal;
21748            };
21749        }
21750
21751        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21752    }
21753
21754    fn update_lsp_data(
21755        &mut self,
21756        ignore_cache: bool,
21757        for_buffer: Option<BufferId>,
21758        window: &mut Window,
21759        cx: &mut Context<'_, Self>,
21760    ) {
21761        self.pull_diagnostics(for_buffer, window, cx);
21762        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21763    }
21764}
21765
21766fn edit_for_markdown_paste<'a>(
21767    buffer: &MultiBufferSnapshot,
21768    range: Range<usize>,
21769    to_insert: &'a str,
21770    url: Option<url::Url>,
21771) -> (Range<usize>, Cow<'a, str>) {
21772    if url.is_none() {
21773        return (range, Cow::Borrowed(to_insert));
21774    };
21775
21776    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21777
21778    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21779        Cow::Borrowed(to_insert)
21780    } else {
21781        Cow::Owned(format!("[{old_text}]({to_insert})"))
21782    };
21783    (range, new_text)
21784}
21785
21786fn vim_enabled(cx: &App) -> bool {
21787    vim_mode_setting::VimModeSetting::try_get(cx)
21788        .map(|vim_mode| vim_mode.0)
21789        .unwrap_or(false)
21790}
21791
21792fn process_completion_for_edit(
21793    completion: &Completion,
21794    intent: CompletionIntent,
21795    buffer: &Entity<Buffer>,
21796    cursor_position: &text::Anchor,
21797    cx: &mut Context<Editor>,
21798) -> CompletionEdit {
21799    let buffer = buffer.read(cx);
21800    let buffer_snapshot = buffer.snapshot();
21801    let (snippet, new_text) = if completion.is_snippet() {
21802        // Workaround for typescript language server issues so that methods don't expand within
21803        // strings and functions with type expressions. The previous point is used because the query
21804        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21805        let mut snippet_source = completion.new_text.clone();
21806        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21807        previous_point.column = previous_point.column.saturating_sub(1);
21808        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21809            && scope.prefers_label_for_snippet_in_completion()
21810            && let Some(label) = completion.label()
21811            && matches!(
21812                completion.kind(),
21813                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21814            )
21815        {
21816            snippet_source = label;
21817        }
21818        match Snippet::parse(&snippet_source).log_err() {
21819            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21820            None => (None, completion.new_text.clone()),
21821        }
21822    } else {
21823        (None, completion.new_text.clone())
21824    };
21825
21826    let mut range_to_replace = {
21827        let replace_range = &completion.replace_range;
21828        if let CompletionSource::Lsp {
21829            insert_range: Some(insert_range),
21830            ..
21831        } = &completion.source
21832        {
21833            debug_assert_eq!(
21834                insert_range.start, replace_range.start,
21835                "insert_range and replace_range should start at the same position"
21836            );
21837            debug_assert!(
21838                insert_range
21839                    .start
21840                    .cmp(cursor_position, &buffer_snapshot)
21841                    .is_le(),
21842                "insert_range should start before or at cursor position"
21843            );
21844            debug_assert!(
21845                replace_range
21846                    .start
21847                    .cmp(cursor_position, &buffer_snapshot)
21848                    .is_le(),
21849                "replace_range should start before or at cursor position"
21850            );
21851
21852            let should_replace = match intent {
21853                CompletionIntent::CompleteWithInsert => false,
21854                CompletionIntent::CompleteWithReplace => true,
21855                CompletionIntent::Complete | CompletionIntent::Compose => {
21856                    let insert_mode =
21857                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21858                            .completions
21859                            .lsp_insert_mode;
21860                    match insert_mode {
21861                        LspInsertMode::Insert => false,
21862                        LspInsertMode::Replace => true,
21863                        LspInsertMode::ReplaceSubsequence => {
21864                            let mut text_to_replace = buffer.chars_for_range(
21865                                buffer.anchor_before(replace_range.start)
21866                                    ..buffer.anchor_after(replace_range.end),
21867                            );
21868                            let mut current_needle = text_to_replace.next();
21869                            for haystack_ch in completion.label.text.chars() {
21870                                if let Some(needle_ch) = current_needle
21871                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21872                                {
21873                                    current_needle = text_to_replace.next();
21874                                }
21875                            }
21876                            current_needle.is_none()
21877                        }
21878                        LspInsertMode::ReplaceSuffix => {
21879                            if replace_range
21880                                .end
21881                                .cmp(cursor_position, &buffer_snapshot)
21882                                .is_gt()
21883                            {
21884                                let range_after_cursor = *cursor_position..replace_range.end;
21885                                let text_after_cursor = buffer
21886                                    .text_for_range(
21887                                        buffer.anchor_before(range_after_cursor.start)
21888                                            ..buffer.anchor_after(range_after_cursor.end),
21889                                    )
21890                                    .collect::<String>()
21891                                    .to_ascii_lowercase();
21892                                completion
21893                                    .label
21894                                    .text
21895                                    .to_ascii_lowercase()
21896                                    .ends_with(&text_after_cursor)
21897                            } else {
21898                                true
21899                            }
21900                        }
21901                    }
21902                }
21903            };
21904
21905            if should_replace {
21906                replace_range.clone()
21907            } else {
21908                insert_range.clone()
21909            }
21910        } else {
21911            replace_range.clone()
21912        }
21913    };
21914
21915    if range_to_replace
21916        .end
21917        .cmp(cursor_position, &buffer_snapshot)
21918        .is_lt()
21919    {
21920        range_to_replace.end = *cursor_position;
21921    }
21922
21923    CompletionEdit {
21924        new_text,
21925        replace_range: range_to_replace.to_offset(buffer),
21926        snippet,
21927    }
21928}
21929
21930struct CompletionEdit {
21931    new_text: String,
21932    replace_range: Range<usize>,
21933    snippet: Option<Snippet>,
21934}
21935
21936fn insert_extra_newline_brackets(
21937    buffer: &MultiBufferSnapshot,
21938    range: Range<usize>,
21939    language: &language::LanguageScope,
21940) -> bool {
21941    let leading_whitespace_len = buffer
21942        .reversed_chars_at(range.start)
21943        .take_while(|c| c.is_whitespace() && *c != '\n')
21944        .map(|c| c.len_utf8())
21945        .sum::<usize>();
21946    let trailing_whitespace_len = buffer
21947        .chars_at(range.end)
21948        .take_while(|c| c.is_whitespace() && *c != '\n')
21949        .map(|c| c.len_utf8())
21950        .sum::<usize>();
21951    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21952
21953    language.brackets().any(|(pair, enabled)| {
21954        let pair_start = pair.start.trim_end();
21955        let pair_end = pair.end.trim_start();
21956
21957        enabled
21958            && pair.newline
21959            && buffer.contains_str_at(range.end, pair_end)
21960            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21961    })
21962}
21963
21964fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21965    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21966        [(buffer, range, _)] => (*buffer, range.clone()),
21967        _ => return false,
21968    };
21969    let pair = {
21970        let mut result: Option<BracketMatch> = None;
21971
21972        for pair in buffer
21973            .all_bracket_ranges(range.clone())
21974            .filter(move |pair| {
21975                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21976            })
21977        {
21978            let len = pair.close_range.end - pair.open_range.start;
21979
21980            if let Some(existing) = &result {
21981                let existing_len = existing.close_range.end - existing.open_range.start;
21982                if len > existing_len {
21983                    continue;
21984                }
21985            }
21986
21987            result = Some(pair);
21988        }
21989
21990        result
21991    };
21992    let Some(pair) = pair else {
21993        return false;
21994    };
21995    pair.newline_only
21996        && buffer
21997            .chars_for_range(pair.open_range.end..range.start)
21998            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21999            .all(|c| c.is_whitespace() && c != '\n')
22000}
22001
22002fn update_uncommitted_diff_for_buffer(
22003    editor: Entity<Editor>,
22004    project: &Entity<Project>,
22005    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22006    buffer: Entity<MultiBuffer>,
22007    cx: &mut App,
22008) -> Task<()> {
22009    let mut tasks = Vec::new();
22010    project.update(cx, |project, cx| {
22011        for buffer in buffers {
22012            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22013                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22014            }
22015        }
22016    });
22017    cx.spawn(async move |cx| {
22018        let diffs = future::join_all(tasks).await;
22019        if editor
22020            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22021            .unwrap_or(false)
22022        {
22023            return;
22024        }
22025
22026        buffer
22027            .update(cx, |buffer, cx| {
22028                for diff in diffs.into_iter().flatten() {
22029                    buffer.add_diff(diff, cx);
22030                }
22031            })
22032            .ok();
22033    })
22034}
22035
22036fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22037    let tab_size = tab_size.get() as usize;
22038    let mut width = offset;
22039
22040    for ch in text.chars() {
22041        width += if ch == '\t' {
22042            tab_size - (width % tab_size)
22043        } else {
22044            1
22045        };
22046    }
22047
22048    width - offset
22049}
22050
22051#[cfg(test)]
22052mod tests {
22053    use super::*;
22054
22055    #[test]
22056    fn test_string_size_with_expanded_tabs() {
22057        let nz = |val| NonZeroU32::new(val).unwrap();
22058        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22059        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22060        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22061        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22062        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22063        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22064        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22065        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22066    }
22067}
22068
22069/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22070struct WordBreakingTokenizer<'a> {
22071    input: &'a str,
22072}
22073
22074impl<'a> WordBreakingTokenizer<'a> {
22075    fn new(input: &'a str) -> Self {
22076        Self { input }
22077    }
22078}
22079
22080fn is_char_ideographic(ch: char) -> bool {
22081    use unicode_script::Script::*;
22082    use unicode_script::UnicodeScript;
22083    matches!(ch.script(), Han | Tangut | Yi)
22084}
22085
22086fn is_grapheme_ideographic(text: &str) -> bool {
22087    text.chars().any(is_char_ideographic)
22088}
22089
22090fn is_grapheme_whitespace(text: &str) -> bool {
22091    text.chars().any(|x| x.is_whitespace())
22092}
22093
22094fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22095    text.chars()
22096        .next()
22097        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22098}
22099
22100#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22101enum WordBreakToken<'a> {
22102    Word { token: &'a str, grapheme_len: usize },
22103    InlineWhitespace { token: &'a str, grapheme_len: usize },
22104    Newline,
22105}
22106
22107impl<'a> Iterator for WordBreakingTokenizer<'a> {
22108    /// Yields a span, the count of graphemes in the token, and whether it was
22109    /// whitespace. Note that it also breaks at word boundaries.
22110    type Item = WordBreakToken<'a>;
22111
22112    fn next(&mut self) -> Option<Self::Item> {
22113        use unicode_segmentation::UnicodeSegmentation;
22114        if self.input.is_empty() {
22115            return None;
22116        }
22117
22118        let mut iter = self.input.graphemes(true).peekable();
22119        let mut offset = 0;
22120        let mut grapheme_len = 0;
22121        if let Some(first_grapheme) = iter.next() {
22122            let is_newline = first_grapheme == "\n";
22123            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22124            offset += first_grapheme.len();
22125            grapheme_len += 1;
22126            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22127                if let Some(grapheme) = iter.peek().copied()
22128                    && should_stay_with_preceding_ideograph(grapheme)
22129                {
22130                    offset += grapheme.len();
22131                    grapheme_len += 1;
22132                }
22133            } else {
22134                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22135                let mut next_word_bound = words.peek().copied();
22136                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22137                    next_word_bound = words.next();
22138                }
22139                while let Some(grapheme) = iter.peek().copied() {
22140                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22141                        break;
22142                    };
22143                    if is_grapheme_whitespace(grapheme) != is_whitespace
22144                        || (grapheme == "\n") != is_newline
22145                    {
22146                        break;
22147                    };
22148                    offset += grapheme.len();
22149                    grapheme_len += 1;
22150                    iter.next();
22151                }
22152            }
22153            let token = &self.input[..offset];
22154            self.input = &self.input[offset..];
22155            if token == "\n" {
22156                Some(WordBreakToken::Newline)
22157            } else if is_whitespace {
22158                Some(WordBreakToken::InlineWhitespace {
22159                    token,
22160                    grapheme_len,
22161                })
22162            } else {
22163                Some(WordBreakToken::Word {
22164                    token,
22165                    grapheme_len,
22166                })
22167            }
22168        } else {
22169            None
22170        }
22171    }
22172}
22173
22174#[test]
22175fn test_word_breaking_tokenizer() {
22176    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22177        ("", &[]),
22178        ("  ", &[whitespace("  ", 2)]),
22179        ("Ʒ", &[word("Ʒ", 1)]),
22180        ("Ǽ", &[word("Ǽ", 1)]),
22181        ("", &[word("", 1)]),
22182        ("⋑⋑", &[word("⋑⋑", 2)]),
22183        (
22184            "原理,进而",
22185            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22186        ),
22187        (
22188            "hello world",
22189            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22190        ),
22191        (
22192            "hello, world",
22193            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22194        ),
22195        (
22196            "  hello world",
22197            &[
22198                whitespace("  ", 2),
22199                word("hello", 5),
22200                whitespace(" ", 1),
22201                word("world", 5),
22202            ],
22203        ),
22204        (
22205            "这是什么 \n 钢笔",
22206            &[
22207                word("", 1),
22208                word("", 1),
22209                word("", 1),
22210                word("", 1),
22211                whitespace(" ", 1),
22212                newline(),
22213                whitespace(" ", 1),
22214                word("", 1),
22215                word("", 1),
22216            ],
22217        ),
22218        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22219    ];
22220
22221    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22222        WordBreakToken::Word {
22223            token,
22224            grapheme_len,
22225        }
22226    }
22227
22228    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22229        WordBreakToken::InlineWhitespace {
22230            token,
22231            grapheme_len,
22232        }
22233    }
22234
22235    fn newline() -> WordBreakToken<'static> {
22236        WordBreakToken::Newline
22237    }
22238
22239    for (input, result) in tests {
22240        assert_eq!(
22241            WordBreakingTokenizer::new(input)
22242                .collect::<Vec<_>>()
22243                .as_slice(),
22244            *result,
22245        );
22246    }
22247}
22248
22249fn wrap_with_prefix(
22250    first_line_prefix: String,
22251    subsequent_lines_prefix: String,
22252    unwrapped_text: String,
22253    wrap_column: usize,
22254    tab_size: NonZeroU32,
22255    preserve_existing_whitespace: bool,
22256) -> String {
22257    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22258    let subsequent_lines_prefix_len =
22259        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22260    let mut wrapped_text = String::new();
22261    let mut current_line = first_line_prefix;
22262    let mut is_first_line = true;
22263
22264    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22265    let mut current_line_len = first_line_prefix_len;
22266    let mut in_whitespace = false;
22267    for token in tokenizer {
22268        let have_preceding_whitespace = in_whitespace;
22269        match token {
22270            WordBreakToken::Word {
22271                token,
22272                grapheme_len,
22273            } => {
22274                in_whitespace = false;
22275                let current_prefix_len = if is_first_line {
22276                    first_line_prefix_len
22277                } else {
22278                    subsequent_lines_prefix_len
22279                };
22280                if current_line_len + grapheme_len > wrap_column
22281                    && current_line_len != current_prefix_len
22282                {
22283                    wrapped_text.push_str(current_line.trim_end());
22284                    wrapped_text.push('\n');
22285                    is_first_line = false;
22286                    current_line = subsequent_lines_prefix.clone();
22287                    current_line_len = subsequent_lines_prefix_len;
22288                }
22289                current_line.push_str(token);
22290                current_line_len += grapheme_len;
22291            }
22292            WordBreakToken::InlineWhitespace {
22293                mut token,
22294                mut grapheme_len,
22295            } => {
22296                in_whitespace = true;
22297                if have_preceding_whitespace && !preserve_existing_whitespace {
22298                    continue;
22299                }
22300                if !preserve_existing_whitespace {
22301                    token = " ";
22302                    grapheme_len = 1;
22303                }
22304                let current_prefix_len = if is_first_line {
22305                    first_line_prefix_len
22306                } else {
22307                    subsequent_lines_prefix_len
22308                };
22309                if current_line_len + grapheme_len > wrap_column {
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 current_line_len != current_prefix_len || preserve_existing_whitespace {
22316                    current_line.push_str(token);
22317                    current_line_len += grapheme_len;
22318                }
22319            }
22320            WordBreakToken::Newline => {
22321                in_whitespace = true;
22322                let current_prefix_len = if is_first_line {
22323                    first_line_prefix_len
22324                } else {
22325                    subsequent_lines_prefix_len
22326                };
22327                if preserve_existing_whitespace {
22328                    wrapped_text.push_str(current_line.trim_end());
22329                    wrapped_text.push('\n');
22330                    is_first_line = false;
22331                    current_line = subsequent_lines_prefix.clone();
22332                    current_line_len = subsequent_lines_prefix_len;
22333                } else if have_preceding_whitespace {
22334                    continue;
22335                } else if current_line_len + 1 > wrap_column
22336                    && current_line_len != current_prefix_len
22337                {
22338                    wrapped_text.push_str(current_line.trim_end());
22339                    wrapped_text.push('\n');
22340                    is_first_line = false;
22341                    current_line = subsequent_lines_prefix.clone();
22342                    current_line_len = subsequent_lines_prefix_len;
22343                } else if current_line_len != current_prefix_len {
22344                    current_line.push(' ');
22345                    current_line_len += 1;
22346                }
22347            }
22348        }
22349    }
22350
22351    if !current_line.is_empty() {
22352        wrapped_text.push_str(&current_line);
22353    }
22354    wrapped_text
22355}
22356
22357#[test]
22358fn test_wrap_with_prefix() {
22359    assert_eq!(
22360        wrap_with_prefix(
22361            "# ".to_string(),
22362            "# ".to_string(),
22363            "abcdefg".to_string(),
22364            4,
22365            NonZeroU32::new(4).unwrap(),
22366            false,
22367        ),
22368        "# abcdefg"
22369    );
22370    assert_eq!(
22371        wrap_with_prefix(
22372            "".to_string(),
22373            "".to_string(),
22374            "\thello world".to_string(),
22375            8,
22376            NonZeroU32::new(4).unwrap(),
22377            false,
22378        ),
22379        "hello\nworld"
22380    );
22381    assert_eq!(
22382        wrap_with_prefix(
22383            "// ".to_string(),
22384            "// ".to_string(),
22385            "xx \nyy zz aa bb cc".to_string(),
22386            12,
22387            NonZeroU32::new(4).unwrap(),
22388            false,
22389        ),
22390        "// xx yy zz\n// aa bb cc"
22391    );
22392    assert_eq!(
22393        wrap_with_prefix(
22394            String::new(),
22395            String::new(),
22396            "这是什么 \n 钢笔".to_string(),
22397            3,
22398            NonZeroU32::new(4).unwrap(),
22399            false,
22400        ),
22401        "这是什\n么 钢\n"
22402    );
22403}
22404
22405pub trait CollaborationHub {
22406    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22407    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22408    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22409}
22410
22411impl CollaborationHub for Entity<Project> {
22412    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22413        self.read(cx).collaborators()
22414    }
22415
22416    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22417        self.read(cx).user_store().read(cx).participant_indices()
22418    }
22419
22420    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22421        let this = self.read(cx);
22422        let user_ids = this.collaborators().values().map(|c| c.user_id);
22423        this.user_store().read(cx).participant_names(user_ids, cx)
22424    }
22425}
22426
22427pub trait SemanticsProvider {
22428    fn hover(
22429        &self,
22430        buffer: &Entity<Buffer>,
22431        position: text::Anchor,
22432        cx: &mut App,
22433    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22434
22435    fn inline_values(
22436        &self,
22437        buffer_handle: Entity<Buffer>,
22438        range: Range<text::Anchor>,
22439        cx: &mut App,
22440    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22441
22442    fn inlay_hints(
22443        &self,
22444        buffer_handle: Entity<Buffer>,
22445        range: Range<text::Anchor>,
22446        cx: &mut App,
22447    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22448
22449    fn resolve_inlay_hint(
22450        &self,
22451        hint: InlayHint,
22452        buffer_handle: Entity<Buffer>,
22453        server_id: LanguageServerId,
22454        cx: &mut App,
22455    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22456
22457    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22458
22459    fn document_highlights(
22460        &self,
22461        buffer: &Entity<Buffer>,
22462        position: text::Anchor,
22463        cx: &mut App,
22464    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22465
22466    fn definitions(
22467        &self,
22468        buffer: &Entity<Buffer>,
22469        position: text::Anchor,
22470        kind: GotoDefinitionKind,
22471        cx: &mut App,
22472    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22473
22474    fn range_for_rename(
22475        &self,
22476        buffer: &Entity<Buffer>,
22477        position: text::Anchor,
22478        cx: &mut App,
22479    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22480
22481    fn perform_rename(
22482        &self,
22483        buffer: &Entity<Buffer>,
22484        position: text::Anchor,
22485        new_name: String,
22486        cx: &mut App,
22487    ) -> Option<Task<Result<ProjectTransaction>>>;
22488}
22489
22490pub trait CompletionProvider {
22491    fn completions(
22492        &self,
22493        excerpt_id: ExcerptId,
22494        buffer: &Entity<Buffer>,
22495        buffer_position: text::Anchor,
22496        trigger: CompletionContext,
22497        window: &mut Window,
22498        cx: &mut Context<Editor>,
22499    ) -> Task<Result<Vec<CompletionResponse>>>;
22500
22501    fn resolve_completions(
22502        &self,
22503        _buffer: Entity<Buffer>,
22504        _completion_indices: Vec<usize>,
22505        _completions: Rc<RefCell<Box<[Completion]>>>,
22506        _cx: &mut Context<Editor>,
22507    ) -> Task<Result<bool>> {
22508        Task::ready(Ok(false))
22509    }
22510
22511    fn apply_additional_edits_for_completion(
22512        &self,
22513        _buffer: Entity<Buffer>,
22514        _completions: Rc<RefCell<Box<[Completion]>>>,
22515        _completion_index: usize,
22516        _push_to_history: bool,
22517        _cx: &mut Context<Editor>,
22518    ) -> Task<Result<Option<language::Transaction>>> {
22519        Task::ready(Ok(None))
22520    }
22521
22522    fn is_completion_trigger(
22523        &self,
22524        buffer: &Entity<Buffer>,
22525        position: language::Anchor,
22526        text: &str,
22527        trigger_in_words: bool,
22528        menu_is_open: bool,
22529        cx: &mut Context<Editor>,
22530    ) -> bool;
22531
22532    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22533
22534    fn sort_completions(&self) -> bool {
22535        true
22536    }
22537
22538    fn filter_completions(&self) -> bool {
22539        true
22540    }
22541}
22542
22543pub trait CodeActionProvider {
22544    fn id(&self) -> Arc<str>;
22545
22546    fn code_actions(
22547        &self,
22548        buffer: &Entity<Buffer>,
22549        range: Range<text::Anchor>,
22550        window: &mut Window,
22551        cx: &mut App,
22552    ) -> Task<Result<Vec<CodeAction>>>;
22553
22554    fn apply_code_action(
22555        &self,
22556        buffer_handle: Entity<Buffer>,
22557        action: CodeAction,
22558        excerpt_id: ExcerptId,
22559        push_to_history: bool,
22560        window: &mut Window,
22561        cx: &mut App,
22562    ) -> Task<Result<ProjectTransaction>>;
22563}
22564
22565impl CodeActionProvider for Entity<Project> {
22566    fn id(&self) -> Arc<str> {
22567        "project".into()
22568    }
22569
22570    fn code_actions(
22571        &self,
22572        buffer: &Entity<Buffer>,
22573        range: Range<text::Anchor>,
22574        _window: &mut Window,
22575        cx: &mut App,
22576    ) -> Task<Result<Vec<CodeAction>>> {
22577        self.update(cx, |project, cx| {
22578            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22579            let code_actions = project.code_actions(buffer, range, None, cx);
22580            cx.background_spawn(async move {
22581                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22582                Ok(code_lens_actions
22583                    .context("code lens fetch")?
22584                    .into_iter()
22585                    .flatten()
22586                    .chain(
22587                        code_actions
22588                            .context("code action fetch")?
22589                            .into_iter()
22590                            .flatten(),
22591                    )
22592                    .collect())
22593            })
22594        })
22595    }
22596
22597    fn apply_code_action(
22598        &self,
22599        buffer_handle: Entity<Buffer>,
22600        action: CodeAction,
22601        _excerpt_id: ExcerptId,
22602        push_to_history: bool,
22603        _window: &mut Window,
22604        cx: &mut App,
22605    ) -> Task<Result<ProjectTransaction>> {
22606        self.update(cx, |project, cx| {
22607            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22608        })
22609    }
22610}
22611
22612fn snippet_completions(
22613    project: &Project,
22614    buffer: &Entity<Buffer>,
22615    buffer_position: text::Anchor,
22616    cx: &mut App,
22617) -> Task<Result<CompletionResponse>> {
22618    let languages = buffer.read(cx).languages_at(buffer_position);
22619    let snippet_store = project.snippets().read(cx);
22620
22621    let scopes: Vec<_> = languages
22622        .iter()
22623        .filter_map(|language| {
22624            let language_name = language.lsp_id();
22625            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22626
22627            if snippets.is_empty() {
22628                None
22629            } else {
22630                Some((language.default_scope(), snippets))
22631            }
22632        })
22633        .collect();
22634
22635    if scopes.is_empty() {
22636        return Task::ready(Ok(CompletionResponse {
22637            completions: vec![],
22638            display_options: CompletionDisplayOptions::default(),
22639            is_incomplete: false,
22640        }));
22641    }
22642
22643    let snapshot = buffer.read(cx).text_snapshot();
22644    let chars: String = snapshot
22645        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22646        .collect();
22647    let executor = cx.background_executor().clone();
22648
22649    cx.background_spawn(async move {
22650        let mut is_incomplete = false;
22651        let mut completions: Vec<Completion> = Vec::new();
22652        for (scope, snippets) in scopes.into_iter() {
22653            let classifier =
22654                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22655            let mut last_word = chars
22656                .chars()
22657                .take_while(|c| classifier.is_word(*c))
22658                .collect::<String>();
22659            last_word = last_word.chars().rev().collect();
22660
22661            if last_word.is_empty() {
22662                return Ok(CompletionResponse {
22663                    completions: vec![],
22664                    display_options: CompletionDisplayOptions::default(),
22665                    is_incomplete: true,
22666                });
22667            }
22668
22669            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22670            let to_lsp = |point: &text::Anchor| {
22671                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22672                point_to_lsp(end)
22673            };
22674            let lsp_end = to_lsp(&buffer_position);
22675
22676            let candidates = snippets
22677                .iter()
22678                .enumerate()
22679                .flat_map(|(ix, snippet)| {
22680                    snippet
22681                        .prefix
22682                        .iter()
22683                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22684                })
22685                .collect::<Vec<StringMatchCandidate>>();
22686
22687            const MAX_RESULTS: usize = 100;
22688            let mut matches = fuzzy::match_strings(
22689                &candidates,
22690                &last_word,
22691                last_word.chars().any(|c| c.is_uppercase()),
22692                true,
22693                MAX_RESULTS,
22694                &Default::default(),
22695                executor.clone(),
22696            )
22697            .await;
22698
22699            if matches.len() >= MAX_RESULTS {
22700                is_incomplete = true;
22701            }
22702
22703            // Remove all candidates where the query's start does not match the start of any word in the candidate
22704            if let Some(query_start) = last_word.chars().next() {
22705                matches.retain(|string_match| {
22706                    split_words(&string_match.string).any(|word| {
22707                        // Check that the first codepoint of the word as lowercase matches the first
22708                        // codepoint of the query as lowercase
22709                        word.chars()
22710                            .flat_map(|codepoint| codepoint.to_lowercase())
22711                            .zip(query_start.to_lowercase())
22712                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22713                    })
22714                });
22715            }
22716
22717            let matched_strings = matches
22718                .into_iter()
22719                .map(|m| m.string)
22720                .collect::<HashSet<_>>();
22721
22722            completions.extend(snippets.iter().filter_map(|snippet| {
22723                let matching_prefix = snippet
22724                    .prefix
22725                    .iter()
22726                    .find(|prefix| matched_strings.contains(*prefix))?;
22727                let start = as_offset - last_word.len();
22728                let start = snapshot.anchor_before(start);
22729                let range = start..buffer_position;
22730                let lsp_start = to_lsp(&start);
22731                let lsp_range = lsp::Range {
22732                    start: lsp_start,
22733                    end: lsp_end,
22734                };
22735                Some(Completion {
22736                    replace_range: range,
22737                    new_text: snippet.body.clone(),
22738                    source: CompletionSource::Lsp {
22739                        insert_range: None,
22740                        server_id: LanguageServerId(usize::MAX),
22741                        resolved: true,
22742                        lsp_completion: Box::new(lsp::CompletionItem {
22743                            label: snippet.prefix.first().unwrap().clone(),
22744                            kind: Some(CompletionItemKind::SNIPPET),
22745                            label_details: snippet.description.as_ref().map(|description| {
22746                                lsp::CompletionItemLabelDetails {
22747                                    detail: Some(description.clone()),
22748                                    description: None,
22749                                }
22750                            }),
22751                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22752                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22753                                lsp::InsertReplaceEdit {
22754                                    new_text: snippet.body.clone(),
22755                                    insert: lsp_range,
22756                                    replace: lsp_range,
22757                                },
22758                            )),
22759                            filter_text: Some(snippet.body.clone()),
22760                            sort_text: Some(char::MAX.to_string()),
22761                            ..lsp::CompletionItem::default()
22762                        }),
22763                        lsp_defaults: None,
22764                    },
22765                    label: CodeLabel {
22766                        text: matching_prefix.clone(),
22767                        runs: Vec::new(),
22768                        filter_range: 0..matching_prefix.len(),
22769                    },
22770                    icon_path: None,
22771                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22772                        single_line: snippet.name.clone().into(),
22773                        plain_text: snippet
22774                            .description
22775                            .clone()
22776                            .map(|description| description.into()),
22777                    }),
22778                    insert_text_mode: None,
22779                    confirm: None,
22780                })
22781            }))
22782        }
22783
22784        Ok(CompletionResponse {
22785            completions,
22786            display_options: CompletionDisplayOptions::default(),
22787            is_incomplete,
22788        })
22789    })
22790}
22791
22792impl CompletionProvider for Entity<Project> {
22793    fn completions(
22794        &self,
22795        _excerpt_id: ExcerptId,
22796        buffer: &Entity<Buffer>,
22797        buffer_position: text::Anchor,
22798        options: CompletionContext,
22799        _window: &mut Window,
22800        cx: &mut Context<Editor>,
22801    ) -> Task<Result<Vec<CompletionResponse>>> {
22802        self.update(cx, |project, cx| {
22803            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22804            let project_completions = project.completions(buffer, buffer_position, options, cx);
22805            cx.background_spawn(async move {
22806                let mut responses = project_completions.await?;
22807                let snippets = snippets.await?;
22808                if !snippets.completions.is_empty() {
22809                    responses.push(snippets);
22810                }
22811                Ok(responses)
22812            })
22813        })
22814    }
22815
22816    fn resolve_completions(
22817        &self,
22818        buffer: Entity<Buffer>,
22819        completion_indices: Vec<usize>,
22820        completions: Rc<RefCell<Box<[Completion]>>>,
22821        cx: &mut Context<Editor>,
22822    ) -> Task<Result<bool>> {
22823        self.update(cx, |project, cx| {
22824            project.lsp_store().update(cx, |lsp_store, cx| {
22825                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22826            })
22827        })
22828    }
22829
22830    fn apply_additional_edits_for_completion(
22831        &self,
22832        buffer: Entity<Buffer>,
22833        completions: Rc<RefCell<Box<[Completion]>>>,
22834        completion_index: usize,
22835        push_to_history: bool,
22836        cx: &mut Context<Editor>,
22837    ) -> Task<Result<Option<language::Transaction>>> {
22838        self.update(cx, |project, cx| {
22839            project.lsp_store().update(cx, |lsp_store, cx| {
22840                lsp_store.apply_additional_edits_for_completion(
22841                    buffer,
22842                    completions,
22843                    completion_index,
22844                    push_to_history,
22845                    cx,
22846                )
22847            })
22848        })
22849    }
22850
22851    fn is_completion_trigger(
22852        &self,
22853        buffer: &Entity<Buffer>,
22854        position: language::Anchor,
22855        text: &str,
22856        trigger_in_words: bool,
22857        menu_is_open: bool,
22858        cx: &mut Context<Editor>,
22859    ) -> bool {
22860        let mut chars = text.chars();
22861        let char = if let Some(char) = chars.next() {
22862            char
22863        } else {
22864            return false;
22865        };
22866        if chars.next().is_some() {
22867            return false;
22868        }
22869
22870        let buffer = buffer.read(cx);
22871        let snapshot = buffer.snapshot();
22872        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22873            return false;
22874        }
22875        let classifier = snapshot
22876            .char_classifier_at(position)
22877            .scope_context(Some(CharScopeContext::Completion));
22878        if trigger_in_words && classifier.is_word(char) {
22879            return true;
22880        }
22881
22882        buffer.completion_triggers().contains(text)
22883    }
22884}
22885
22886impl SemanticsProvider for Entity<Project> {
22887    fn hover(
22888        &self,
22889        buffer: &Entity<Buffer>,
22890        position: text::Anchor,
22891        cx: &mut App,
22892    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22893        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22894    }
22895
22896    fn document_highlights(
22897        &self,
22898        buffer: &Entity<Buffer>,
22899        position: text::Anchor,
22900        cx: &mut App,
22901    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22902        Some(self.update(cx, |project, cx| {
22903            project.document_highlights(buffer, position, cx)
22904        }))
22905    }
22906
22907    fn definitions(
22908        &self,
22909        buffer: &Entity<Buffer>,
22910        position: text::Anchor,
22911        kind: GotoDefinitionKind,
22912        cx: &mut App,
22913    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22914        Some(self.update(cx, |project, cx| match kind {
22915            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22916            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22917            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22918            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22919        }))
22920    }
22921
22922    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22923        self.update(cx, |project, cx| {
22924            if project
22925                .active_debug_session(cx)
22926                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22927            {
22928                return true;
22929            }
22930
22931            buffer.update(cx, |buffer, cx| {
22932                project.any_language_server_supports_inlay_hints(buffer, cx)
22933            })
22934        })
22935    }
22936
22937    fn inline_values(
22938        &self,
22939        buffer_handle: Entity<Buffer>,
22940        range: Range<text::Anchor>,
22941        cx: &mut App,
22942    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22943        self.update(cx, |project, cx| {
22944            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22945
22946            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22947        })
22948    }
22949
22950    fn inlay_hints(
22951        &self,
22952        buffer_handle: Entity<Buffer>,
22953        range: Range<text::Anchor>,
22954        cx: &mut App,
22955    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22956        Some(self.update(cx, |project, cx| {
22957            project.inlay_hints(buffer_handle, range, cx)
22958        }))
22959    }
22960
22961    fn resolve_inlay_hint(
22962        &self,
22963        hint: InlayHint,
22964        buffer_handle: Entity<Buffer>,
22965        server_id: LanguageServerId,
22966        cx: &mut App,
22967    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22968        Some(self.update(cx, |project, cx| {
22969            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22970        }))
22971    }
22972
22973    fn range_for_rename(
22974        &self,
22975        buffer: &Entity<Buffer>,
22976        position: text::Anchor,
22977        cx: &mut App,
22978    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22979        Some(self.update(cx, |project, cx| {
22980            let buffer = buffer.clone();
22981            let task = project.prepare_rename(buffer.clone(), position, cx);
22982            cx.spawn(async move |_, cx| {
22983                Ok(match task.await? {
22984                    PrepareRenameResponse::Success(range) => Some(range),
22985                    PrepareRenameResponse::InvalidPosition => None,
22986                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22987                        // Fallback on using TreeSitter info to determine identifier range
22988                        buffer.read_with(cx, |buffer, _| {
22989                            let snapshot = buffer.snapshot();
22990                            let (range, kind) = snapshot.surrounding_word(position, None);
22991                            if kind != Some(CharKind::Word) {
22992                                return None;
22993                            }
22994                            Some(
22995                                snapshot.anchor_before(range.start)
22996                                    ..snapshot.anchor_after(range.end),
22997                            )
22998                        })?
22999                    }
23000                })
23001            })
23002        }))
23003    }
23004
23005    fn perform_rename(
23006        &self,
23007        buffer: &Entity<Buffer>,
23008        position: text::Anchor,
23009        new_name: String,
23010        cx: &mut App,
23011    ) -> Option<Task<Result<ProjectTransaction>>> {
23012        Some(self.update(cx, |project, cx| {
23013            project.perform_rename(buffer.clone(), position, new_name, cx)
23014        }))
23015    }
23016}
23017
23018fn inlay_hint_settings(
23019    location: Anchor,
23020    snapshot: &MultiBufferSnapshot,
23021    cx: &mut Context<Editor>,
23022) -> InlayHintSettings {
23023    let file = snapshot.file_at(location);
23024    let language = snapshot.language_at(location).map(|l| l.name());
23025    language_settings(language, file, cx).inlay_hints
23026}
23027
23028fn consume_contiguous_rows(
23029    contiguous_row_selections: &mut Vec<Selection<Point>>,
23030    selection: &Selection<Point>,
23031    display_map: &DisplaySnapshot,
23032    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23033) -> (MultiBufferRow, MultiBufferRow) {
23034    contiguous_row_selections.push(selection.clone());
23035    let start_row = starting_row(selection, display_map);
23036    let mut end_row = ending_row(selection, display_map);
23037
23038    while let Some(next_selection) = selections.peek() {
23039        if next_selection.start.row <= end_row.0 {
23040            end_row = ending_row(next_selection, display_map);
23041            contiguous_row_selections.push(selections.next().unwrap().clone());
23042        } else {
23043            break;
23044        }
23045    }
23046    (start_row, end_row)
23047}
23048
23049fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23050    if selection.start.column > 0 {
23051        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23052    } else {
23053        MultiBufferRow(selection.start.row)
23054    }
23055}
23056
23057fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23058    if next_selection.end.column > 0 || next_selection.is_empty() {
23059        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23060    } else {
23061        MultiBufferRow(next_selection.end.row)
23062    }
23063}
23064
23065impl EditorSnapshot {
23066    pub fn remote_selections_in_range<'a>(
23067        &'a self,
23068        range: &'a Range<Anchor>,
23069        collaboration_hub: &dyn CollaborationHub,
23070        cx: &'a App,
23071    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23072        let participant_names = collaboration_hub.user_names(cx);
23073        let participant_indices = collaboration_hub.user_participant_indices(cx);
23074        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23075        let collaborators_by_replica_id = collaborators_by_peer_id
23076            .values()
23077            .map(|collaborator| (collaborator.replica_id, collaborator))
23078            .collect::<HashMap<_, _>>();
23079        self.buffer_snapshot
23080            .selections_in_range(range, false)
23081            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23082                if replica_id == AGENT_REPLICA_ID {
23083                    Some(RemoteSelection {
23084                        replica_id,
23085                        selection,
23086                        cursor_shape,
23087                        line_mode,
23088                        collaborator_id: CollaboratorId::Agent,
23089                        user_name: Some("Agent".into()),
23090                        color: cx.theme().players().agent(),
23091                    })
23092                } else {
23093                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23094                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23095                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23096                    Some(RemoteSelection {
23097                        replica_id,
23098                        selection,
23099                        cursor_shape,
23100                        line_mode,
23101                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23102                        user_name,
23103                        color: if let Some(index) = participant_index {
23104                            cx.theme().players().color_for_participant(index.0)
23105                        } else {
23106                            cx.theme().players().absent()
23107                        },
23108                    })
23109                }
23110            })
23111    }
23112
23113    pub fn hunks_for_ranges(
23114        &self,
23115        ranges: impl IntoIterator<Item = Range<Point>>,
23116    ) -> Vec<MultiBufferDiffHunk> {
23117        let mut hunks = Vec::new();
23118        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23119            HashMap::default();
23120        for query_range in ranges {
23121            let query_rows =
23122                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23123            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23124                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23125            ) {
23126                // Include deleted hunks that are adjacent to the query range, because
23127                // otherwise they would be missed.
23128                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23129                if hunk.status().is_deleted() {
23130                    intersects_range |= hunk.row_range.start == query_rows.end;
23131                    intersects_range |= hunk.row_range.end == query_rows.start;
23132                }
23133                if intersects_range {
23134                    if !processed_buffer_rows
23135                        .entry(hunk.buffer_id)
23136                        .or_default()
23137                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23138                    {
23139                        continue;
23140                    }
23141                    hunks.push(hunk);
23142                }
23143            }
23144        }
23145
23146        hunks
23147    }
23148
23149    fn display_diff_hunks_for_rows<'a>(
23150        &'a self,
23151        display_rows: Range<DisplayRow>,
23152        folded_buffers: &'a HashSet<BufferId>,
23153    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23154        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23155        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23156
23157        self.buffer_snapshot
23158            .diff_hunks_in_range(buffer_start..buffer_end)
23159            .filter_map(|hunk| {
23160                if folded_buffers.contains(&hunk.buffer_id) {
23161                    return None;
23162                }
23163
23164                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23165                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23166
23167                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23168                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23169
23170                let display_hunk = if hunk_display_start.column() != 0 {
23171                    DisplayDiffHunk::Folded {
23172                        display_row: hunk_display_start.row(),
23173                    }
23174                } else {
23175                    let mut end_row = hunk_display_end.row();
23176                    if hunk_display_end.column() > 0 {
23177                        end_row.0 += 1;
23178                    }
23179                    let is_created_file = hunk.is_created_file();
23180                    DisplayDiffHunk::Unfolded {
23181                        status: hunk.status(),
23182                        diff_base_byte_range: hunk.diff_base_byte_range,
23183                        display_row_range: hunk_display_start.row()..end_row,
23184                        multi_buffer_range: Anchor::range_in_buffer(
23185                            hunk.excerpt_id,
23186                            hunk.buffer_id,
23187                            hunk.buffer_range,
23188                        ),
23189                        is_created_file,
23190                    }
23191                };
23192
23193                Some(display_hunk)
23194            })
23195    }
23196
23197    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23198        self.display_snapshot.buffer_snapshot.language_at(position)
23199    }
23200
23201    pub fn is_focused(&self) -> bool {
23202        self.is_focused
23203    }
23204
23205    pub fn placeholder_text(&self) -> Option<String> {
23206        self.placeholder_display_snapshot
23207            .as_ref()
23208            .map(|display_map| display_map.text())
23209    }
23210
23211    pub fn scroll_position(&self) -> gpui::Point<f32> {
23212        self.scroll_anchor.scroll_position(&self.display_snapshot)
23213    }
23214
23215    fn gutter_dimensions(
23216        &self,
23217        font_id: FontId,
23218        font_size: Pixels,
23219        max_line_number_width: Pixels,
23220        cx: &App,
23221    ) -> Option<GutterDimensions> {
23222        if !self.show_gutter {
23223            return None;
23224        }
23225
23226        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23227        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23228
23229        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23230            matches!(
23231                ProjectSettings::get_global(cx).git.git_gutter,
23232                GitGutterSetting::TrackedFiles
23233            )
23234        });
23235        let gutter_settings = EditorSettings::get_global(cx).gutter;
23236        let show_line_numbers = self
23237            .show_line_numbers
23238            .unwrap_or(gutter_settings.line_numbers);
23239        let line_gutter_width = if show_line_numbers {
23240            // Avoid flicker-like gutter resizes when the line number gains another digit by
23241            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23242            let min_width_for_number_on_gutter =
23243                ch_advance * gutter_settings.min_line_number_digits as f32;
23244            max_line_number_width.max(min_width_for_number_on_gutter)
23245        } else {
23246            0.0.into()
23247        };
23248
23249        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23250        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23251
23252        let git_blame_entries_width =
23253            self.git_blame_gutter_max_author_length
23254                .map(|max_author_length| {
23255                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23256                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23257
23258                    /// The number of characters to dedicate to gaps and margins.
23259                    const SPACING_WIDTH: usize = 4;
23260
23261                    let max_char_count = max_author_length.min(renderer.max_author_length())
23262                        + ::git::SHORT_SHA_LENGTH
23263                        + MAX_RELATIVE_TIMESTAMP.len()
23264                        + SPACING_WIDTH;
23265
23266                    ch_advance * max_char_count
23267                });
23268
23269        let is_singleton = self.buffer_snapshot.is_singleton();
23270
23271        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23272        left_padding += if !is_singleton {
23273            ch_width * 4.0
23274        } else if show_runnables || show_breakpoints {
23275            ch_width * 3.0
23276        } else if show_git_gutter && show_line_numbers {
23277            ch_width * 2.0
23278        } else if show_git_gutter || show_line_numbers {
23279            ch_width
23280        } else {
23281            px(0.)
23282        };
23283
23284        let shows_folds = is_singleton && gutter_settings.folds;
23285
23286        let right_padding = if shows_folds && show_line_numbers {
23287            ch_width * 4.0
23288        } else if shows_folds || (!is_singleton && show_line_numbers) {
23289            ch_width * 3.0
23290        } else if show_line_numbers {
23291            ch_width
23292        } else {
23293            px(0.)
23294        };
23295
23296        Some(GutterDimensions {
23297            left_padding,
23298            right_padding,
23299            width: line_gutter_width + left_padding + right_padding,
23300            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23301            git_blame_entries_width,
23302        })
23303    }
23304
23305    pub fn render_crease_toggle(
23306        &self,
23307        buffer_row: MultiBufferRow,
23308        row_contains_cursor: bool,
23309        editor: Entity<Editor>,
23310        window: &mut Window,
23311        cx: &mut App,
23312    ) -> Option<AnyElement> {
23313        let folded = self.is_line_folded(buffer_row);
23314        let mut is_foldable = false;
23315
23316        if let Some(crease) = self
23317            .crease_snapshot
23318            .query_row(buffer_row, &self.buffer_snapshot)
23319        {
23320            is_foldable = true;
23321            match crease {
23322                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23323                    if let Some(render_toggle) = render_toggle {
23324                        let toggle_callback =
23325                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23326                                if folded {
23327                                    editor.update(cx, |editor, cx| {
23328                                        editor.fold_at(buffer_row, window, cx)
23329                                    });
23330                                } else {
23331                                    editor.update(cx, |editor, cx| {
23332                                        editor.unfold_at(buffer_row, window, cx)
23333                                    });
23334                                }
23335                            });
23336                        return Some((render_toggle)(
23337                            buffer_row,
23338                            folded,
23339                            toggle_callback,
23340                            window,
23341                            cx,
23342                        ));
23343                    }
23344                }
23345            }
23346        }
23347
23348        is_foldable |= self.starts_indent(buffer_row);
23349
23350        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23351            Some(
23352                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23353                    .toggle_state(folded)
23354                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23355                        if folded {
23356                            this.unfold_at(buffer_row, window, cx);
23357                        } else {
23358                            this.fold_at(buffer_row, window, cx);
23359                        }
23360                    }))
23361                    .into_any_element(),
23362            )
23363        } else {
23364            None
23365        }
23366    }
23367
23368    pub fn render_crease_trailer(
23369        &self,
23370        buffer_row: MultiBufferRow,
23371        window: &mut Window,
23372        cx: &mut App,
23373    ) -> Option<AnyElement> {
23374        let folded = self.is_line_folded(buffer_row);
23375        if let Crease::Inline { render_trailer, .. } = self
23376            .crease_snapshot
23377            .query_row(buffer_row, &self.buffer_snapshot)?
23378        {
23379            let render_trailer = render_trailer.as_ref()?;
23380            Some(render_trailer(buffer_row, folded, window, cx))
23381        } else {
23382            None
23383        }
23384    }
23385}
23386
23387impl Deref for EditorSnapshot {
23388    type Target = DisplaySnapshot;
23389
23390    fn deref(&self) -> &Self::Target {
23391        &self.display_snapshot
23392    }
23393}
23394
23395#[derive(Clone, Debug, PartialEq, Eq)]
23396pub enum EditorEvent {
23397    InputIgnored {
23398        text: Arc<str>,
23399    },
23400    InputHandled {
23401        utf16_range_to_replace: Option<Range<isize>>,
23402        text: Arc<str>,
23403    },
23404    ExcerptsAdded {
23405        buffer: Entity<Buffer>,
23406        predecessor: ExcerptId,
23407        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23408    },
23409    ExcerptsRemoved {
23410        ids: Vec<ExcerptId>,
23411        removed_buffer_ids: Vec<BufferId>,
23412    },
23413    BufferFoldToggled {
23414        ids: Vec<ExcerptId>,
23415        folded: bool,
23416    },
23417    ExcerptsEdited {
23418        ids: Vec<ExcerptId>,
23419    },
23420    ExcerptsExpanded {
23421        ids: Vec<ExcerptId>,
23422    },
23423    BufferEdited,
23424    Edited {
23425        transaction_id: clock::Lamport,
23426    },
23427    Reparsed(BufferId),
23428    Focused,
23429    FocusedIn,
23430    Blurred,
23431    DirtyChanged,
23432    Saved,
23433    TitleChanged,
23434    SelectionsChanged {
23435        local: bool,
23436    },
23437    ScrollPositionChanged {
23438        local: bool,
23439        autoscroll: bool,
23440    },
23441    TransactionUndone {
23442        transaction_id: clock::Lamport,
23443    },
23444    TransactionBegun {
23445        transaction_id: clock::Lamport,
23446    },
23447    CursorShapeChanged,
23448    BreadcrumbsChanged,
23449    PushedToNavHistory {
23450        anchor: Anchor,
23451        is_deactivate: bool,
23452    },
23453}
23454
23455impl EventEmitter<EditorEvent> for Editor {}
23456
23457impl Focusable for Editor {
23458    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23459        self.focus_handle.clone()
23460    }
23461}
23462
23463impl Render for Editor {
23464    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23465        let settings = ThemeSettings::get_global(cx);
23466
23467        let mut text_style = match self.mode {
23468            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23469                color: cx.theme().colors().editor_foreground,
23470                font_family: settings.ui_font.family.clone(),
23471                font_features: settings.ui_font.features.clone(),
23472                font_fallbacks: settings.ui_font.fallbacks.clone(),
23473                font_size: rems(0.875).into(),
23474                font_weight: settings.ui_font.weight,
23475                line_height: relative(settings.buffer_line_height.value()),
23476                ..Default::default()
23477            },
23478            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23479                color: cx.theme().colors().editor_foreground,
23480                font_family: settings.buffer_font.family.clone(),
23481                font_features: settings.buffer_font.features.clone(),
23482                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23483                font_size: settings.buffer_font_size(cx).into(),
23484                font_weight: settings.buffer_font.weight,
23485                line_height: relative(settings.buffer_line_height.value()),
23486                ..Default::default()
23487            },
23488        };
23489        if let Some(text_style_refinement) = &self.text_style_refinement {
23490            text_style.refine(text_style_refinement)
23491        }
23492
23493        let background = match self.mode {
23494            EditorMode::SingleLine => cx.theme().system().transparent,
23495            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23496            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23497            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23498        };
23499
23500        EditorElement::new(
23501            &cx.entity(),
23502            EditorStyle {
23503                background,
23504                border: cx.theme().colors().border,
23505                local_player: cx.theme().players().local(),
23506                text: text_style,
23507                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23508                syntax: cx.theme().syntax().clone(),
23509                status: cx.theme().status().clone(),
23510                inlay_hints_style: make_inlay_hints_style(cx),
23511                edit_prediction_styles: make_suggestion_styles(cx),
23512                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23513                show_underlines: self.diagnostics_enabled(),
23514            },
23515        )
23516    }
23517}
23518
23519impl EntityInputHandler for Editor {
23520    fn text_for_range(
23521        &mut self,
23522        range_utf16: Range<usize>,
23523        adjusted_range: &mut Option<Range<usize>>,
23524        _: &mut Window,
23525        cx: &mut Context<Self>,
23526    ) -> Option<String> {
23527        let snapshot = self.buffer.read(cx).read(cx);
23528        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23529        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23530        if (start.0..end.0) != range_utf16 {
23531            adjusted_range.replace(start.0..end.0);
23532        }
23533        Some(snapshot.text_for_range(start..end).collect())
23534    }
23535
23536    fn selected_text_range(
23537        &mut self,
23538        ignore_disabled_input: bool,
23539        _: &mut Window,
23540        cx: &mut Context<Self>,
23541    ) -> Option<UTF16Selection> {
23542        // Prevent the IME menu from appearing when holding down an alphabetic key
23543        // while input is disabled.
23544        if !ignore_disabled_input && !self.input_enabled {
23545            return None;
23546        }
23547
23548        let selection = self.selections.newest::<OffsetUtf16>(cx);
23549        let range = selection.range();
23550
23551        Some(UTF16Selection {
23552            range: range.start.0..range.end.0,
23553            reversed: selection.reversed,
23554        })
23555    }
23556
23557    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23558        let snapshot = self.buffer.read(cx).read(cx);
23559        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23560        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23561    }
23562
23563    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23564        self.clear_highlights::<InputComposition>(cx);
23565        self.ime_transaction.take();
23566    }
23567
23568    fn replace_text_in_range(
23569        &mut self,
23570        range_utf16: Option<Range<usize>>,
23571        text: &str,
23572        window: &mut Window,
23573        cx: &mut Context<Self>,
23574    ) {
23575        if !self.input_enabled {
23576            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23577            return;
23578        }
23579
23580        self.transact(window, cx, |this, window, cx| {
23581            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23582                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23583                Some(this.selection_replacement_ranges(range_utf16, cx))
23584            } else {
23585                this.marked_text_ranges(cx)
23586            };
23587
23588            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23589                let newest_selection_id = this.selections.newest_anchor().id;
23590                this.selections
23591                    .all::<OffsetUtf16>(cx)
23592                    .iter()
23593                    .zip(ranges_to_replace.iter())
23594                    .find_map(|(selection, range)| {
23595                        if selection.id == newest_selection_id {
23596                            Some(
23597                                (range.start.0 as isize - selection.head().0 as isize)
23598                                    ..(range.end.0 as isize - selection.head().0 as isize),
23599                            )
23600                        } else {
23601                            None
23602                        }
23603                    })
23604            });
23605
23606            cx.emit(EditorEvent::InputHandled {
23607                utf16_range_to_replace: range_to_replace,
23608                text: text.into(),
23609            });
23610
23611            if let Some(new_selected_ranges) = new_selected_ranges {
23612                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23613                    selections.select_ranges(new_selected_ranges)
23614                });
23615                this.backspace(&Default::default(), window, cx);
23616            }
23617
23618            this.handle_input(text, window, cx);
23619        });
23620
23621        if let Some(transaction) = self.ime_transaction {
23622            self.buffer.update(cx, |buffer, cx| {
23623                buffer.group_until_transaction(transaction, cx);
23624            });
23625        }
23626
23627        self.unmark_text(window, cx);
23628    }
23629
23630    fn replace_and_mark_text_in_range(
23631        &mut self,
23632        range_utf16: Option<Range<usize>>,
23633        text: &str,
23634        new_selected_range_utf16: Option<Range<usize>>,
23635        window: &mut Window,
23636        cx: &mut Context<Self>,
23637    ) {
23638        if !self.input_enabled {
23639            return;
23640        }
23641
23642        let transaction = self.transact(window, cx, |this, window, cx| {
23643            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23644                let snapshot = this.buffer.read(cx).read(cx);
23645                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23646                    for marked_range in &mut marked_ranges {
23647                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23648                        marked_range.start.0 += relative_range_utf16.start;
23649                        marked_range.start =
23650                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23651                        marked_range.end =
23652                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23653                    }
23654                }
23655                Some(marked_ranges)
23656            } else if let Some(range_utf16) = range_utf16 {
23657                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23658                Some(this.selection_replacement_ranges(range_utf16, cx))
23659            } else {
23660                None
23661            };
23662
23663            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23664                let newest_selection_id = this.selections.newest_anchor().id;
23665                this.selections
23666                    .all::<OffsetUtf16>(cx)
23667                    .iter()
23668                    .zip(ranges_to_replace.iter())
23669                    .find_map(|(selection, range)| {
23670                        if selection.id == newest_selection_id {
23671                            Some(
23672                                (range.start.0 as isize - selection.head().0 as isize)
23673                                    ..(range.end.0 as isize - selection.head().0 as isize),
23674                            )
23675                        } else {
23676                            None
23677                        }
23678                    })
23679            });
23680
23681            cx.emit(EditorEvent::InputHandled {
23682                utf16_range_to_replace: range_to_replace,
23683                text: text.into(),
23684            });
23685
23686            if let Some(ranges) = ranges_to_replace {
23687                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23688                    s.select_ranges(ranges)
23689                });
23690            }
23691
23692            let marked_ranges = {
23693                let snapshot = this.buffer.read(cx).read(cx);
23694                this.selections
23695                    .disjoint_anchors_arc()
23696                    .iter()
23697                    .map(|selection| {
23698                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23699                    })
23700                    .collect::<Vec<_>>()
23701            };
23702
23703            if text.is_empty() {
23704                this.unmark_text(window, cx);
23705            } else {
23706                this.highlight_text::<InputComposition>(
23707                    marked_ranges.clone(),
23708                    HighlightStyle {
23709                        underline: Some(UnderlineStyle {
23710                            thickness: px(1.),
23711                            color: None,
23712                            wavy: false,
23713                        }),
23714                        ..Default::default()
23715                    },
23716                    cx,
23717                );
23718            }
23719
23720            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23721            let use_autoclose = this.use_autoclose;
23722            let use_auto_surround = this.use_auto_surround;
23723            this.set_use_autoclose(false);
23724            this.set_use_auto_surround(false);
23725            this.handle_input(text, window, cx);
23726            this.set_use_autoclose(use_autoclose);
23727            this.set_use_auto_surround(use_auto_surround);
23728
23729            if let Some(new_selected_range) = new_selected_range_utf16 {
23730                let snapshot = this.buffer.read(cx).read(cx);
23731                let new_selected_ranges = marked_ranges
23732                    .into_iter()
23733                    .map(|marked_range| {
23734                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23735                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23736                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23737                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23738                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23739                    })
23740                    .collect::<Vec<_>>();
23741
23742                drop(snapshot);
23743                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23744                    selections.select_ranges(new_selected_ranges)
23745                });
23746            }
23747        });
23748
23749        self.ime_transaction = self.ime_transaction.or(transaction);
23750        if let Some(transaction) = self.ime_transaction {
23751            self.buffer.update(cx, |buffer, cx| {
23752                buffer.group_until_transaction(transaction, cx);
23753            });
23754        }
23755
23756        if self.text_highlights::<InputComposition>(cx).is_none() {
23757            self.ime_transaction.take();
23758        }
23759    }
23760
23761    fn bounds_for_range(
23762        &mut self,
23763        range_utf16: Range<usize>,
23764        element_bounds: gpui::Bounds<Pixels>,
23765        window: &mut Window,
23766        cx: &mut Context<Self>,
23767    ) -> Option<gpui::Bounds<Pixels>> {
23768        let text_layout_details = self.text_layout_details(window);
23769        let CharacterDimensions {
23770            em_width,
23771            em_advance,
23772            line_height,
23773        } = self.character_dimensions(window);
23774
23775        let snapshot = self.snapshot(window, cx);
23776        let scroll_position = snapshot.scroll_position();
23777        let scroll_left = scroll_position.x * em_advance;
23778
23779        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23780        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23781            + self.gutter_dimensions.full_width();
23782        let y = line_height * (start.row().as_f32() - scroll_position.y);
23783
23784        Some(Bounds {
23785            origin: element_bounds.origin + point(x, y),
23786            size: size(em_width, line_height),
23787        })
23788    }
23789
23790    fn character_index_for_point(
23791        &mut self,
23792        point: gpui::Point<Pixels>,
23793        _window: &mut Window,
23794        _cx: &mut Context<Self>,
23795    ) -> Option<usize> {
23796        let position_map = self.last_position_map.as_ref()?;
23797        if !position_map.text_hitbox.contains(&point) {
23798            return None;
23799        }
23800        let display_point = position_map.point_for_position(point).previous_valid;
23801        let anchor = position_map
23802            .snapshot
23803            .display_point_to_anchor(display_point, Bias::Left);
23804        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23805        Some(utf16_offset.0)
23806    }
23807}
23808
23809trait SelectionExt {
23810    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23811    fn spanned_rows(
23812        &self,
23813        include_end_if_at_line_start: bool,
23814        map: &DisplaySnapshot,
23815    ) -> Range<MultiBufferRow>;
23816}
23817
23818impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23819    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23820        let start = self
23821            .start
23822            .to_point(&map.buffer_snapshot)
23823            .to_display_point(map);
23824        let end = self
23825            .end
23826            .to_point(&map.buffer_snapshot)
23827            .to_display_point(map);
23828        if self.reversed {
23829            end..start
23830        } else {
23831            start..end
23832        }
23833    }
23834
23835    fn spanned_rows(
23836        &self,
23837        include_end_if_at_line_start: bool,
23838        map: &DisplaySnapshot,
23839    ) -> Range<MultiBufferRow> {
23840        let start = self.start.to_point(&map.buffer_snapshot);
23841        let mut end = self.end.to_point(&map.buffer_snapshot);
23842        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23843            end.row -= 1;
23844        }
23845
23846        let buffer_start = map.prev_line_boundary(start).0;
23847        let buffer_end = map.next_line_boundary(end).0;
23848        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23849    }
23850}
23851
23852impl<T: InvalidationRegion> InvalidationStack<T> {
23853    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23854    where
23855        S: Clone + ToOffset,
23856    {
23857        while let Some(region) = self.last() {
23858            let all_selections_inside_invalidation_ranges =
23859                if selections.len() == region.ranges().len() {
23860                    selections
23861                        .iter()
23862                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23863                        .all(|(selection, invalidation_range)| {
23864                            let head = selection.head().to_offset(buffer);
23865                            invalidation_range.start <= head && invalidation_range.end >= head
23866                        })
23867                } else {
23868                    false
23869                };
23870
23871            if all_selections_inside_invalidation_ranges {
23872                break;
23873            } else {
23874                self.pop();
23875            }
23876        }
23877    }
23878}
23879
23880impl<T> Default for InvalidationStack<T> {
23881    fn default() -> Self {
23882        Self(Default::default())
23883    }
23884}
23885
23886impl<T> Deref for InvalidationStack<T> {
23887    type Target = Vec<T>;
23888
23889    fn deref(&self) -> &Self::Target {
23890        &self.0
23891    }
23892}
23893
23894impl<T> DerefMut for InvalidationStack<T> {
23895    fn deref_mut(&mut self) -> &mut Self::Target {
23896        &mut self.0
23897    }
23898}
23899
23900impl InvalidationRegion for SnippetState {
23901    fn ranges(&self) -> &[Range<Anchor>] {
23902        &self.ranges[self.active_index]
23903    }
23904}
23905
23906fn edit_prediction_edit_text(
23907    current_snapshot: &BufferSnapshot,
23908    edits: &[(Range<Anchor>, String)],
23909    edit_preview: &EditPreview,
23910    include_deletions: bool,
23911    cx: &App,
23912) -> HighlightedText {
23913    let edits = edits
23914        .iter()
23915        .map(|(anchor, text)| {
23916            (
23917                anchor.start.text_anchor..anchor.end.text_anchor,
23918                text.clone(),
23919            )
23920        })
23921        .collect::<Vec<_>>();
23922
23923    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23924}
23925
23926fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23927    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23928    // Just show the raw edit text with basic styling
23929    let mut text = String::new();
23930    let mut highlights = Vec::new();
23931
23932    let insertion_highlight_style = HighlightStyle {
23933        color: Some(cx.theme().colors().text),
23934        ..Default::default()
23935    };
23936
23937    for (_, edit_text) in edits {
23938        let start_offset = text.len();
23939        text.push_str(edit_text);
23940        let end_offset = text.len();
23941
23942        if start_offset < end_offset {
23943            highlights.push((start_offset..end_offset, insertion_highlight_style));
23944        }
23945    }
23946
23947    HighlightedText {
23948        text: text.into(),
23949        highlights,
23950    }
23951}
23952
23953pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23954    match severity {
23955        lsp::DiagnosticSeverity::ERROR => colors.error,
23956        lsp::DiagnosticSeverity::WARNING => colors.warning,
23957        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23958        lsp::DiagnosticSeverity::HINT => colors.info,
23959        _ => colors.ignored,
23960    }
23961}
23962
23963pub fn styled_runs_for_code_label<'a>(
23964    label: &'a CodeLabel,
23965    syntax_theme: &'a theme::SyntaxTheme,
23966) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23967    let fade_out = HighlightStyle {
23968        fade_out: Some(0.35),
23969        ..Default::default()
23970    };
23971
23972    let mut prev_end = label.filter_range.end;
23973    label
23974        .runs
23975        .iter()
23976        .enumerate()
23977        .flat_map(move |(ix, (range, highlight_id))| {
23978            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23979                style
23980            } else {
23981                return Default::default();
23982            };
23983            let muted_style = style.highlight(fade_out);
23984
23985            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23986            if range.start >= label.filter_range.end {
23987                if range.start > prev_end {
23988                    runs.push((prev_end..range.start, fade_out));
23989                }
23990                runs.push((range.clone(), muted_style));
23991            } else if range.end <= label.filter_range.end {
23992                runs.push((range.clone(), style));
23993            } else {
23994                runs.push((range.start..label.filter_range.end, style));
23995                runs.push((label.filter_range.end..range.end, muted_style));
23996            }
23997            prev_end = cmp::max(prev_end, range.end);
23998
23999            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24000                runs.push((prev_end..label.text.len(), fade_out));
24001            }
24002
24003            runs
24004        })
24005}
24006
24007pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24008    let mut prev_index = 0;
24009    let mut prev_codepoint: Option<char> = None;
24010    text.char_indices()
24011        .chain([(text.len(), '\0')])
24012        .filter_map(move |(index, codepoint)| {
24013            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24014            let is_boundary = index == text.len()
24015                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24016                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24017            if is_boundary {
24018                let chunk = &text[prev_index..index];
24019                prev_index = index;
24020                Some(chunk)
24021            } else {
24022                None
24023            }
24024        })
24025}
24026
24027pub trait RangeToAnchorExt: Sized {
24028    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24029
24030    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24031        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24032        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24033    }
24034}
24035
24036impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24037    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24038        let start_offset = self.start.to_offset(snapshot);
24039        let end_offset = self.end.to_offset(snapshot);
24040        if start_offset == end_offset {
24041            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24042        } else {
24043            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24044        }
24045    }
24046}
24047
24048pub trait RowExt {
24049    fn as_f32(&self) -> f32;
24050
24051    fn next_row(&self) -> Self;
24052
24053    fn previous_row(&self) -> Self;
24054
24055    fn minus(&self, other: Self) -> u32;
24056}
24057
24058impl RowExt for DisplayRow {
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
24076impl RowExt for MultiBufferRow {
24077    fn as_f32(&self) -> f32 {
24078        self.0 as f32
24079    }
24080
24081    fn next_row(&self) -> Self {
24082        Self(self.0 + 1)
24083    }
24084
24085    fn previous_row(&self) -> Self {
24086        Self(self.0.saturating_sub(1))
24087    }
24088
24089    fn minus(&self, other: Self) -> u32 {
24090        self.0 - other.0
24091    }
24092}
24093
24094trait RowRangeExt {
24095    type Row;
24096
24097    fn len(&self) -> usize;
24098
24099    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24100}
24101
24102impl RowRangeExt for Range<MultiBufferRow> {
24103    type Row = MultiBufferRow;
24104
24105    fn len(&self) -> usize {
24106        (self.end.0 - self.start.0) as usize
24107    }
24108
24109    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24110        (self.start.0..self.end.0).map(MultiBufferRow)
24111    }
24112}
24113
24114impl RowRangeExt for Range<DisplayRow> {
24115    type Row = DisplayRow;
24116
24117    fn len(&self) -> usize {
24118        (self.end.0 - self.start.0) as usize
24119    }
24120
24121    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24122        (self.start.0..self.end.0).map(DisplayRow)
24123    }
24124}
24125
24126/// If select range has more than one line, we
24127/// just point the cursor to range.start.
24128fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24129    if range.start.row == range.end.row {
24130        range
24131    } else {
24132        range.start..range.start
24133    }
24134}
24135pub struct KillRing(ClipboardItem);
24136impl Global for KillRing {}
24137
24138const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24139
24140enum BreakpointPromptEditAction {
24141    Log,
24142    Condition,
24143    HitCondition,
24144}
24145
24146struct BreakpointPromptEditor {
24147    pub(crate) prompt: Entity<Editor>,
24148    editor: WeakEntity<Editor>,
24149    breakpoint_anchor: Anchor,
24150    breakpoint: Breakpoint,
24151    edit_action: BreakpointPromptEditAction,
24152    block_ids: HashSet<CustomBlockId>,
24153    editor_margins: Arc<Mutex<EditorMargins>>,
24154    _subscriptions: Vec<Subscription>,
24155}
24156
24157impl BreakpointPromptEditor {
24158    const MAX_LINES: u8 = 4;
24159
24160    fn new(
24161        editor: WeakEntity<Editor>,
24162        breakpoint_anchor: Anchor,
24163        breakpoint: Breakpoint,
24164        edit_action: BreakpointPromptEditAction,
24165        window: &mut Window,
24166        cx: &mut Context<Self>,
24167    ) -> Self {
24168        let base_text = match edit_action {
24169            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24170            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24171            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24172        }
24173        .map(|msg| msg.to_string())
24174        .unwrap_or_default();
24175
24176        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24177        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24178
24179        let prompt = cx.new(|cx| {
24180            let mut prompt = Editor::new(
24181                EditorMode::AutoHeight {
24182                    min_lines: 1,
24183                    max_lines: Some(Self::MAX_LINES as usize),
24184                },
24185                buffer,
24186                None,
24187                window,
24188                cx,
24189            );
24190            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24191            prompt.set_show_cursor_when_unfocused(false, cx);
24192            prompt.set_placeholder_text(
24193                match edit_action {
24194                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24195                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24196                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24197                },
24198                window,
24199                cx,
24200            );
24201
24202            prompt
24203        });
24204
24205        Self {
24206            prompt,
24207            editor,
24208            breakpoint_anchor,
24209            breakpoint,
24210            edit_action,
24211            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24212            block_ids: Default::default(),
24213            _subscriptions: vec![],
24214        }
24215    }
24216
24217    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24218        self.block_ids.extend(block_ids)
24219    }
24220
24221    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24222        if let Some(editor) = self.editor.upgrade() {
24223            let message = self
24224                .prompt
24225                .read(cx)
24226                .buffer
24227                .read(cx)
24228                .as_singleton()
24229                .expect("A multi buffer in breakpoint prompt isn't possible")
24230                .read(cx)
24231                .as_rope()
24232                .to_string();
24233
24234            editor.update(cx, |editor, cx| {
24235                editor.edit_breakpoint_at_anchor(
24236                    self.breakpoint_anchor,
24237                    self.breakpoint.clone(),
24238                    match self.edit_action {
24239                        BreakpointPromptEditAction::Log => {
24240                            BreakpointEditAction::EditLogMessage(message.into())
24241                        }
24242                        BreakpointPromptEditAction::Condition => {
24243                            BreakpointEditAction::EditCondition(message.into())
24244                        }
24245                        BreakpointPromptEditAction::HitCondition => {
24246                            BreakpointEditAction::EditHitCondition(message.into())
24247                        }
24248                    },
24249                    cx,
24250                );
24251
24252                editor.remove_blocks(self.block_ids.clone(), None, cx);
24253                cx.focus_self(window);
24254            });
24255        }
24256    }
24257
24258    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24259        self.editor
24260            .update(cx, |editor, cx| {
24261                editor.remove_blocks(self.block_ids.clone(), None, cx);
24262                window.focus(&editor.focus_handle);
24263            })
24264            .log_err();
24265    }
24266
24267    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24268        let settings = ThemeSettings::get_global(cx);
24269        let text_style = TextStyle {
24270            color: if self.prompt.read(cx).read_only(cx) {
24271                cx.theme().colors().text_disabled
24272            } else {
24273                cx.theme().colors().text
24274            },
24275            font_family: settings.buffer_font.family.clone(),
24276            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24277            font_size: settings.buffer_font_size(cx).into(),
24278            font_weight: settings.buffer_font.weight,
24279            line_height: relative(settings.buffer_line_height.value()),
24280            ..Default::default()
24281        };
24282        EditorElement::new(
24283            &self.prompt,
24284            EditorStyle {
24285                background: cx.theme().colors().editor_background,
24286                local_player: cx.theme().players().local(),
24287                text: text_style,
24288                ..Default::default()
24289            },
24290        )
24291    }
24292}
24293
24294impl Render for BreakpointPromptEditor {
24295    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24296        let editor_margins = *self.editor_margins.lock();
24297        let gutter_dimensions = editor_margins.gutter;
24298        h_flex()
24299            .key_context("Editor")
24300            .bg(cx.theme().colors().editor_background)
24301            .border_y_1()
24302            .border_color(cx.theme().status().info_border)
24303            .size_full()
24304            .py(window.line_height() / 2.5)
24305            .on_action(cx.listener(Self::confirm))
24306            .on_action(cx.listener(Self::cancel))
24307            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24308            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24309    }
24310}
24311
24312impl Focusable for BreakpointPromptEditor {
24313    fn focus_handle(&self, cx: &App) -> FocusHandle {
24314        self.prompt.focus_handle(cx)
24315    }
24316}
24317
24318fn all_edits_insertions_or_deletions(
24319    edits: &Vec<(Range<Anchor>, String)>,
24320    snapshot: &MultiBufferSnapshot,
24321) -> bool {
24322    let mut all_insertions = true;
24323    let mut all_deletions = true;
24324
24325    for (range, new_text) in edits.iter() {
24326        let range_is_empty = range.to_offset(snapshot).is_empty();
24327        let text_is_empty = new_text.is_empty();
24328
24329        if range_is_empty != text_is_empty {
24330            if range_is_empty {
24331                all_deletions = false;
24332            } else {
24333                all_insertions = false;
24334            }
24335        } else {
24336            return false;
24337        }
24338
24339        if !all_insertions && !all_deletions {
24340            return false;
24341        }
24342    }
24343    all_insertions || all_deletions
24344}
24345
24346struct MissingEditPredictionKeybindingTooltip;
24347
24348impl Render for MissingEditPredictionKeybindingTooltip {
24349    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24350        ui::tooltip_container(window, cx, |container, _, cx| {
24351            container
24352                .flex_shrink_0()
24353                .max_w_80()
24354                .min_h(rems_from_px(124.))
24355                .justify_between()
24356                .child(
24357                    v_flex()
24358                        .flex_1()
24359                        .text_ui_sm(cx)
24360                        .child(Label::new("Conflict with Accept Keybinding"))
24361                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24362                )
24363                .child(
24364                    h_flex()
24365                        .pb_1()
24366                        .gap_1()
24367                        .items_end()
24368                        .w_full()
24369                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24370                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24371                        }))
24372                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24373                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24374                        })),
24375                )
24376        })
24377    }
24378}
24379
24380#[derive(Debug, Clone, Copy, PartialEq)]
24381pub struct LineHighlight {
24382    pub background: Background,
24383    pub border: Option<gpui::Hsla>,
24384    pub include_gutter: bool,
24385    pub type_id: Option<TypeId>,
24386}
24387
24388struct LineManipulationResult {
24389    pub new_text: String,
24390    pub line_count_before: usize,
24391    pub line_count_after: usize,
24392}
24393
24394fn render_diff_hunk_controls(
24395    row: u32,
24396    status: &DiffHunkStatus,
24397    hunk_range: Range<Anchor>,
24398    is_created_file: bool,
24399    line_height: Pixels,
24400    editor: &Entity<Editor>,
24401    _window: &mut Window,
24402    cx: &mut App,
24403) -> AnyElement {
24404    h_flex()
24405        .h(line_height)
24406        .mr_1()
24407        .gap_1()
24408        .px_0p5()
24409        .pb_1()
24410        .border_x_1()
24411        .border_b_1()
24412        .border_color(cx.theme().colors().border_variant)
24413        .rounded_b_lg()
24414        .bg(cx.theme().colors().editor_background)
24415        .gap_1()
24416        .block_mouse_except_scroll()
24417        .shadow_md()
24418        .child(if status.has_secondary_hunk() {
24419            Button::new(("stage", row as u64), "Stage")
24420                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24421                .tooltip({
24422                    let focus_handle = editor.focus_handle(cx);
24423                    move |window, cx| {
24424                        Tooltip::for_action_in(
24425                            "Stage Hunk",
24426                            &::git::ToggleStaged,
24427                            &focus_handle,
24428                            window,
24429                            cx,
24430                        )
24431                    }
24432                })
24433                .on_click({
24434                    let editor = editor.clone();
24435                    move |_event, _window, cx| {
24436                        editor.update(cx, |editor, cx| {
24437                            editor.stage_or_unstage_diff_hunks(
24438                                true,
24439                                vec![hunk_range.start..hunk_range.start],
24440                                cx,
24441                            );
24442                        });
24443                    }
24444                })
24445        } else {
24446            Button::new(("unstage", row as u64), "Unstage")
24447                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24448                .tooltip({
24449                    let focus_handle = editor.focus_handle(cx);
24450                    move |window, cx| {
24451                        Tooltip::for_action_in(
24452                            "Unstage Hunk",
24453                            &::git::ToggleStaged,
24454                            &focus_handle,
24455                            window,
24456                            cx,
24457                        )
24458                    }
24459                })
24460                .on_click({
24461                    let editor = editor.clone();
24462                    move |_event, _window, cx| {
24463                        editor.update(cx, |editor, cx| {
24464                            editor.stage_or_unstage_diff_hunks(
24465                                false,
24466                                vec![hunk_range.start..hunk_range.start],
24467                                cx,
24468                            );
24469                        });
24470                    }
24471                })
24472        })
24473        .child(
24474            Button::new(("restore", row as u64), "Restore")
24475                .tooltip({
24476                    let focus_handle = editor.focus_handle(cx);
24477                    move |window, cx| {
24478                        Tooltip::for_action_in(
24479                            "Restore Hunk",
24480                            &::git::Restore,
24481                            &focus_handle,
24482                            window,
24483                            cx,
24484                        )
24485                    }
24486                })
24487                .on_click({
24488                    let editor = editor.clone();
24489                    move |_event, window, cx| {
24490                        editor.update(cx, |editor, cx| {
24491                            let snapshot = editor.snapshot(window, cx);
24492                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24493                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24494                        });
24495                    }
24496                })
24497                .disabled(is_created_file),
24498        )
24499        .when(
24500            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24501            |el| {
24502                el.child(
24503                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24504                        .shape(IconButtonShape::Square)
24505                        .icon_size(IconSize::Small)
24506                        // .disabled(!has_multiple_hunks)
24507                        .tooltip({
24508                            let focus_handle = editor.focus_handle(cx);
24509                            move |window, cx| {
24510                                Tooltip::for_action_in(
24511                                    "Next Hunk",
24512                                    &GoToHunk,
24513                                    &focus_handle,
24514                                    window,
24515                                    cx,
24516                                )
24517                            }
24518                        })
24519                        .on_click({
24520                            let editor = editor.clone();
24521                            move |_event, window, cx| {
24522                                editor.update(cx, |editor, cx| {
24523                                    let snapshot = editor.snapshot(window, cx);
24524                                    let position =
24525                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24526                                    editor.go_to_hunk_before_or_after_position(
24527                                        &snapshot,
24528                                        position,
24529                                        Direction::Next,
24530                                        window,
24531                                        cx,
24532                                    );
24533                                    editor.expand_selected_diff_hunks(cx);
24534                                });
24535                            }
24536                        }),
24537                )
24538                .child(
24539                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24540                        .shape(IconButtonShape::Square)
24541                        .icon_size(IconSize::Small)
24542                        // .disabled(!has_multiple_hunks)
24543                        .tooltip({
24544                            let focus_handle = editor.focus_handle(cx);
24545                            move |window, cx| {
24546                                Tooltip::for_action_in(
24547                                    "Previous Hunk",
24548                                    &GoToPreviousHunk,
24549                                    &focus_handle,
24550                                    window,
24551                                    cx,
24552                                )
24553                            }
24554                        })
24555                        .on_click({
24556                            let editor = editor.clone();
24557                            move |_event, window, cx| {
24558                                editor.update(cx, |editor, cx| {
24559                                    let snapshot = editor.snapshot(window, cx);
24560                                    let point =
24561                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24562                                    editor.go_to_hunk_before_or_after_position(
24563                                        &snapshot,
24564                                        point,
24565                                        Direction::Prev,
24566                                        window,
24567                                        cx,
24568                                    );
24569                                    editor.expand_selected_diff_hunks(cx);
24570                                });
24571                            }
24572                        }),
24573                )
24574            },
24575        )
24576        .into_any_element()
24577}
24578
24579pub fn multibuffer_context_lines(cx: &App) -> u32 {
24580    EditorSettings::try_get(cx)
24581        .map(|settings| settings.excerpt_context_lines)
24582        .unwrap_or(2)
24583        .min(32)
24584}