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    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2522        if self.mouse_cursor_hidden {
 2523            self.mouse_cursor_hidden = false;
 2524            cx.notify();
 2525        }
 2526    }
 2527
 2528    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2529        let hide_mouse_cursor = match origin {
 2530            HideMouseCursorOrigin::TypingAction => {
 2531                matches!(
 2532                    self.hide_mouse_mode,
 2533                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2534                )
 2535            }
 2536            HideMouseCursorOrigin::MovementAction => {
 2537                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2538            }
 2539        };
 2540        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2541            self.mouse_cursor_hidden = hide_mouse_cursor;
 2542            cx.notify();
 2543        }
 2544    }
 2545
 2546    pub fn edit_prediction_in_conflict(&self) -> bool {
 2547        if !self.show_edit_predictions_in_menu() {
 2548            return false;
 2549        }
 2550
 2551        let showing_completions = self
 2552            .context_menu
 2553            .borrow()
 2554            .as_ref()
 2555            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2556
 2557        showing_completions
 2558            || self.edit_prediction_requires_modifier()
 2559            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2560            // bindings to insert tab characters.
 2561            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2562    }
 2563
 2564    pub fn accept_edit_prediction_keybind(
 2565        &self,
 2566        accept_partial: bool,
 2567        window: &Window,
 2568        cx: &App,
 2569    ) -> AcceptEditPredictionBinding {
 2570        let key_context = self.key_context_internal(true, window, cx);
 2571        let in_conflict = self.edit_prediction_in_conflict();
 2572
 2573        let bindings = if accept_partial {
 2574            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2575        } else {
 2576            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2577        };
 2578
 2579        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2580        // just the first one.
 2581        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2582            !in_conflict
 2583                || binding
 2584                    .keystrokes()
 2585                    .first()
 2586                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2587        }))
 2588    }
 2589
 2590    pub fn new_file(
 2591        workspace: &mut Workspace,
 2592        _: &workspace::NewFile,
 2593        window: &mut Window,
 2594        cx: &mut Context<Workspace>,
 2595    ) {
 2596        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2597            "Failed to create buffer",
 2598            window,
 2599            cx,
 2600            |e, _, _| match e.error_code() {
 2601                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2602                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2603                e.error_tag("required").unwrap_or("the latest version")
 2604            )),
 2605                _ => None,
 2606            },
 2607        );
 2608    }
 2609
 2610    pub fn new_in_workspace(
 2611        workspace: &mut Workspace,
 2612        window: &mut Window,
 2613        cx: &mut Context<Workspace>,
 2614    ) -> Task<Result<Entity<Editor>>> {
 2615        let project = workspace.project().clone();
 2616        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2617
 2618        cx.spawn_in(window, async move |workspace, cx| {
 2619            let buffer = create.await?;
 2620            workspace.update_in(cx, |workspace, window, cx| {
 2621                let editor =
 2622                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2623                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2624                editor
 2625            })
 2626        })
 2627    }
 2628
 2629    fn new_file_vertical(
 2630        workspace: &mut Workspace,
 2631        _: &workspace::NewFileSplitVertical,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) {
 2635        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2636    }
 2637
 2638    fn new_file_horizontal(
 2639        workspace: &mut Workspace,
 2640        _: &workspace::NewFileSplitHorizontal,
 2641        window: &mut Window,
 2642        cx: &mut Context<Workspace>,
 2643    ) {
 2644        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2645    }
 2646
 2647    fn new_file_in_direction(
 2648        workspace: &mut Workspace,
 2649        direction: SplitDirection,
 2650        window: &mut Window,
 2651        cx: &mut Context<Workspace>,
 2652    ) {
 2653        let project = workspace.project().clone();
 2654        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2655
 2656        cx.spawn_in(window, async move |workspace, cx| {
 2657            let buffer = create.await?;
 2658            workspace.update_in(cx, move |workspace, window, cx| {
 2659                workspace.split_item(
 2660                    direction,
 2661                    Box::new(
 2662                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2663                    ),
 2664                    window,
 2665                    cx,
 2666                )
 2667            })?;
 2668            anyhow::Ok(())
 2669        })
 2670        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2671            match e.error_code() {
 2672                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2673                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2674                e.error_tag("required").unwrap_or("the latest version")
 2675            )),
 2676                _ => None,
 2677            }
 2678        });
 2679    }
 2680
 2681    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2682        self.leader_id
 2683    }
 2684
 2685    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2686        &self.buffer
 2687    }
 2688
 2689    pub fn project(&self) -> Option<&Entity<Project>> {
 2690        self.project.as_ref()
 2691    }
 2692
 2693    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2694        self.workspace.as_ref()?.0.upgrade()
 2695    }
 2696
 2697    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2698        self.buffer().read(cx).title(cx)
 2699    }
 2700
 2701    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2702        let git_blame_gutter_max_author_length = self
 2703            .render_git_blame_gutter(cx)
 2704            .then(|| {
 2705                if let Some(blame) = self.blame.as_ref() {
 2706                    let max_author_length =
 2707                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2708                    Some(max_author_length)
 2709                } else {
 2710                    None
 2711                }
 2712            })
 2713            .flatten();
 2714
 2715        EditorSnapshot {
 2716            mode: self.mode.clone(),
 2717            show_gutter: self.show_gutter,
 2718            show_line_numbers: self.show_line_numbers,
 2719            show_git_diff_gutter: self.show_git_diff_gutter,
 2720            show_code_actions: self.show_code_actions,
 2721            show_runnables: self.show_runnables,
 2722            show_breakpoints: self.show_breakpoints,
 2723            git_blame_gutter_max_author_length,
 2724            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2725            placeholder_display_snapshot: self
 2726                .placeholder_display_map
 2727                .as_ref()
 2728                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2729            scroll_anchor: self.scroll_manager.anchor(),
 2730            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2731            is_focused: self.focus_handle.is_focused(window),
 2732            current_line_highlight: self
 2733                .current_line_highlight
 2734                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2735            gutter_hovered: self.gutter_hovered,
 2736        }
 2737    }
 2738
 2739    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2740        self.buffer.read(cx).language_at(point, cx)
 2741    }
 2742
 2743    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2744        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2745    }
 2746
 2747    pub fn active_excerpt(
 2748        &self,
 2749        cx: &App,
 2750    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2751        self.buffer
 2752            .read(cx)
 2753            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2754    }
 2755
 2756    pub fn mode(&self) -> &EditorMode {
 2757        &self.mode
 2758    }
 2759
 2760    pub fn set_mode(&mut self, mode: EditorMode) {
 2761        self.mode = mode;
 2762    }
 2763
 2764    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2765        self.collaboration_hub.as_deref()
 2766    }
 2767
 2768    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2769        self.collaboration_hub = Some(hub);
 2770    }
 2771
 2772    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2773        self.in_project_search = in_project_search;
 2774    }
 2775
 2776    pub fn set_custom_context_menu(
 2777        &mut self,
 2778        f: impl 'static
 2779        + Fn(
 2780            &mut Self,
 2781            DisplayPoint,
 2782            &mut Window,
 2783            &mut Context<Self>,
 2784        ) -> Option<Entity<ui::ContextMenu>>,
 2785    ) {
 2786        self.custom_context_menu = Some(Box::new(f))
 2787    }
 2788
 2789    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2790        self.completion_provider = provider;
 2791    }
 2792
 2793    #[cfg(any(test, feature = "test-support"))]
 2794    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2795        self.completion_provider.clone()
 2796    }
 2797
 2798    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2799        self.semantics_provider.clone()
 2800    }
 2801
 2802    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2803        self.semantics_provider = provider;
 2804    }
 2805
 2806    pub fn set_edit_prediction_provider<T>(
 2807        &mut self,
 2808        provider: Option<Entity<T>>,
 2809        window: &mut Window,
 2810        cx: &mut Context<Self>,
 2811    ) where
 2812        T: EditPredictionProvider,
 2813    {
 2814        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2815            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2816                if this.focus_handle.is_focused(window) {
 2817                    this.update_visible_edit_prediction(window, cx);
 2818                }
 2819            }),
 2820            provider: Arc::new(provider),
 2821        });
 2822        self.update_edit_prediction_settings(cx);
 2823        self.refresh_edit_prediction(false, false, window, cx);
 2824    }
 2825
 2826    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2827        self.placeholder_display_map
 2828            .as_ref()
 2829            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2830    }
 2831
 2832    pub fn set_placeholder_text(
 2833        &mut self,
 2834        placeholder_text: &str,
 2835        window: &mut Window,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let multibuffer = cx
 2839            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2840
 2841        let style = window.text_style();
 2842
 2843        self.placeholder_display_map = Some(cx.new(|cx| {
 2844            DisplayMap::new(
 2845                multibuffer,
 2846                style.font(),
 2847                style.font_size.to_pixels(window.rem_size()),
 2848                None,
 2849                FILE_HEADER_HEIGHT,
 2850                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2851                Default::default(),
 2852                DiagnosticSeverity::Off,
 2853                cx,
 2854            )
 2855        }));
 2856        cx.notify();
 2857    }
 2858
 2859    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2860        self.cursor_shape = cursor_shape;
 2861
 2862        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2863        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2864
 2865        cx.notify();
 2866    }
 2867
 2868    pub fn set_current_line_highlight(
 2869        &mut self,
 2870        current_line_highlight: Option<CurrentLineHighlight>,
 2871    ) {
 2872        self.current_line_highlight = current_line_highlight;
 2873    }
 2874
 2875    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2876        self.collapse_matches = collapse_matches;
 2877    }
 2878
 2879    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2880        let buffers = self.buffer.read(cx).all_buffers();
 2881        let Some(project) = self.project.as_ref() else {
 2882            return;
 2883        };
 2884        project.update(cx, |project, cx| {
 2885            for buffer in buffers {
 2886                self.registered_buffers
 2887                    .entry(buffer.read(cx).remote_id())
 2888                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2889            }
 2890        })
 2891    }
 2892
 2893    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2894        if self.collapse_matches {
 2895            return range.start..range.start;
 2896        }
 2897        range.clone()
 2898    }
 2899
 2900    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2901        if self.display_map.read(cx).clip_at_line_ends != clip {
 2902            self.display_map
 2903                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2904        }
 2905    }
 2906
 2907    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2908        self.input_enabled = input_enabled;
 2909    }
 2910
 2911    pub fn set_edit_predictions_hidden_for_vim_mode(
 2912        &mut self,
 2913        hidden: bool,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916    ) {
 2917        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2918            self.edit_predictions_hidden_for_vim_mode = hidden;
 2919            if hidden {
 2920                self.update_visible_edit_prediction(window, cx);
 2921            } else {
 2922                self.refresh_edit_prediction(true, false, window, cx);
 2923            }
 2924        }
 2925    }
 2926
 2927    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2928        self.menu_edit_predictions_policy = value;
 2929    }
 2930
 2931    pub fn set_autoindent(&mut self, autoindent: bool) {
 2932        if autoindent {
 2933            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2934        } else {
 2935            self.autoindent_mode = None;
 2936        }
 2937    }
 2938
 2939    pub fn read_only(&self, cx: &App) -> bool {
 2940        self.read_only || self.buffer.read(cx).read_only()
 2941    }
 2942
 2943    pub fn set_read_only(&mut self, read_only: bool) {
 2944        self.read_only = read_only;
 2945    }
 2946
 2947    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2948        self.use_autoclose = autoclose;
 2949    }
 2950
 2951    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2952        self.use_auto_surround = auto_surround;
 2953    }
 2954
 2955    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2956        self.auto_replace_emoji_shortcode = auto_replace;
 2957    }
 2958
 2959    pub fn toggle_edit_predictions(
 2960        &mut self,
 2961        _: &ToggleEditPrediction,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        if self.show_edit_predictions_override.is_some() {
 2966            self.set_show_edit_predictions(None, window, cx);
 2967        } else {
 2968            let show_edit_predictions = !self.edit_predictions_enabled();
 2969            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2970        }
 2971    }
 2972
 2973    pub fn set_show_edit_predictions(
 2974        &mut self,
 2975        show_edit_predictions: Option<bool>,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        self.show_edit_predictions_override = show_edit_predictions;
 2980        self.update_edit_prediction_settings(cx);
 2981
 2982        if let Some(false) = show_edit_predictions {
 2983            self.discard_edit_prediction(false, cx);
 2984        } else {
 2985            self.refresh_edit_prediction(false, true, window, cx);
 2986        }
 2987    }
 2988
 2989    fn edit_predictions_disabled_in_scope(
 2990        &self,
 2991        buffer: &Entity<Buffer>,
 2992        buffer_position: language::Anchor,
 2993        cx: &App,
 2994    ) -> bool {
 2995        let snapshot = buffer.read(cx).snapshot();
 2996        let settings = snapshot.settings_at(buffer_position, cx);
 2997
 2998        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2999            return false;
 3000        };
 3001
 3002        scope.override_name().is_some_and(|scope_name| {
 3003            settings
 3004                .edit_predictions_disabled_in
 3005                .iter()
 3006                .any(|s| s == scope_name)
 3007        })
 3008    }
 3009
 3010    pub fn set_use_modal_editing(&mut self, to: bool) {
 3011        self.use_modal_editing = to;
 3012    }
 3013
 3014    pub fn use_modal_editing(&self) -> bool {
 3015        self.use_modal_editing
 3016    }
 3017
 3018    fn selections_did_change(
 3019        &mut self,
 3020        local: bool,
 3021        old_cursor_position: &Anchor,
 3022        effects: SelectionEffects,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        window.invalidate_character_coordinates();
 3027
 3028        // Copy selections to primary selection buffer
 3029        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3030        if local {
 3031            let selections = self.selections.all::<usize>(cx);
 3032            let buffer_handle = self.buffer.read(cx).read(cx);
 3033
 3034            let mut text = String::new();
 3035            for (index, selection) in selections.iter().enumerate() {
 3036                let text_for_selection = buffer_handle
 3037                    .text_for_range(selection.start..selection.end)
 3038                    .collect::<String>();
 3039
 3040                text.push_str(&text_for_selection);
 3041                if index != selections.len() - 1 {
 3042                    text.push('\n');
 3043                }
 3044            }
 3045
 3046            if !text.is_empty() {
 3047                cx.write_to_primary(ClipboardItem::new_string(text));
 3048            }
 3049        }
 3050
 3051        let selection_anchors = self.selections.disjoint_anchors_arc();
 3052
 3053        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3054            self.buffer.update(cx, |buffer, cx| {
 3055                buffer.set_active_selections(
 3056                    &selection_anchors,
 3057                    self.selections.line_mode,
 3058                    self.cursor_shape,
 3059                    cx,
 3060                )
 3061            });
 3062        }
 3063        let display_map = self
 3064            .display_map
 3065            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3066        let buffer = &display_map.buffer_snapshot;
 3067        if self.selections.count() == 1 {
 3068            self.add_selections_state = None;
 3069        }
 3070        self.select_next_state = None;
 3071        self.select_prev_state = None;
 3072        self.select_syntax_node_history.try_clear();
 3073        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3074        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3075        self.take_rename(false, window, cx);
 3076
 3077        let newest_selection = self.selections.newest_anchor();
 3078        let new_cursor_position = newest_selection.head();
 3079        let selection_start = newest_selection.start;
 3080
 3081        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3082            self.push_to_nav_history(
 3083                *old_cursor_position,
 3084                Some(new_cursor_position.to_point(buffer)),
 3085                false,
 3086                effects.nav_history == Some(true),
 3087                cx,
 3088            );
 3089        }
 3090
 3091        if local {
 3092            if let Some(buffer_id) = new_cursor_position.buffer_id
 3093                && !self.registered_buffers.contains_key(&buffer_id)
 3094                && let Some(project) = self.project.as_ref()
 3095            {
 3096                project.update(cx, |project, cx| {
 3097                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3098                        return;
 3099                    };
 3100                    self.registered_buffers.insert(
 3101                        buffer_id,
 3102                        project.register_buffer_with_language_servers(&buffer, cx),
 3103                    );
 3104                })
 3105            }
 3106
 3107            let mut context_menu = self.context_menu.borrow_mut();
 3108            let completion_menu = match context_menu.as_ref() {
 3109                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3110                Some(CodeContextMenu::CodeActions(_)) => {
 3111                    *context_menu = None;
 3112                    None
 3113                }
 3114                None => None,
 3115            };
 3116            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3117            drop(context_menu);
 3118
 3119            if effects.completions
 3120                && let Some(completion_position) = completion_position
 3121            {
 3122                let start_offset = selection_start.to_offset(buffer);
 3123                let position_matches = start_offset == completion_position.to_offset(buffer);
 3124                let continue_showing = if position_matches {
 3125                    if self.snippet_stack.is_empty() {
 3126                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3127                            == Some(CharKind::Word)
 3128                    } else {
 3129                        // Snippet choices can be shown even when the cursor is in whitespace.
 3130                        // Dismissing the menu with actions like backspace is handled by
 3131                        // invalidation regions.
 3132                        true
 3133                    }
 3134                } else {
 3135                    false
 3136                };
 3137
 3138                if continue_showing {
 3139                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3140                } else {
 3141                    self.hide_context_menu(window, cx);
 3142                }
 3143            }
 3144
 3145            hide_hover(self, cx);
 3146
 3147            if old_cursor_position.to_display_point(&display_map).row()
 3148                != new_cursor_position.to_display_point(&display_map).row()
 3149            {
 3150                self.available_code_actions.take();
 3151            }
 3152            self.refresh_code_actions(window, cx);
 3153            self.refresh_document_highlights(cx);
 3154            self.refresh_selected_text_highlights(false, window, cx);
 3155            refresh_matching_bracket_highlights(self, window, cx);
 3156            self.update_visible_edit_prediction(window, cx);
 3157            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3158            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3159            self.inline_blame_popover.take();
 3160            if self.git_blame_inline_enabled {
 3161                self.start_inline_blame_timer(window, cx);
 3162            }
 3163        }
 3164
 3165        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3166        cx.emit(EditorEvent::SelectionsChanged { local });
 3167
 3168        let selections = &self.selections.disjoint_anchors_arc();
 3169        if selections.len() == 1 {
 3170            cx.emit(SearchEvent::ActiveMatchChanged)
 3171        }
 3172        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3173            let inmemory_selections = selections
 3174                .iter()
 3175                .map(|s| {
 3176                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3177                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3178                })
 3179                .collect();
 3180            self.update_restoration_data(cx, |data| {
 3181                data.selections = inmemory_selections;
 3182            });
 3183
 3184            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3185                && let Some(workspace_id) =
 3186                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3187            {
 3188                let snapshot = self.buffer().read(cx).snapshot(cx);
 3189                let selections = selections.clone();
 3190                let background_executor = cx.background_executor().clone();
 3191                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3192                self.serialize_selections = cx.background_spawn(async move {
 3193                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3194                            let db_selections = selections
 3195                                .iter()
 3196                                .map(|selection| {
 3197                                    (
 3198                                        selection.start.to_offset(&snapshot),
 3199                                        selection.end.to_offset(&snapshot),
 3200                                    )
 3201                                })
 3202                                .collect();
 3203
 3204                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3205                                .await
 3206                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3207                                .log_err();
 3208                        });
 3209            }
 3210        }
 3211
 3212        cx.notify();
 3213    }
 3214
 3215    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3216        use text::ToOffset as _;
 3217        use text::ToPoint as _;
 3218
 3219        if self.mode.is_minimap()
 3220            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3221        {
 3222            return;
 3223        }
 3224
 3225        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3226            return;
 3227        };
 3228
 3229        let snapshot = singleton.read(cx).snapshot();
 3230        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3231            let display_snapshot = display_map.snapshot(cx);
 3232
 3233            display_snapshot
 3234                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3235                .map(|fold| {
 3236                    fold.range.start.text_anchor.to_point(&snapshot)
 3237                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3238                })
 3239                .collect()
 3240        });
 3241        self.update_restoration_data(cx, |data| {
 3242            data.folds = inmemory_folds;
 3243        });
 3244
 3245        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3246            return;
 3247        };
 3248        let background_executor = cx.background_executor().clone();
 3249        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3250        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3251            display_map
 3252                .snapshot(cx)
 3253                .folds_in_range(0..snapshot.len())
 3254                .map(|fold| {
 3255                    (
 3256                        fold.range.start.text_anchor.to_offset(&snapshot),
 3257                        fold.range.end.text_anchor.to_offset(&snapshot),
 3258                    )
 3259                })
 3260                .collect()
 3261        });
 3262        self.serialize_folds = cx.background_spawn(async move {
 3263            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3264            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3265                .await
 3266                .with_context(|| {
 3267                    format!(
 3268                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3269                    )
 3270                })
 3271                .log_err();
 3272        });
 3273    }
 3274
 3275    pub fn sync_selections(
 3276        &mut self,
 3277        other: Entity<Editor>,
 3278        cx: &mut Context<Self>,
 3279    ) -> gpui::Subscription {
 3280        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3281        self.selections.change_with(cx, |selections| {
 3282            selections.select_anchors(other_selections);
 3283        });
 3284
 3285        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3286            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3287                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3288                if other_selections.is_empty() {
 3289                    return;
 3290                }
 3291                this.selections.change_with(cx, |selections| {
 3292                    selections.select_anchors(other_selections);
 3293                });
 3294            }
 3295        });
 3296
 3297        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3298            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3299                let these_selections = this.selections.disjoint_anchors().to_vec();
 3300                if these_selections.is_empty() {
 3301                    return;
 3302                }
 3303                other.update(cx, |other_editor, cx| {
 3304                    other_editor.selections.change_with(cx, |selections| {
 3305                        selections.select_anchors(these_selections);
 3306                    })
 3307                });
 3308            }
 3309        });
 3310
 3311        Subscription::join(other_subscription, this_subscription)
 3312    }
 3313
 3314    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3315    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3316    /// effects of selection change occur at the end of the transaction.
 3317    pub fn change_selections<R>(
 3318        &mut self,
 3319        effects: SelectionEffects,
 3320        window: &mut Window,
 3321        cx: &mut Context<Self>,
 3322        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3323    ) -> R {
 3324        if let Some(state) = &mut self.deferred_selection_effects_state {
 3325            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3326            state.effects.completions = effects.completions;
 3327            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3328            let (changed, result) = self.selections.change_with(cx, change);
 3329            state.changed |= changed;
 3330            return result;
 3331        }
 3332        let mut state = DeferredSelectionEffectsState {
 3333            changed: false,
 3334            effects,
 3335            old_cursor_position: self.selections.newest_anchor().head(),
 3336            history_entry: SelectionHistoryEntry {
 3337                selections: self.selections.disjoint_anchors_arc(),
 3338                select_next_state: self.select_next_state.clone(),
 3339                select_prev_state: self.select_prev_state.clone(),
 3340                add_selections_state: self.add_selections_state.clone(),
 3341            },
 3342        };
 3343        let (changed, result) = self.selections.change_with(cx, change);
 3344        state.changed = state.changed || changed;
 3345        if self.defer_selection_effects {
 3346            self.deferred_selection_effects_state = Some(state);
 3347        } else {
 3348            self.apply_selection_effects(state, window, cx);
 3349        }
 3350        result
 3351    }
 3352
 3353    /// Defers the effects of selection change, so that the effects of multiple calls to
 3354    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3355    /// to selection history and the state of popovers based on selection position aren't
 3356    /// erroneously updated.
 3357    pub fn with_selection_effects_deferred<R>(
 3358        &mut self,
 3359        window: &mut Window,
 3360        cx: &mut Context<Self>,
 3361        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3362    ) -> R {
 3363        let already_deferred = self.defer_selection_effects;
 3364        self.defer_selection_effects = true;
 3365        let result = update(self, window, cx);
 3366        if !already_deferred {
 3367            self.defer_selection_effects = false;
 3368            if let Some(state) = self.deferred_selection_effects_state.take() {
 3369                self.apply_selection_effects(state, window, cx);
 3370            }
 3371        }
 3372        result
 3373    }
 3374
 3375    fn apply_selection_effects(
 3376        &mut self,
 3377        state: DeferredSelectionEffectsState,
 3378        window: &mut Window,
 3379        cx: &mut Context<Self>,
 3380    ) {
 3381        if state.changed {
 3382            self.selection_history.push(state.history_entry);
 3383
 3384            if let Some(autoscroll) = state.effects.scroll {
 3385                self.request_autoscroll(autoscroll, cx);
 3386            }
 3387
 3388            let old_cursor_position = &state.old_cursor_position;
 3389
 3390            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3391
 3392            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3393                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3394            }
 3395        }
 3396    }
 3397
 3398    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3399    where
 3400        I: IntoIterator<Item = (Range<S>, T)>,
 3401        S: ToOffset,
 3402        T: Into<Arc<str>>,
 3403    {
 3404        if self.read_only(cx) {
 3405            return;
 3406        }
 3407
 3408        self.buffer
 3409            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3410    }
 3411
 3412    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3413    where
 3414        I: IntoIterator<Item = (Range<S>, T)>,
 3415        S: ToOffset,
 3416        T: Into<Arc<str>>,
 3417    {
 3418        if self.read_only(cx) {
 3419            return;
 3420        }
 3421
 3422        self.buffer.update(cx, |buffer, cx| {
 3423            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3424        });
 3425    }
 3426
 3427    pub fn edit_with_block_indent<I, S, T>(
 3428        &mut self,
 3429        edits: I,
 3430        original_indent_columns: Vec<Option<u32>>,
 3431        cx: &mut Context<Self>,
 3432    ) where
 3433        I: IntoIterator<Item = (Range<S>, T)>,
 3434        S: ToOffset,
 3435        T: Into<Arc<str>>,
 3436    {
 3437        if self.read_only(cx) {
 3438            return;
 3439        }
 3440
 3441        self.buffer.update(cx, |buffer, cx| {
 3442            buffer.edit(
 3443                edits,
 3444                Some(AutoindentMode::Block {
 3445                    original_indent_columns,
 3446                }),
 3447                cx,
 3448            )
 3449        });
 3450    }
 3451
 3452    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3453        self.hide_context_menu(window, cx);
 3454
 3455        match phase {
 3456            SelectPhase::Begin {
 3457                position,
 3458                add,
 3459                click_count,
 3460            } => self.begin_selection(position, add, click_count, window, cx),
 3461            SelectPhase::BeginColumnar {
 3462                position,
 3463                goal_column,
 3464                reset,
 3465                mode,
 3466            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3467            SelectPhase::Extend {
 3468                position,
 3469                click_count,
 3470            } => self.extend_selection(position, click_count, window, cx),
 3471            SelectPhase::Update {
 3472                position,
 3473                goal_column,
 3474                scroll_delta,
 3475            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3476            SelectPhase::End => self.end_selection(window, cx),
 3477        }
 3478    }
 3479
 3480    fn extend_selection(
 3481        &mut self,
 3482        position: DisplayPoint,
 3483        click_count: usize,
 3484        window: &mut Window,
 3485        cx: &mut Context<Self>,
 3486    ) {
 3487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3488        let tail = self.selections.newest::<usize>(cx).tail();
 3489        self.begin_selection(position, false, click_count, window, cx);
 3490
 3491        let position = position.to_offset(&display_map, Bias::Left);
 3492        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3493
 3494        let mut pending_selection = self
 3495            .selections
 3496            .pending_anchor()
 3497            .cloned()
 3498            .expect("extend_selection not called with pending selection");
 3499        if position >= tail {
 3500            pending_selection.start = tail_anchor;
 3501        } else {
 3502            pending_selection.end = tail_anchor;
 3503            pending_selection.reversed = true;
 3504        }
 3505
 3506        let mut pending_mode = self.selections.pending_mode().unwrap();
 3507        match &mut pending_mode {
 3508            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3509            _ => {}
 3510        }
 3511
 3512        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3513            SelectionEffects::scroll(Autoscroll::fit())
 3514        } else {
 3515            SelectionEffects::no_scroll()
 3516        };
 3517
 3518        self.change_selections(effects, window, cx, |s| {
 3519            s.set_pending(pending_selection.clone(), pending_mode)
 3520        });
 3521    }
 3522
 3523    fn begin_selection(
 3524        &mut self,
 3525        position: DisplayPoint,
 3526        add: bool,
 3527        click_count: usize,
 3528        window: &mut Window,
 3529        cx: &mut Context<Self>,
 3530    ) {
 3531        if !self.focus_handle.is_focused(window) {
 3532            self.last_focused_descendant = None;
 3533            window.focus(&self.focus_handle);
 3534        }
 3535
 3536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3537        let buffer = &display_map.buffer_snapshot;
 3538        let position = display_map.clip_point(position, Bias::Left);
 3539
 3540        let start;
 3541        let end;
 3542        let mode;
 3543        let mut auto_scroll;
 3544        match click_count {
 3545            1 => {
 3546                start = buffer.anchor_before(position.to_point(&display_map));
 3547                end = start;
 3548                mode = SelectMode::Character;
 3549                auto_scroll = true;
 3550            }
 3551            2 => {
 3552                let position = display_map
 3553                    .clip_point(position, Bias::Left)
 3554                    .to_offset(&display_map, Bias::Left);
 3555                let (range, _) = buffer.surrounding_word(position, None);
 3556                start = buffer.anchor_before(range.start);
 3557                end = buffer.anchor_before(range.end);
 3558                mode = SelectMode::Word(start..end);
 3559                auto_scroll = true;
 3560            }
 3561            3 => {
 3562                let position = display_map
 3563                    .clip_point(position, Bias::Left)
 3564                    .to_point(&display_map);
 3565                let line_start = display_map.prev_line_boundary(position).0;
 3566                let next_line_start = buffer.clip_point(
 3567                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3568                    Bias::Left,
 3569                );
 3570                start = buffer.anchor_before(line_start);
 3571                end = buffer.anchor_before(next_line_start);
 3572                mode = SelectMode::Line(start..end);
 3573                auto_scroll = true;
 3574            }
 3575            _ => {
 3576                start = buffer.anchor_before(0);
 3577                end = buffer.anchor_before(buffer.len());
 3578                mode = SelectMode::All;
 3579                auto_scroll = false;
 3580            }
 3581        }
 3582        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3583
 3584        let point_to_delete: Option<usize> = {
 3585            let selected_points: Vec<Selection<Point>> =
 3586                self.selections.disjoint_in_range(start..end, cx);
 3587
 3588            if !add || click_count > 1 {
 3589                None
 3590            } else if !selected_points.is_empty() {
 3591                Some(selected_points[0].id)
 3592            } else {
 3593                let clicked_point_already_selected =
 3594                    self.selections.disjoint_anchors().iter().find(|selection| {
 3595                        selection.start.to_point(buffer) == start.to_point(buffer)
 3596                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3597                    });
 3598
 3599                clicked_point_already_selected.map(|selection| selection.id)
 3600            }
 3601        };
 3602
 3603        let selections_count = self.selections.count();
 3604        let effects = if auto_scroll {
 3605            SelectionEffects::default()
 3606        } else {
 3607            SelectionEffects::no_scroll()
 3608        };
 3609
 3610        self.change_selections(effects, window, cx, |s| {
 3611            if let Some(point_to_delete) = point_to_delete {
 3612                s.delete(point_to_delete);
 3613
 3614                if selections_count == 1 {
 3615                    s.set_pending_anchor_range(start..end, mode);
 3616                }
 3617            } else {
 3618                if !add {
 3619                    s.clear_disjoint();
 3620                }
 3621
 3622                s.set_pending_anchor_range(start..end, mode);
 3623            }
 3624        });
 3625    }
 3626
 3627    fn begin_columnar_selection(
 3628        &mut self,
 3629        position: DisplayPoint,
 3630        goal_column: u32,
 3631        reset: bool,
 3632        mode: ColumnarMode,
 3633        window: &mut Window,
 3634        cx: &mut Context<Self>,
 3635    ) {
 3636        if !self.focus_handle.is_focused(window) {
 3637            self.last_focused_descendant = None;
 3638            window.focus(&self.focus_handle);
 3639        }
 3640
 3641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3642
 3643        if reset {
 3644            let pointer_position = display_map
 3645                .buffer_snapshot
 3646                .anchor_before(position.to_point(&display_map));
 3647
 3648            self.change_selections(
 3649                SelectionEffects::scroll(Autoscroll::newest()),
 3650                window,
 3651                cx,
 3652                |s| {
 3653                    s.clear_disjoint();
 3654                    s.set_pending_anchor_range(
 3655                        pointer_position..pointer_position,
 3656                        SelectMode::Character,
 3657                    );
 3658                },
 3659            );
 3660        };
 3661
 3662        let tail = self.selections.newest::<Point>(cx).tail();
 3663        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3664        self.columnar_selection_state = match mode {
 3665            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3666                selection_tail: selection_anchor,
 3667                display_point: if reset {
 3668                    if position.column() != goal_column {
 3669                        Some(DisplayPoint::new(position.row(), goal_column))
 3670                    } else {
 3671                        None
 3672                    }
 3673                } else {
 3674                    None
 3675                },
 3676            }),
 3677            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3678                selection_tail: selection_anchor,
 3679            }),
 3680        };
 3681
 3682        if !reset {
 3683            self.select_columns(position, goal_column, &display_map, window, cx);
 3684        }
 3685    }
 3686
 3687    fn update_selection(
 3688        &mut self,
 3689        position: DisplayPoint,
 3690        goal_column: u32,
 3691        scroll_delta: gpui::Point<f32>,
 3692        window: &mut Window,
 3693        cx: &mut Context<Self>,
 3694    ) {
 3695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3696
 3697        if self.columnar_selection_state.is_some() {
 3698            self.select_columns(position, goal_column, &display_map, window, cx);
 3699        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3700            let buffer = &display_map.buffer_snapshot;
 3701            let head;
 3702            let tail;
 3703            let mode = self.selections.pending_mode().unwrap();
 3704            match &mode {
 3705                SelectMode::Character => {
 3706                    head = position.to_point(&display_map);
 3707                    tail = pending.tail().to_point(buffer);
 3708                }
 3709                SelectMode::Word(original_range) => {
 3710                    let offset = display_map
 3711                        .clip_point(position, Bias::Left)
 3712                        .to_offset(&display_map, Bias::Left);
 3713                    let original_range = original_range.to_offset(buffer);
 3714
 3715                    let head_offset = if buffer.is_inside_word(offset, None)
 3716                        || original_range.contains(&offset)
 3717                    {
 3718                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3719                        if word_range.start < original_range.start {
 3720                            word_range.start
 3721                        } else {
 3722                            word_range.end
 3723                        }
 3724                    } else {
 3725                        offset
 3726                    };
 3727
 3728                    head = head_offset.to_point(buffer);
 3729                    if head_offset <= original_range.start {
 3730                        tail = original_range.end.to_point(buffer);
 3731                    } else {
 3732                        tail = original_range.start.to_point(buffer);
 3733                    }
 3734                }
 3735                SelectMode::Line(original_range) => {
 3736                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3737
 3738                    let position = display_map
 3739                        .clip_point(position, Bias::Left)
 3740                        .to_point(&display_map);
 3741                    let line_start = display_map.prev_line_boundary(position).0;
 3742                    let next_line_start = buffer.clip_point(
 3743                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3744                        Bias::Left,
 3745                    );
 3746
 3747                    if line_start < original_range.start {
 3748                        head = line_start
 3749                    } else {
 3750                        head = next_line_start
 3751                    }
 3752
 3753                    if head <= original_range.start {
 3754                        tail = original_range.end;
 3755                    } else {
 3756                        tail = original_range.start;
 3757                    }
 3758                }
 3759                SelectMode::All => {
 3760                    return;
 3761                }
 3762            };
 3763
 3764            if head < tail {
 3765                pending.start = buffer.anchor_before(head);
 3766                pending.end = buffer.anchor_before(tail);
 3767                pending.reversed = true;
 3768            } else {
 3769                pending.start = buffer.anchor_before(tail);
 3770                pending.end = buffer.anchor_before(head);
 3771                pending.reversed = false;
 3772            }
 3773
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.set_pending(pending.clone(), mode);
 3776            });
 3777        } else {
 3778            log::error!("update_selection dispatched with no pending selection");
 3779            return;
 3780        }
 3781
 3782        self.apply_scroll_delta(scroll_delta, window, cx);
 3783        cx.notify();
 3784    }
 3785
 3786    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3787        self.columnar_selection_state.take();
 3788        if self.selections.pending_anchor().is_some() {
 3789            let selections = self.selections.all::<usize>(cx);
 3790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3791                s.select(selections);
 3792                s.clear_pending();
 3793            });
 3794        }
 3795    }
 3796
 3797    fn select_columns(
 3798        &mut self,
 3799        head: DisplayPoint,
 3800        goal_column: u32,
 3801        display_map: &DisplaySnapshot,
 3802        window: &mut Window,
 3803        cx: &mut Context<Self>,
 3804    ) {
 3805        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3806            return;
 3807        };
 3808
 3809        let tail = match columnar_state {
 3810            ColumnarSelectionState::FromMouse {
 3811                selection_tail,
 3812                display_point,
 3813            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3814            ColumnarSelectionState::FromSelection { selection_tail } => {
 3815                selection_tail.to_display_point(display_map)
 3816            }
 3817        };
 3818
 3819        let start_row = cmp::min(tail.row(), head.row());
 3820        let end_row = cmp::max(tail.row(), head.row());
 3821        let start_column = cmp::min(tail.column(), goal_column);
 3822        let end_column = cmp::max(tail.column(), goal_column);
 3823        let reversed = start_column < tail.column();
 3824
 3825        let selection_ranges = (start_row.0..=end_row.0)
 3826            .map(DisplayRow)
 3827            .filter_map(|row| {
 3828                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3829                    || start_column <= display_map.line_len(row))
 3830                    && !display_map.is_block_line(row)
 3831                {
 3832                    let start = display_map
 3833                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3834                        .to_point(display_map);
 3835                    let end = display_map
 3836                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3837                        .to_point(display_map);
 3838                    if reversed {
 3839                        Some(end..start)
 3840                    } else {
 3841                        Some(start..end)
 3842                    }
 3843                } else {
 3844                    None
 3845                }
 3846            })
 3847            .collect::<Vec<_>>();
 3848
 3849        let ranges = match columnar_state {
 3850            ColumnarSelectionState::FromMouse { .. } => {
 3851                let mut non_empty_ranges = selection_ranges
 3852                    .iter()
 3853                    .filter(|selection_range| selection_range.start != selection_range.end)
 3854                    .peekable();
 3855                if non_empty_ranges.peek().is_some() {
 3856                    non_empty_ranges.cloned().collect()
 3857                } else {
 3858                    selection_ranges
 3859                }
 3860            }
 3861            _ => selection_ranges,
 3862        };
 3863
 3864        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3865            s.select_ranges(ranges);
 3866        });
 3867        cx.notify();
 3868    }
 3869
 3870    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3871        self.selections
 3872            .all_adjusted(cx)
 3873            .iter()
 3874            .any(|selection| !selection.is_empty())
 3875    }
 3876
 3877    pub fn has_pending_nonempty_selection(&self) -> bool {
 3878        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3879            Some(Selection { start, end, .. }) => start != end,
 3880            None => false,
 3881        };
 3882
 3883        pending_nonempty_selection
 3884            || (self.columnar_selection_state.is_some()
 3885                && self.selections.disjoint_anchors().len() > 1)
 3886    }
 3887
 3888    pub fn has_pending_selection(&self) -> bool {
 3889        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3890    }
 3891
 3892    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3893        self.selection_mark_mode = false;
 3894        self.selection_drag_state = SelectionDragState::None;
 3895
 3896        if self.clear_expanded_diff_hunks(cx) {
 3897            cx.notify();
 3898            return;
 3899        }
 3900        if self.dismiss_menus_and_popups(true, window, cx) {
 3901            return;
 3902        }
 3903
 3904        if self.mode.is_full()
 3905            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3906        {
 3907            return;
 3908        }
 3909
 3910        cx.propagate();
 3911    }
 3912
 3913    pub fn dismiss_menus_and_popups(
 3914        &mut self,
 3915        is_user_requested: bool,
 3916        window: &mut Window,
 3917        cx: &mut Context<Self>,
 3918    ) -> bool {
 3919        if self.take_rename(false, window, cx).is_some() {
 3920            return true;
 3921        }
 3922
 3923        if hide_hover(self, cx) {
 3924            return true;
 3925        }
 3926
 3927        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3928            return true;
 3929        }
 3930
 3931        if self.hide_context_menu(window, cx).is_some() {
 3932            return true;
 3933        }
 3934
 3935        if self.mouse_context_menu.take().is_some() {
 3936            return true;
 3937        }
 3938
 3939        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3940            return true;
 3941        }
 3942
 3943        if self.snippet_stack.pop().is_some() {
 3944            return true;
 3945        }
 3946
 3947        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3948            self.dismiss_diagnostics(cx);
 3949            return true;
 3950        }
 3951
 3952        false
 3953    }
 3954
 3955    fn linked_editing_ranges_for(
 3956        &self,
 3957        selection: Range<text::Anchor>,
 3958        cx: &App,
 3959    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3960        if self.linked_edit_ranges.is_empty() {
 3961            return None;
 3962        }
 3963        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3964            selection.end.buffer_id.and_then(|end_buffer_id| {
 3965                if selection.start.buffer_id != Some(end_buffer_id) {
 3966                    return None;
 3967                }
 3968                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3969                let snapshot = buffer.read(cx).snapshot();
 3970                self.linked_edit_ranges
 3971                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3972                    .map(|ranges| (ranges, snapshot, buffer))
 3973            })?;
 3974        use text::ToOffset as TO;
 3975        // find offset from the start of current range to current cursor position
 3976        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3977
 3978        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3979        let start_difference = start_offset - start_byte_offset;
 3980        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3981        let end_difference = end_offset - start_byte_offset;
 3982        // Current range has associated linked ranges.
 3983        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3984        for range in linked_ranges.iter() {
 3985            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3986            let end_offset = start_offset + end_difference;
 3987            let start_offset = start_offset + start_difference;
 3988            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3989                continue;
 3990            }
 3991            if self.selections.disjoint_anchor_ranges().any(|s| {
 3992                if s.start.buffer_id != selection.start.buffer_id
 3993                    || s.end.buffer_id != selection.end.buffer_id
 3994                {
 3995                    return false;
 3996                }
 3997                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3998                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3999            }) {
 4000                continue;
 4001            }
 4002            let start = buffer_snapshot.anchor_after(start_offset);
 4003            let end = buffer_snapshot.anchor_after(end_offset);
 4004            linked_edits
 4005                .entry(buffer.clone())
 4006                .or_default()
 4007                .push(start..end);
 4008        }
 4009        Some(linked_edits)
 4010    }
 4011
 4012    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4013        let text: Arc<str> = text.into();
 4014
 4015        if self.read_only(cx) {
 4016            return;
 4017        }
 4018
 4019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4020
 4021        let selections = self.selections.all_adjusted(cx);
 4022        let mut bracket_inserted = false;
 4023        let mut edits = Vec::new();
 4024        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4025        let mut new_selections = Vec::with_capacity(selections.len());
 4026        let mut new_autoclose_regions = Vec::new();
 4027        let snapshot = self.buffer.read(cx).read(cx);
 4028        let mut clear_linked_edit_ranges = false;
 4029
 4030        for (selection, autoclose_region) in
 4031            self.selections_with_autoclose_regions(selections, &snapshot)
 4032        {
 4033            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4034                // Determine if the inserted text matches the opening or closing
 4035                // bracket of any of this language's bracket pairs.
 4036                let mut bracket_pair = None;
 4037                let mut is_bracket_pair_start = false;
 4038                let mut is_bracket_pair_end = false;
 4039                if !text.is_empty() {
 4040                    let mut bracket_pair_matching_end = None;
 4041                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4042                    //  and they are removing the character that triggered IME popup.
 4043                    for (pair, enabled) in scope.brackets() {
 4044                        if !pair.close && !pair.surround {
 4045                            continue;
 4046                        }
 4047
 4048                        if enabled && pair.start.ends_with(text.as_ref()) {
 4049                            let prefix_len = pair.start.len() - text.len();
 4050                            let preceding_text_matches_prefix = prefix_len == 0
 4051                                || (selection.start.column >= (prefix_len as u32)
 4052                                    && snapshot.contains_str_at(
 4053                                        Point::new(
 4054                                            selection.start.row,
 4055                                            selection.start.column - (prefix_len as u32),
 4056                                        ),
 4057                                        &pair.start[..prefix_len],
 4058                                    ));
 4059                            if preceding_text_matches_prefix {
 4060                                bracket_pair = Some(pair.clone());
 4061                                is_bracket_pair_start = true;
 4062                                break;
 4063                            }
 4064                        }
 4065                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4066                        {
 4067                            // take first bracket pair matching end, but don't break in case a later bracket
 4068                            // pair matches start
 4069                            bracket_pair_matching_end = Some(pair.clone());
 4070                        }
 4071                    }
 4072                    if let Some(end) = bracket_pair_matching_end
 4073                        && bracket_pair.is_none()
 4074                    {
 4075                        bracket_pair = Some(end);
 4076                        is_bracket_pair_end = true;
 4077                    }
 4078                }
 4079
 4080                if let Some(bracket_pair) = bracket_pair {
 4081                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4082                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4083                    let auto_surround =
 4084                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4085                    if selection.is_empty() {
 4086                        if is_bracket_pair_start {
 4087                            // If the inserted text is a suffix of an opening bracket and the
 4088                            // selection is preceded by the rest of the opening bracket, then
 4089                            // insert the closing bracket.
 4090                            let following_text_allows_autoclose = snapshot
 4091                                .chars_at(selection.start)
 4092                                .next()
 4093                                .is_none_or(|c| scope.should_autoclose_before(c));
 4094
 4095                            let preceding_text_allows_autoclose = selection.start.column == 0
 4096                                || snapshot
 4097                                    .reversed_chars_at(selection.start)
 4098                                    .next()
 4099                                    .is_none_or(|c| {
 4100                                        bracket_pair.start != bracket_pair.end
 4101                                            || !snapshot
 4102                                                .char_classifier_at(selection.start)
 4103                                                .is_word(c)
 4104                                    });
 4105
 4106                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4107                                && bracket_pair.start.len() == 1
 4108                            {
 4109                                let target = bracket_pair.start.chars().next().unwrap();
 4110                                let current_line_count = snapshot
 4111                                    .reversed_chars_at(selection.start)
 4112                                    .take_while(|&c| c != '\n')
 4113                                    .filter(|&c| c == target)
 4114                                    .count();
 4115                                current_line_count % 2 == 1
 4116                            } else {
 4117                                false
 4118                            };
 4119
 4120                            if autoclose
 4121                                && bracket_pair.close
 4122                                && following_text_allows_autoclose
 4123                                && preceding_text_allows_autoclose
 4124                                && !is_closing_quote
 4125                            {
 4126                                let anchor = snapshot.anchor_before(selection.end);
 4127                                new_selections.push((selection.map(|_| anchor), text.len()));
 4128                                new_autoclose_regions.push((
 4129                                    anchor,
 4130                                    text.len(),
 4131                                    selection.id,
 4132                                    bracket_pair.clone(),
 4133                                ));
 4134                                edits.push((
 4135                                    selection.range(),
 4136                                    format!("{}{}", text, bracket_pair.end).into(),
 4137                                ));
 4138                                bracket_inserted = true;
 4139                                continue;
 4140                            }
 4141                        }
 4142
 4143                        if let Some(region) = autoclose_region {
 4144                            // If the selection is followed by an auto-inserted closing bracket,
 4145                            // then don't insert that closing bracket again; just move the selection
 4146                            // past the closing bracket.
 4147                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4148                                && text.as_ref() == region.pair.end.as_str()
 4149                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4150                            if should_skip {
 4151                                let anchor = snapshot.anchor_after(selection.end);
 4152                                new_selections
 4153                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4154                                continue;
 4155                            }
 4156                        }
 4157
 4158                        let always_treat_brackets_as_autoclosed = snapshot
 4159                            .language_settings_at(selection.start, cx)
 4160                            .always_treat_brackets_as_autoclosed;
 4161                        if always_treat_brackets_as_autoclosed
 4162                            && is_bracket_pair_end
 4163                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4164                        {
 4165                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4166                            // and the inserted text is a closing bracket and the selection is followed
 4167                            // by the closing bracket then move the selection past the closing bracket.
 4168                            let anchor = snapshot.anchor_after(selection.end);
 4169                            new_selections.push((selection.map(|_| anchor), text.len()));
 4170                            continue;
 4171                        }
 4172                    }
 4173                    // If an opening bracket is 1 character long and is typed while
 4174                    // text is selected, then surround that text with the bracket pair.
 4175                    else if auto_surround
 4176                        && bracket_pair.surround
 4177                        && is_bracket_pair_start
 4178                        && bracket_pair.start.chars().count() == 1
 4179                    {
 4180                        edits.push((selection.start..selection.start, text.clone()));
 4181                        edits.push((
 4182                            selection.end..selection.end,
 4183                            bracket_pair.end.as_str().into(),
 4184                        ));
 4185                        bracket_inserted = true;
 4186                        new_selections.push((
 4187                            Selection {
 4188                                id: selection.id,
 4189                                start: snapshot.anchor_after(selection.start),
 4190                                end: snapshot.anchor_before(selection.end),
 4191                                reversed: selection.reversed,
 4192                                goal: selection.goal,
 4193                            },
 4194                            0,
 4195                        ));
 4196                        continue;
 4197                    }
 4198                }
 4199            }
 4200
 4201            if self.auto_replace_emoji_shortcode
 4202                && selection.is_empty()
 4203                && text.as_ref().ends_with(':')
 4204                && let Some(possible_emoji_short_code) =
 4205                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4206                && !possible_emoji_short_code.is_empty()
 4207                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4208            {
 4209                let emoji_shortcode_start = Point::new(
 4210                    selection.start.row,
 4211                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4212                );
 4213
 4214                // Remove shortcode from buffer
 4215                edits.push((
 4216                    emoji_shortcode_start..selection.start,
 4217                    "".to_string().into(),
 4218                ));
 4219                new_selections.push((
 4220                    Selection {
 4221                        id: selection.id,
 4222                        start: snapshot.anchor_after(emoji_shortcode_start),
 4223                        end: snapshot.anchor_before(selection.start),
 4224                        reversed: selection.reversed,
 4225                        goal: selection.goal,
 4226                    },
 4227                    0,
 4228                ));
 4229
 4230                // Insert emoji
 4231                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4232                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4233                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4234
 4235                continue;
 4236            }
 4237
 4238            // If not handling any auto-close operation, then just replace the selected
 4239            // text with the given input and move the selection to the end of the
 4240            // newly inserted text.
 4241            let anchor = snapshot.anchor_after(selection.end);
 4242            if !self.linked_edit_ranges.is_empty() {
 4243                let start_anchor = snapshot.anchor_before(selection.start);
 4244
 4245                let is_word_char = text.chars().next().is_none_or(|char| {
 4246                    let classifier = snapshot
 4247                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4248                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4249                    classifier.is_word(char)
 4250                });
 4251
 4252                if is_word_char {
 4253                    if let Some(ranges) = self
 4254                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4255                    {
 4256                        for (buffer, edits) in ranges {
 4257                            linked_edits
 4258                                .entry(buffer.clone())
 4259                                .or_default()
 4260                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4261                        }
 4262                    }
 4263                } else {
 4264                    clear_linked_edit_ranges = true;
 4265                }
 4266            }
 4267
 4268            new_selections.push((selection.map(|_| anchor), 0));
 4269            edits.push((selection.start..selection.end, text.clone()));
 4270        }
 4271
 4272        drop(snapshot);
 4273
 4274        self.transact(window, cx, |this, window, cx| {
 4275            if clear_linked_edit_ranges {
 4276                this.linked_edit_ranges.clear();
 4277            }
 4278            let initial_buffer_versions =
 4279                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4280
 4281            this.buffer.update(cx, |buffer, cx| {
 4282                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4283            });
 4284            for (buffer, edits) in linked_edits {
 4285                buffer.update(cx, |buffer, cx| {
 4286                    let snapshot = buffer.snapshot();
 4287                    let edits = edits
 4288                        .into_iter()
 4289                        .map(|(range, text)| {
 4290                            use text::ToPoint as TP;
 4291                            let end_point = TP::to_point(&range.end, &snapshot);
 4292                            let start_point = TP::to_point(&range.start, &snapshot);
 4293                            (start_point..end_point, text)
 4294                        })
 4295                        .sorted_by_key(|(range, _)| range.start);
 4296                    buffer.edit(edits, None, cx);
 4297                })
 4298            }
 4299            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4300            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4301            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4302            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4303                .zip(new_selection_deltas)
 4304                .map(|(selection, delta)| Selection {
 4305                    id: selection.id,
 4306                    start: selection.start + delta,
 4307                    end: selection.end + delta,
 4308                    reversed: selection.reversed,
 4309                    goal: SelectionGoal::None,
 4310                })
 4311                .collect::<Vec<_>>();
 4312
 4313            let mut i = 0;
 4314            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4315                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4316                let start = map.buffer_snapshot.anchor_before(position);
 4317                let end = map.buffer_snapshot.anchor_after(position);
 4318                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4319                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4320                        Ordering::Less => i += 1,
 4321                        Ordering::Greater => break,
 4322                        Ordering::Equal => {
 4323                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4324                                Ordering::Less => i += 1,
 4325                                Ordering::Equal => break,
 4326                                Ordering::Greater => break,
 4327                            }
 4328                        }
 4329                    }
 4330                }
 4331                this.autoclose_regions.insert(
 4332                    i,
 4333                    AutocloseRegion {
 4334                        selection_id,
 4335                        range: start..end,
 4336                        pair,
 4337                    },
 4338                );
 4339            }
 4340
 4341            let had_active_edit_prediction = this.has_active_edit_prediction();
 4342            this.change_selections(
 4343                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4344                window,
 4345                cx,
 4346                |s| s.select(new_selections),
 4347            );
 4348
 4349            if !bracket_inserted
 4350                && let Some(on_type_format_task) =
 4351                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4352            {
 4353                on_type_format_task.detach_and_log_err(cx);
 4354            }
 4355
 4356            let editor_settings = EditorSettings::get_global(cx);
 4357            if bracket_inserted
 4358                && (editor_settings.auto_signature_help
 4359                    || editor_settings.show_signature_help_after_edits)
 4360            {
 4361                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4362            }
 4363
 4364            let trigger_in_words =
 4365                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4366            if this.hard_wrap.is_some() {
 4367                let latest: Range<Point> = this.selections.newest(cx).range();
 4368                if latest.is_empty()
 4369                    && this
 4370                        .buffer()
 4371                        .read(cx)
 4372                        .snapshot(cx)
 4373                        .line_len(MultiBufferRow(latest.start.row))
 4374                        == latest.start.column
 4375                {
 4376                    this.rewrap_impl(
 4377                        RewrapOptions {
 4378                            override_language_settings: true,
 4379                            preserve_existing_whitespace: true,
 4380                        },
 4381                        cx,
 4382                    )
 4383                }
 4384            }
 4385            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4386            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4387            this.refresh_edit_prediction(true, false, window, cx);
 4388            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4389        });
 4390    }
 4391
 4392    fn find_possible_emoji_shortcode_at_position(
 4393        snapshot: &MultiBufferSnapshot,
 4394        position: Point,
 4395    ) -> Option<String> {
 4396        let mut chars = Vec::new();
 4397        let mut found_colon = false;
 4398        for char in snapshot.reversed_chars_at(position).take(100) {
 4399            // Found a possible emoji shortcode in the middle of the buffer
 4400            if found_colon {
 4401                if char.is_whitespace() {
 4402                    chars.reverse();
 4403                    return Some(chars.iter().collect());
 4404                }
 4405                // If the previous character is not a whitespace, we are in the middle of a word
 4406                // and we only want to complete the shortcode if the word is made up of other emojis
 4407                let mut containing_word = String::new();
 4408                for ch in snapshot
 4409                    .reversed_chars_at(position)
 4410                    .skip(chars.len() + 1)
 4411                    .take(100)
 4412                {
 4413                    if ch.is_whitespace() {
 4414                        break;
 4415                    }
 4416                    containing_word.push(ch);
 4417                }
 4418                let containing_word = containing_word.chars().rev().collect::<String>();
 4419                if util::word_consists_of_emojis(containing_word.as_str()) {
 4420                    chars.reverse();
 4421                    return Some(chars.iter().collect());
 4422                }
 4423            }
 4424
 4425            if char.is_whitespace() || !char.is_ascii() {
 4426                return None;
 4427            }
 4428            if char == ':' {
 4429                found_colon = true;
 4430            } else {
 4431                chars.push(char);
 4432            }
 4433        }
 4434        // Found a possible emoji shortcode at the beginning of the buffer
 4435        chars.reverse();
 4436        Some(chars.iter().collect())
 4437    }
 4438
 4439    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4441        self.transact(window, cx, |this, window, cx| {
 4442            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4443                let selections = this.selections.all::<usize>(cx);
 4444                let multi_buffer = this.buffer.read(cx);
 4445                let buffer = multi_buffer.snapshot(cx);
 4446                selections
 4447                    .iter()
 4448                    .map(|selection| {
 4449                        let start_point = selection.start.to_point(&buffer);
 4450                        let mut existing_indent =
 4451                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4452                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4453                        let start = selection.start;
 4454                        let end = selection.end;
 4455                        let selection_is_empty = start == end;
 4456                        let language_scope = buffer.language_scope_at(start);
 4457                        let (
 4458                            comment_delimiter,
 4459                            doc_delimiter,
 4460                            insert_extra_newline,
 4461                            indent_on_newline,
 4462                            indent_on_extra_newline,
 4463                        ) = if let Some(language) = &language_scope {
 4464                            let mut insert_extra_newline =
 4465                                insert_extra_newline_brackets(&buffer, start..end, language)
 4466                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4467
 4468                            // Comment extension on newline is allowed only for cursor selections
 4469                            let comment_delimiter = maybe!({
 4470                                if !selection_is_empty {
 4471                                    return None;
 4472                                }
 4473
 4474                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4475                                    return None;
 4476                                }
 4477
 4478                                let delimiters = language.line_comment_prefixes();
 4479                                let max_len_of_delimiter =
 4480                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4481                                let (snapshot, range) =
 4482                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4483
 4484                                let num_of_whitespaces = snapshot
 4485                                    .chars_for_range(range.clone())
 4486                                    .take_while(|c| c.is_whitespace())
 4487                                    .count();
 4488                                let comment_candidate = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .skip(num_of_whitespaces)
 4491                                    .take(max_len_of_delimiter)
 4492                                    .collect::<String>();
 4493                                let (delimiter, trimmed_len) = delimiters
 4494                                    .iter()
 4495                                    .filter_map(|delimiter| {
 4496                                        let prefix = delimiter.trim_end();
 4497                                        if comment_candidate.starts_with(prefix) {
 4498                                            Some((delimiter, prefix.len()))
 4499                                        } else {
 4500                                            None
 4501                                        }
 4502                                    })
 4503                                    .max_by_key(|(_, len)| *len)?;
 4504
 4505                                if let Some(BlockCommentConfig {
 4506                                    start: block_start, ..
 4507                                }) = language.block_comment()
 4508                                {
 4509                                    let block_start_trimmed = block_start.trim_end();
 4510                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4511                                        let line_content = snapshot
 4512                                            .chars_for_range(range)
 4513                                            .skip(num_of_whitespaces)
 4514                                            .take(block_start_trimmed.len())
 4515                                            .collect::<String>();
 4516
 4517                                        if line_content.starts_with(block_start_trimmed) {
 4518                                            return None;
 4519                                        }
 4520                                    }
 4521                                }
 4522
 4523                                let cursor_is_placed_after_comment_marker =
 4524                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4525                                if cursor_is_placed_after_comment_marker {
 4526                                    Some(delimiter.clone())
 4527                                } else {
 4528                                    None
 4529                                }
 4530                            });
 4531
 4532                            let mut indent_on_newline = IndentSize::spaces(0);
 4533                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4534
 4535                            let doc_delimiter = maybe!({
 4536                                if !selection_is_empty {
 4537                                    return None;
 4538                                }
 4539
 4540                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4541                                    return None;
 4542                                }
 4543
 4544                                let BlockCommentConfig {
 4545                                    start: start_tag,
 4546                                    end: end_tag,
 4547                                    prefix: delimiter,
 4548                                    tab_size: len,
 4549                                } = language.documentation_comment()?;
 4550                                let is_within_block_comment = buffer
 4551                                    .language_scope_at(start_point)
 4552                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4553                                if !is_within_block_comment {
 4554                                    return None;
 4555                                }
 4556
 4557                                let (snapshot, range) =
 4558                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4559
 4560                                let num_of_whitespaces = snapshot
 4561                                    .chars_for_range(range.clone())
 4562                                    .take_while(|c| c.is_whitespace())
 4563                                    .count();
 4564
 4565                                // 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.
 4566                                let column = start_point.column;
 4567                                let cursor_is_after_start_tag = {
 4568                                    let start_tag_len = start_tag.len();
 4569                                    let start_tag_line = snapshot
 4570                                        .chars_for_range(range.clone())
 4571                                        .skip(num_of_whitespaces)
 4572                                        .take(start_tag_len)
 4573                                        .collect::<String>();
 4574                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4575                                        num_of_whitespaces + start_tag_len <= column as usize
 4576                                    } else {
 4577                                        false
 4578                                    }
 4579                                };
 4580
 4581                                let cursor_is_after_delimiter = {
 4582                                    let delimiter_trim = delimiter.trim_end();
 4583                                    let delimiter_line = snapshot
 4584                                        .chars_for_range(range.clone())
 4585                                        .skip(num_of_whitespaces)
 4586                                        .take(delimiter_trim.len())
 4587                                        .collect::<String>();
 4588                                    if delimiter_line.starts_with(delimiter_trim) {
 4589                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4590                                    } else {
 4591                                        false
 4592                                    }
 4593                                };
 4594
 4595                                let cursor_is_before_end_tag_if_exists = {
 4596                                    let mut char_position = 0u32;
 4597                                    let mut end_tag_offset = None;
 4598
 4599                                    'outer: for chunk in snapshot.text_for_range(range) {
 4600                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4601                                            let chars_before_match =
 4602                                                chunk[..byte_pos].chars().count() as u32;
 4603                                            end_tag_offset =
 4604                                                Some(char_position + chars_before_match);
 4605                                            break 'outer;
 4606                                        }
 4607                                        char_position += chunk.chars().count() as u32;
 4608                                    }
 4609
 4610                                    if let Some(end_tag_offset) = end_tag_offset {
 4611                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4612                                        if cursor_is_after_start_tag {
 4613                                            if cursor_is_before_end_tag {
 4614                                                insert_extra_newline = true;
 4615                                            }
 4616                                            let cursor_is_at_start_of_end_tag =
 4617                                                column == end_tag_offset;
 4618                                            if cursor_is_at_start_of_end_tag {
 4619                                                indent_on_extra_newline.len = *len;
 4620                                            }
 4621                                        }
 4622                                        cursor_is_before_end_tag
 4623                                    } else {
 4624                                        true
 4625                                    }
 4626                                };
 4627
 4628                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4629                                    && cursor_is_before_end_tag_if_exists
 4630                                {
 4631                                    if cursor_is_after_start_tag {
 4632                                        indent_on_newline.len = *len;
 4633                                    }
 4634                                    Some(delimiter.clone())
 4635                                } else {
 4636                                    None
 4637                                }
 4638                            });
 4639
 4640                            (
 4641                                comment_delimiter,
 4642                                doc_delimiter,
 4643                                insert_extra_newline,
 4644                                indent_on_newline,
 4645                                indent_on_extra_newline,
 4646                            )
 4647                        } else {
 4648                            (
 4649                                None,
 4650                                None,
 4651                                false,
 4652                                IndentSize::default(),
 4653                                IndentSize::default(),
 4654                            )
 4655                        };
 4656
 4657                        let prevent_auto_indent = doc_delimiter.is_some();
 4658                        let delimiter = comment_delimiter.or(doc_delimiter);
 4659
 4660                        let capacity_for_delimiter =
 4661                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4662                        let mut new_text = String::with_capacity(
 4663                            1 + capacity_for_delimiter
 4664                                + existing_indent.len as usize
 4665                                + indent_on_newline.len as usize
 4666                                + indent_on_extra_newline.len as usize,
 4667                        );
 4668                        new_text.push('\n');
 4669                        new_text.extend(existing_indent.chars());
 4670                        new_text.extend(indent_on_newline.chars());
 4671
 4672                        if let Some(delimiter) = &delimiter {
 4673                            new_text.push_str(delimiter);
 4674                        }
 4675
 4676                        if insert_extra_newline {
 4677                            new_text.push('\n');
 4678                            new_text.extend(existing_indent.chars());
 4679                            new_text.extend(indent_on_extra_newline.chars());
 4680                        }
 4681
 4682                        let anchor = buffer.anchor_after(end);
 4683                        let new_selection = selection.map(|_| anchor);
 4684                        (
 4685                            ((start..end, new_text), prevent_auto_indent),
 4686                            (insert_extra_newline, new_selection),
 4687                        )
 4688                    })
 4689                    .unzip()
 4690            };
 4691
 4692            let mut auto_indent_edits = Vec::new();
 4693            let mut edits = Vec::new();
 4694            for (edit, prevent_auto_indent) in edits_with_flags {
 4695                if prevent_auto_indent {
 4696                    edits.push(edit);
 4697                } else {
 4698                    auto_indent_edits.push(edit);
 4699                }
 4700            }
 4701            if !edits.is_empty() {
 4702                this.edit(edits, cx);
 4703            }
 4704            if !auto_indent_edits.is_empty() {
 4705                this.edit_with_autoindent(auto_indent_edits, cx);
 4706            }
 4707
 4708            let buffer = this.buffer.read(cx).snapshot(cx);
 4709            let new_selections = selection_info
 4710                .into_iter()
 4711                .map(|(extra_newline_inserted, new_selection)| {
 4712                    let mut cursor = new_selection.end.to_point(&buffer);
 4713                    if extra_newline_inserted {
 4714                        cursor.row -= 1;
 4715                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4716                    }
 4717                    new_selection.map(|_| cursor)
 4718                })
 4719                .collect();
 4720
 4721            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4722            this.refresh_edit_prediction(true, false, window, cx);
 4723        });
 4724    }
 4725
 4726    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4728
 4729        let buffer = self.buffer.read(cx);
 4730        let snapshot = buffer.snapshot(cx);
 4731
 4732        let mut edits = Vec::new();
 4733        let mut rows = Vec::new();
 4734
 4735        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4736            let cursor = selection.head();
 4737            let row = cursor.row;
 4738
 4739            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4740
 4741            let newline = "\n".to_string();
 4742            edits.push((start_of_line..start_of_line, newline));
 4743
 4744            rows.push(row + rows_inserted as u32);
 4745        }
 4746
 4747        self.transact(window, cx, |editor, window, cx| {
 4748            editor.edit(edits, cx);
 4749
 4750            editor.change_selections(Default::default(), window, cx, |s| {
 4751                let mut index = 0;
 4752                s.move_cursors_with(|map, _, _| {
 4753                    let row = rows[index];
 4754                    index += 1;
 4755
 4756                    let point = Point::new(row, 0);
 4757                    let boundary = map.next_line_boundary(point).1;
 4758                    let clipped = map.clip_point(boundary, Bias::Left);
 4759
 4760                    (clipped, SelectionGoal::None)
 4761                });
 4762            });
 4763
 4764            let mut indent_edits = Vec::new();
 4765            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4766            for row in rows {
 4767                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4768                for (row, indent) in indents {
 4769                    if indent.len == 0 {
 4770                        continue;
 4771                    }
 4772
 4773                    let text = match indent.kind {
 4774                        IndentKind::Space => " ".repeat(indent.len as usize),
 4775                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4776                    };
 4777                    let point = Point::new(row.0, 0);
 4778                    indent_edits.push((point..point, text));
 4779                }
 4780            }
 4781            editor.edit(indent_edits, cx);
 4782        });
 4783    }
 4784
 4785    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4787
 4788        let buffer = self.buffer.read(cx);
 4789        let snapshot = buffer.snapshot(cx);
 4790
 4791        let mut edits = Vec::new();
 4792        let mut rows = Vec::new();
 4793        let mut rows_inserted = 0;
 4794
 4795        for selection in self.selections.all_adjusted(cx) {
 4796            let cursor = selection.head();
 4797            let row = cursor.row;
 4798
 4799            let point = Point::new(row + 1, 0);
 4800            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4801
 4802            let newline = "\n".to_string();
 4803            edits.push((start_of_line..start_of_line, newline));
 4804
 4805            rows_inserted += 1;
 4806            rows.push(row + rows_inserted);
 4807        }
 4808
 4809        self.transact(window, cx, |editor, window, cx| {
 4810            editor.edit(edits, cx);
 4811
 4812            editor.change_selections(Default::default(), window, cx, |s| {
 4813                let mut index = 0;
 4814                s.move_cursors_with(|map, _, _| {
 4815                    let row = rows[index];
 4816                    index += 1;
 4817
 4818                    let point = Point::new(row, 0);
 4819                    let boundary = map.next_line_boundary(point).1;
 4820                    let clipped = map.clip_point(boundary, Bias::Left);
 4821
 4822                    (clipped, SelectionGoal::None)
 4823                });
 4824            });
 4825
 4826            let mut indent_edits = Vec::new();
 4827            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4828            for row in rows {
 4829                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4830                for (row, indent) in indents {
 4831                    if indent.len == 0 {
 4832                        continue;
 4833                    }
 4834
 4835                    let text = match indent.kind {
 4836                        IndentKind::Space => " ".repeat(indent.len as usize),
 4837                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4838                    };
 4839                    let point = Point::new(row.0, 0);
 4840                    indent_edits.push((point..point, text));
 4841                }
 4842            }
 4843            editor.edit(indent_edits, cx);
 4844        });
 4845    }
 4846
 4847    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4848        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4849            original_indent_columns: Vec::new(),
 4850        });
 4851        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4852    }
 4853
 4854    fn insert_with_autoindent_mode(
 4855        &mut self,
 4856        text: &str,
 4857        autoindent_mode: Option<AutoindentMode>,
 4858        window: &mut Window,
 4859        cx: &mut Context<Self>,
 4860    ) {
 4861        if self.read_only(cx) {
 4862            return;
 4863        }
 4864
 4865        let text: Arc<str> = text.into();
 4866        self.transact(window, cx, |this, window, cx| {
 4867            let old_selections = this.selections.all_adjusted(cx);
 4868            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4869                let anchors = {
 4870                    let snapshot = buffer.read(cx);
 4871                    old_selections
 4872                        .iter()
 4873                        .map(|s| {
 4874                            let anchor = snapshot.anchor_after(s.head());
 4875                            s.map(|_| anchor)
 4876                        })
 4877                        .collect::<Vec<_>>()
 4878                };
 4879                buffer.edit(
 4880                    old_selections
 4881                        .iter()
 4882                        .map(|s| (s.start..s.end, text.clone())),
 4883                    autoindent_mode,
 4884                    cx,
 4885                );
 4886                anchors
 4887            });
 4888
 4889            this.change_selections(Default::default(), window, cx, |s| {
 4890                s.select_anchors(selection_anchors);
 4891            });
 4892
 4893            cx.notify();
 4894        });
 4895    }
 4896
 4897    fn trigger_completion_on_input(
 4898        &mut self,
 4899        text: &str,
 4900        trigger_in_words: bool,
 4901        window: &mut Window,
 4902        cx: &mut Context<Self>,
 4903    ) {
 4904        let completions_source = self
 4905            .context_menu
 4906            .borrow()
 4907            .as_ref()
 4908            .and_then(|menu| match menu {
 4909                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4910                CodeContextMenu::CodeActions(_) => None,
 4911            });
 4912
 4913        match completions_source {
 4914            Some(CompletionsMenuSource::Words { .. }) => {
 4915                self.open_or_update_completions_menu(
 4916                    Some(CompletionsMenuSource::Words {
 4917                        ignore_threshold: false,
 4918                    }),
 4919                    None,
 4920                    window,
 4921                    cx,
 4922                );
 4923            }
 4924            Some(CompletionsMenuSource::Normal)
 4925            | Some(CompletionsMenuSource::SnippetChoices)
 4926            | None
 4927                if self.is_completion_trigger(
 4928                    text,
 4929                    trigger_in_words,
 4930                    completions_source.is_some(),
 4931                    cx,
 4932                ) =>
 4933            {
 4934                self.show_completions(
 4935                    &ShowCompletions {
 4936                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4937                    },
 4938                    window,
 4939                    cx,
 4940                )
 4941            }
 4942            _ => {
 4943                self.hide_context_menu(window, cx);
 4944            }
 4945        }
 4946    }
 4947
 4948    fn is_completion_trigger(
 4949        &self,
 4950        text: &str,
 4951        trigger_in_words: bool,
 4952        menu_is_open: bool,
 4953        cx: &mut Context<Self>,
 4954    ) -> bool {
 4955        let position = self.selections.newest_anchor().head();
 4956        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4957            return false;
 4958        };
 4959
 4960        if let Some(completion_provider) = &self.completion_provider {
 4961            completion_provider.is_completion_trigger(
 4962                &buffer,
 4963                position.text_anchor,
 4964                text,
 4965                trigger_in_words,
 4966                menu_is_open,
 4967                cx,
 4968            )
 4969        } else {
 4970            false
 4971        }
 4972    }
 4973
 4974    /// If any empty selections is touching the start of its innermost containing autoclose
 4975    /// region, expand it to select the brackets.
 4976    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4977        let selections = self.selections.all::<usize>(cx);
 4978        let buffer = self.buffer.read(cx).read(cx);
 4979        let new_selections = self
 4980            .selections_with_autoclose_regions(selections, &buffer)
 4981            .map(|(mut selection, region)| {
 4982                if !selection.is_empty() {
 4983                    return selection;
 4984                }
 4985
 4986                if let Some(region) = region {
 4987                    let mut range = region.range.to_offset(&buffer);
 4988                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4989                        range.start -= region.pair.start.len();
 4990                        if buffer.contains_str_at(range.start, &region.pair.start)
 4991                            && buffer.contains_str_at(range.end, &region.pair.end)
 4992                        {
 4993                            range.end += region.pair.end.len();
 4994                            selection.start = range.start;
 4995                            selection.end = range.end;
 4996
 4997                            return selection;
 4998                        }
 4999                    }
 5000                }
 5001
 5002                let always_treat_brackets_as_autoclosed = buffer
 5003                    .language_settings_at(selection.start, cx)
 5004                    .always_treat_brackets_as_autoclosed;
 5005
 5006                if !always_treat_brackets_as_autoclosed {
 5007                    return selection;
 5008                }
 5009
 5010                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5011                    for (pair, enabled) in scope.brackets() {
 5012                        if !enabled || !pair.close {
 5013                            continue;
 5014                        }
 5015
 5016                        if buffer.contains_str_at(selection.start, &pair.end) {
 5017                            let pair_start_len = pair.start.len();
 5018                            if buffer.contains_str_at(
 5019                                selection.start.saturating_sub(pair_start_len),
 5020                                &pair.start,
 5021                            ) {
 5022                                selection.start -= pair_start_len;
 5023                                selection.end += pair.end.len();
 5024
 5025                                return selection;
 5026                            }
 5027                        }
 5028                    }
 5029                }
 5030
 5031                selection
 5032            })
 5033            .collect();
 5034
 5035        drop(buffer);
 5036        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5037            selections.select(new_selections)
 5038        });
 5039    }
 5040
 5041    /// Iterate the given selections, and for each one, find the smallest surrounding
 5042    /// autoclose region. This uses the ordering of the selections and the autoclose
 5043    /// regions to avoid repeated comparisons.
 5044    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5045        &'a self,
 5046        selections: impl IntoIterator<Item = Selection<D>>,
 5047        buffer: &'a MultiBufferSnapshot,
 5048    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5049        let mut i = 0;
 5050        let mut regions = self.autoclose_regions.as_slice();
 5051        selections.into_iter().map(move |selection| {
 5052            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5053
 5054            let mut enclosing = None;
 5055            while let Some(pair_state) = regions.get(i) {
 5056                if pair_state.range.end.to_offset(buffer) < range.start {
 5057                    regions = &regions[i + 1..];
 5058                    i = 0;
 5059                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5060                    break;
 5061                } else {
 5062                    if pair_state.selection_id == selection.id {
 5063                        enclosing = Some(pair_state);
 5064                    }
 5065                    i += 1;
 5066                }
 5067            }
 5068
 5069            (selection, enclosing)
 5070        })
 5071    }
 5072
 5073    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5074    fn invalidate_autoclose_regions(
 5075        &mut self,
 5076        mut selections: &[Selection<Anchor>],
 5077        buffer: &MultiBufferSnapshot,
 5078    ) {
 5079        self.autoclose_regions.retain(|state| {
 5080            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5081                return false;
 5082            }
 5083
 5084            let mut i = 0;
 5085            while let Some(selection) = selections.get(i) {
 5086                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5087                    selections = &selections[1..];
 5088                    continue;
 5089                }
 5090                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5091                    break;
 5092                }
 5093                if selection.id == state.selection_id {
 5094                    return true;
 5095                } else {
 5096                    i += 1;
 5097                }
 5098            }
 5099            false
 5100        });
 5101    }
 5102
 5103    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5104        let offset = position.to_offset(buffer);
 5105        let (word_range, kind) =
 5106            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5107        if offset > word_range.start && kind == Some(CharKind::Word) {
 5108            Some(
 5109                buffer
 5110                    .text_for_range(word_range.start..offset)
 5111                    .collect::<String>(),
 5112            )
 5113        } else {
 5114            None
 5115        }
 5116    }
 5117
 5118    pub fn toggle_inline_values(
 5119        &mut self,
 5120        _: &ToggleInlineValues,
 5121        _: &mut Window,
 5122        cx: &mut Context<Self>,
 5123    ) {
 5124        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5125
 5126        self.refresh_inline_values(cx);
 5127    }
 5128
 5129    pub fn toggle_inlay_hints(
 5130        &mut self,
 5131        _: &ToggleInlayHints,
 5132        _: &mut Window,
 5133        cx: &mut Context<Self>,
 5134    ) {
 5135        self.refresh_inlay_hints(
 5136            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5137            cx,
 5138        );
 5139    }
 5140
 5141    pub fn inlay_hints_enabled(&self) -> bool {
 5142        self.inlay_hint_cache.enabled
 5143    }
 5144
 5145    pub fn inline_values_enabled(&self) -> bool {
 5146        self.inline_value_cache.enabled
 5147    }
 5148
 5149    #[cfg(any(test, feature = "test-support"))]
 5150    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5151        self.display_map
 5152            .read(cx)
 5153            .current_inlays()
 5154            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5155            .cloned()
 5156            .collect()
 5157    }
 5158
 5159    #[cfg(any(test, feature = "test-support"))]
 5160    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5161        self.display_map
 5162            .read(cx)
 5163            .current_inlays()
 5164            .cloned()
 5165            .collect()
 5166    }
 5167
 5168    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5169        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5170            return;
 5171        }
 5172
 5173        let reason_description = reason.description();
 5174        let ignore_debounce = matches!(
 5175            reason,
 5176            InlayHintRefreshReason::SettingsChange(_)
 5177                | InlayHintRefreshReason::Toggle(_)
 5178                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5179                | InlayHintRefreshReason::ModifiersChanged(_)
 5180        );
 5181        let (invalidate_cache, required_languages) = match reason {
 5182            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5183                match self.inlay_hint_cache.modifiers_override(enabled) {
 5184                    Some(enabled) => {
 5185                        if enabled {
 5186                            (InvalidationStrategy::RefreshRequested, None)
 5187                        } else {
 5188                            self.splice_inlays(
 5189                                &self
 5190                                    .visible_inlay_hints(cx)
 5191                                    .iter()
 5192                                    .map(|inlay| inlay.id)
 5193                                    .collect::<Vec<InlayId>>(),
 5194                                Vec::new(),
 5195                                cx,
 5196                            );
 5197                            return;
 5198                        }
 5199                    }
 5200                    None => return,
 5201                }
 5202            }
 5203            InlayHintRefreshReason::Toggle(enabled) => {
 5204                if self.inlay_hint_cache.toggle(enabled) {
 5205                    if enabled {
 5206                        (InvalidationStrategy::RefreshRequested, None)
 5207                    } else {
 5208                        self.splice_inlays(
 5209                            &self
 5210                                .visible_inlay_hints(cx)
 5211                                .iter()
 5212                                .map(|inlay| inlay.id)
 5213                                .collect::<Vec<InlayId>>(),
 5214                            Vec::new(),
 5215                            cx,
 5216                        );
 5217                        return;
 5218                    }
 5219                } else {
 5220                    return;
 5221                }
 5222            }
 5223            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5224                match self.inlay_hint_cache.update_settings(
 5225                    &self.buffer,
 5226                    new_settings,
 5227                    self.visible_inlay_hints(cx),
 5228                    cx,
 5229                ) {
 5230                    ControlFlow::Break(Some(InlaySplice {
 5231                        to_remove,
 5232                        to_insert,
 5233                    })) => {
 5234                        self.splice_inlays(&to_remove, to_insert, cx);
 5235                        return;
 5236                    }
 5237                    ControlFlow::Break(None) => return,
 5238                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5239                }
 5240            }
 5241            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5242                if let Some(InlaySplice {
 5243                    to_remove,
 5244                    to_insert,
 5245                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5246                {
 5247                    self.splice_inlays(&to_remove, to_insert, cx);
 5248                }
 5249                self.display_map.update(cx, |display_map, _| {
 5250                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5251                });
 5252                return;
 5253            }
 5254            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5255            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5256                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5257            }
 5258            InlayHintRefreshReason::RefreshRequested => {
 5259                (InvalidationStrategy::RefreshRequested, None)
 5260            }
 5261        };
 5262
 5263        if let Some(InlaySplice {
 5264            to_remove,
 5265            to_insert,
 5266        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5267            reason_description,
 5268            self.visible_excerpts(required_languages.as_ref(), cx),
 5269            invalidate_cache,
 5270            ignore_debounce,
 5271            cx,
 5272        ) {
 5273            self.splice_inlays(&to_remove, to_insert, cx);
 5274        }
 5275    }
 5276
 5277    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5278        self.display_map
 5279            .read(cx)
 5280            .current_inlays()
 5281            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5282            .cloned()
 5283            .collect()
 5284    }
 5285
 5286    pub fn visible_excerpts(
 5287        &self,
 5288        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5289        cx: &mut Context<Editor>,
 5290    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5291        let Some(project) = self.project() else {
 5292            return HashMap::default();
 5293        };
 5294        let project = project.read(cx);
 5295        let multi_buffer = self.buffer().read(cx);
 5296        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5297        let multi_buffer_visible_start = self
 5298            .scroll_manager
 5299            .anchor()
 5300            .anchor
 5301            .to_point(&multi_buffer_snapshot);
 5302        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5303            multi_buffer_visible_start
 5304                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5305            Bias::Left,
 5306        );
 5307        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5308        multi_buffer_snapshot
 5309            .range_to_buffer_ranges(multi_buffer_visible_range)
 5310            .into_iter()
 5311            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5312            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5313                let buffer_file = project::File::from_dyn(buffer.file())?;
 5314                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5315                let worktree_entry = buffer_worktree
 5316                    .read(cx)
 5317                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5318                if worktree_entry.is_ignored {
 5319                    return None;
 5320                }
 5321
 5322                let language = buffer.language()?;
 5323                if let Some(restrict_to_languages) = restrict_to_languages
 5324                    && !restrict_to_languages.contains(language)
 5325                {
 5326                    return None;
 5327                }
 5328                Some((
 5329                    excerpt_id,
 5330                    (
 5331                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5332                        buffer.version().clone(),
 5333                        excerpt_visible_range,
 5334                    ),
 5335                ))
 5336            })
 5337            .collect()
 5338    }
 5339
 5340    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5341        TextLayoutDetails {
 5342            text_system: window.text_system().clone(),
 5343            editor_style: self.style.clone().unwrap(),
 5344            rem_size: window.rem_size(),
 5345            scroll_anchor: self.scroll_manager.anchor(),
 5346            visible_rows: self.visible_line_count(),
 5347            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5348        }
 5349    }
 5350
 5351    pub fn splice_inlays(
 5352        &self,
 5353        to_remove: &[InlayId],
 5354        to_insert: Vec<Inlay>,
 5355        cx: &mut Context<Self>,
 5356    ) {
 5357        self.display_map.update(cx, |display_map, cx| {
 5358            display_map.splice_inlays(to_remove, to_insert, cx)
 5359        });
 5360        cx.notify();
 5361    }
 5362
 5363    fn trigger_on_type_formatting(
 5364        &self,
 5365        input: String,
 5366        window: &mut Window,
 5367        cx: &mut Context<Self>,
 5368    ) -> Option<Task<Result<()>>> {
 5369        if input.len() != 1 {
 5370            return None;
 5371        }
 5372
 5373        let project = self.project()?;
 5374        let position = self.selections.newest_anchor().head();
 5375        let (buffer, buffer_position) = self
 5376            .buffer
 5377            .read(cx)
 5378            .text_anchor_for_position(position, cx)?;
 5379
 5380        let settings = language_settings::language_settings(
 5381            buffer
 5382                .read(cx)
 5383                .language_at(buffer_position)
 5384                .map(|l| l.name()),
 5385            buffer.read(cx).file(),
 5386            cx,
 5387        );
 5388        if !settings.use_on_type_format {
 5389            return None;
 5390        }
 5391
 5392        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5393        // hence we do LSP request & edit on host side only — add formats to host's history.
 5394        let push_to_lsp_host_history = true;
 5395        // If this is not the host, append its history with new edits.
 5396        let push_to_client_history = project.read(cx).is_via_collab();
 5397
 5398        let on_type_formatting = project.update(cx, |project, cx| {
 5399            project.on_type_format(
 5400                buffer.clone(),
 5401                buffer_position,
 5402                input,
 5403                push_to_lsp_host_history,
 5404                cx,
 5405            )
 5406        });
 5407        Some(cx.spawn_in(window, async move |editor, cx| {
 5408            if let Some(transaction) = on_type_formatting.await? {
 5409                if push_to_client_history {
 5410                    buffer
 5411                        .update(cx, |buffer, _| {
 5412                            buffer.push_transaction(transaction, Instant::now());
 5413                            buffer.finalize_last_transaction();
 5414                        })
 5415                        .ok();
 5416                }
 5417                editor.update(cx, |editor, cx| {
 5418                    editor.refresh_document_highlights(cx);
 5419                })?;
 5420            }
 5421            Ok(())
 5422        }))
 5423    }
 5424
 5425    pub fn show_word_completions(
 5426        &mut self,
 5427        _: &ShowWordCompletions,
 5428        window: &mut Window,
 5429        cx: &mut Context<Self>,
 5430    ) {
 5431        self.open_or_update_completions_menu(
 5432            Some(CompletionsMenuSource::Words {
 5433                ignore_threshold: true,
 5434            }),
 5435            None,
 5436            window,
 5437            cx,
 5438        );
 5439    }
 5440
 5441    pub fn show_completions(
 5442        &mut self,
 5443        options: &ShowCompletions,
 5444        window: &mut Window,
 5445        cx: &mut Context<Self>,
 5446    ) {
 5447        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5448    }
 5449
 5450    fn open_or_update_completions_menu(
 5451        &mut self,
 5452        requested_source: Option<CompletionsMenuSource>,
 5453        trigger: Option<&str>,
 5454        window: &mut Window,
 5455        cx: &mut Context<Self>,
 5456    ) {
 5457        if self.pending_rename.is_some() {
 5458            return;
 5459        }
 5460
 5461        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5462
 5463        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5464        // inserted and selected. To handle that case, the start of the selection is used so that
 5465        // the menu starts with all choices.
 5466        let position = self
 5467            .selections
 5468            .newest_anchor()
 5469            .start
 5470            .bias_right(&multibuffer_snapshot);
 5471        if position.diff_base_anchor.is_some() {
 5472            return;
 5473        }
 5474        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5475        let Some(buffer) = buffer_position
 5476            .buffer_id
 5477            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5478        else {
 5479            return;
 5480        };
 5481        let buffer_snapshot = buffer.read(cx).snapshot();
 5482
 5483        let query: Option<Arc<String>> =
 5484            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5485                .map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        // Hide the current completions menu when query is empty. Without this, cached
 5490        // completions from before the trigger char may be reused (#32774).
 5491        if query.is_none() {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        let mut ignore_word_threshold = false;
 5502        let provider = match requested_source {
 5503            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5504            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5505                ignore_word_threshold = ignore_threshold;
 5506                None
 5507            }
 5508            Some(CompletionsMenuSource::SnippetChoices) => {
 5509                log::error!("bug: SnippetChoices requested_source is not handled");
 5510                None
 5511            }
 5512        };
 5513
 5514        let sort_completions = provider
 5515            .as_ref()
 5516            .is_some_and(|provider| provider.sort_completions());
 5517
 5518        let filter_completions = provider
 5519            .as_ref()
 5520            .is_none_or(|provider| provider.filter_completions());
 5521
 5522        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5523            if filter_completions {
 5524                menu.filter(query.clone(), provider.clone(), window, cx);
 5525            }
 5526            // When `is_incomplete` is false, no need to re-query completions when the current query
 5527            // is a suffix of the initial query.
 5528            if !menu.is_incomplete {
 5529                // If the new query is a suffix of the old query (typing more characters) and
 5530                // the previous result was complete, the existing completions can be filtered.
 5531                //
 5532                // Note that this is always true for snippet completions.
 5533                let query_matches = match (&menu.initial_query, &query) {
 5534                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5535                    (None, _) => true,
 5536                    _ => false,
 5537                };
 5538                if query_matches {
 5539                    let position_matches = if menu.initial_position == position {
 5540                        true
 5541                    } else {
 5542                        let snapshot = self.buffer.read(cx).read(cx);
 5543                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5544                    };
 5545                    if position_matches {
 5546                        return;
 5547                    }
 5548                }
 5549            }
 5550        };
 5551
 5552        let trigger_kind = match trigger {
 5553            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5554                CompletionTriggerKind::TRIGGER_CHARACTER
 5555            }
 5556            _ => CompletionTriggerKind::INVOKED,
 5557        };
 5558        let completion_context = CompletionContext {
 5559            trigger_character: trigger.and_then(|trigger| {
 5560                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5561                    Some(String::from(trigger))
 5562                } else {
 5563                    None
 5564                }
 5565            }),
 5566            trigger_kind,
 5567        };
 5568
 5569        let Anchor {
 5570            excerpt_id: buffer_excerpt_id,
 5571            text_anchor: buffer_position,
 5572            ..
 5573        } = buffer_position;
 5574
 5575        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5576            buffer_snapshot.surrounding_word(buffer_position, None)
 5577        {
 5578            let word_to_exclude = buffer_snapshot
 5579                .text_for_range(word_range.clone())
 5580                .collect::<String>();
 5581            (
 5582                buffer_snapshot.anchor_before(word_range.start)
 5583                    ..buffer_snapshot.anchor_after(buffer_position),
 5584                Some(word_to_exclude),
 5585            )
 5586        } else {
 5587            (buffer_position..buffer_position, None)
 5588        };
 5589
 5590        let language = buffer_snapshot
 5591            .language_at(buffer_position)
 5592            .map(|language| language.name());
 5593
 5594        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5595            .completions
 5596            .clone();
 5597
 5598        let show_completion_documentation = buffer_snapshot
 5599            .settings_at(buffer_position, cx)
 5600            .show_completion_documentation;
 5601
 5602        // The document can be large, so stay in reasonable bounds when searching for words,
 5603        // otherwise completion pop-up might be slow to appear.
 5604        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5605        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5606        let min_word_search = buffer_snapshot.clip_point(
 5607            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5608            Bias::Left,
 5609        );
 5610        let max_word_search = buffer_snapshot.clip_point(
 5611            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5612            Bias::Right,
 5613        );
 5614        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5615            ..buffer_snapshot.point_to_offset(max_word_search);
 5616
 5617        let skip_digits = query
 5618            .as_ref()
 5619            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5620
 5621        let omit_word_completions = !self.word_completions_enabled
 5622            || (!ignore_word_threshold
 5623                && match &query {
 5624                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5625                    None => completion_settings.words_min_length != 0,
 5626                });
 5627
 5628        let (mut words, provider_responses) = match &provider {
 5629            Some(provider) => {
 5630                let provider_responses = provider.completions(
 5631                    buffer_excerpt_id,
 5632                    &buffer,
 5633                    buffer_position,
 5634                    completion_context,
 5635                    window,
 5636                    cx,
 5637                );
 5638
 5639                let words = match (omit_word_completions, completion_settings.words) {
 5640                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5641                        Task::ready(BTreeMap::default())
 5642                    }
 5643                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5644                        .background_spawn(async move {
 5645                            buffer_snapshot.words_in_range(WordsQuery {
 5646                                fuzzy_contents: None,
 5647                                range: word_search_range,
 5648                                skip_digits,
 5649                            })
 5650                        }),
 5651                };
 5652
 5653                (words, provider_responses)
 5654            }
 5655            None => {
 5656                let words = if omit_word_completions {
 5657                    Task::ready(BTreeMap::default())
 5658                } else {
 5659                    cx.background_spawn(async move {
 5660                        buffer_snapshot.words_in_range(WordsQuery {
 5661                            fuzzy_contents: None,
 5662                            range: word_search_range,
 5663                            skip_digits,
 5664                        })
 5665                    })
 5666                };
 5667                (words, Task::ready(Ok(Vec::new())))
 5668            }
 5669        };
 5670
 5671        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5672
 5673        let id = post_inc(&mut self.next_completion_id);
 5674        let task = cx.spawn_in(window, async move |editor, cx| {
 5675            let Ok(()) = editor.update(cx, |this, _| {
 5676                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5677            }) else {
 5678                return;
 5679            };
 5680
 5681            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5682            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5683            let mut completions = Vec::new();
 5684            let mut is_incomplete = false;
 5685            let mut display_options: Option<CompletionDisplayOptions> = None;
 5686            if let Some(provider_responses) = provider_responses.await.log_err()
 5687                && !provider_responses.is_empty()
 5688            {
 5689                for response in provider_responses {
 5690                    completions.extend(response.completions);
 5691                    is_incomplete = is_incomplete || response.is_incomplete;
 5692                    match display_options.as_mut() {
 5693                        None => {
 5694                            display_options = Some(response.display_options);
 5695                        }
 5696                        Some(options) => options.merge(&response.display_options),
 5697                    }
 5698                }
 5699                if completion_settings.words == WordsCompletionMode::Fallback {
 5700                    words = Task::ready(BTreeMap::default());
 5701                }
 5702            }
 5703            let display_options = display_options.unwrap_or_default();
 5704
 5705            let mut words = words.await;
 5706            if let Some(word_to_exclude) = &word_to_exclude {
 5707                words.remove(word_to_exclude);
 5708            }
 5709            for lsp_completion in &completions {
 5710                words.remove(&lsp_completion.new_text);
 5711            }
 5712            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5713                replace_range: word_replace_range.clone(),
 5714                new_text: word.clone(),
 5715                label: CodeLabel::plain(word, None),
 5716                icon_path: None,
 5717                documentation: None,
 5718                source: CompletionSource::BufferWord {
 5719                    word_range,
 5720                    resolved: false,
 5721                },
 5722                insert_text_mode: Some(InsertTextMode::AS_IS),
 5723                confirm: None,
 5724            }));
 5725
 5726            let menu = if completions.is_empty() {
 5727                None
 5728            } else {
 5729                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5730                    let languages = editor
 5731                        .workspace
 5732                        .as_ref()
 5733                        .and_then(|(workspace, _)| workspace.upgrade())
 5734                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5735                    let menu = CompletionsMenu::new(
 5736                        id,
 5737                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5738                        sort_completions,
 5739                        show_completion_documentation,
 5740                        position,
 5741                        query.clone(),
 5742                        is_incomplete,
 5743                        buffer.clone(),
 5744                        completions.into(),
 5745                        display_options,
 5746                        snippet_sort_order,
 5747                        languages,
 5748                        language,
 5749                        cx,
 5750                    );
 5751
 5752                    let query = if filter_completions { query } else { None };
 5753                    let matches_task = if let Some(query) = query {
 5754                        menu.do_async_filtering(query, cx)
 5755                    } else {
 5756                        Task::ready(menu.unfiltered_matches())
 5757                    };
 5758                    (menu, matches_task)
 5759                }) else {
 5760                    return;
 5761                };
 5762
 5763                let matches = matches_task.await;
 5764
 5765                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5766                    // Newer menu already set, so exit.
 5767                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5768                        editor.context_menu.borrow().as_ref()
 5769                        && prev_menu.id > id
 5770                    {
 5771                        return;
 5772                    };
 5773
 5774                    // Only valid to take prev_menu because it the new menu is immediately set
 5775                    // below, or the menu is hidden.
 5776                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5777                        editor.context_menu.borrow_mut().take()
 5778                    {
 5779                        let position_matches =
 5780                            if prev_menu.initial_position == menu.initial_position {
 5781                                true
 5782                            } else {
 5783                                let snapshot = editor.buffer.read(cx).read(cx);
 5784                                prev_menu.initial_position.to_offset(&snapshot)
 5785                                    == menu.initial_position.to_offset(&snapshot)
 5786                            };
 5787                        if position_matches {
 5788                            // Preserve markdown cache before `set_filter_results` because it will
 5789                            // try to populate the documentation cache.
 5790                            menu.preserve_markdown_cache(prev_menu);
 5791                        }
 5792                    };
 5793
 5794                    menu.set_filter_results(matches, provider, window, cx);
 5795                }) else {
 5796                    return;
 5797                };
 5798
 5799                menu.visible().then_some(menu)
 5800            };
 5801
 5802            editor
 5803                .update_in(cx, |editor, window, cx| {
 5804                    if editor.focus_handle.is_focused(window)
 5805                        && let Some(menu) = menu
 5806                    {
 5807                        *editor.context_menu.borrow_mut() =
 5808                            Some(CodeContextMenu::Completions(menu));
 5809
 5810                        crate::hover_popover::hide_hover(editor, cx);
 5811                        if editor.show_edit_predictions_in_menu() {
 5812                            editor.update_visible_edit_prediction(window, cx);
 5813                        } else {
 5814                            editor.discard_edit_prediction(false, cx);
 5815                        }
 5816
 5817                        cx.notify();
 5818                        return;
 5819                    }
 5820
 5821                    if editor.completion_tasks.len() <= 1 {
 5822                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5823                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5824                        // If it was already hidden and we don't show edit predictions in the menu,
 5825                        // we should also show the edit prediction when available.
 5826                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5827                            editor.update_visible_edit_prediction(window, cx);
 5828                        }
 5829                    }
 5830                })
 5831                .ok();
 5832        });
 5833
 5834        self.completion_tasks.push((id, task));
 5835    }
 5836
 5837    #[cfg(feature = "test-support")]
 5838    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5839        let menu = self.context_menu.borrow();
 5840        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5841            let completions = menu.completions.borrow();
 5842            Some(completions.to_vec())
 5843        } else {
 5844            None
 5845        }
 5846    }
 5847
 5848    pub fn with_completions_menu_matching_id<R>(
 5849        &self,
 5850        id: CompletionId,
 5851        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5852    ) -> R {
 5853        let mut context_menu = self.context_menu.borrow_mut();
 5854        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5855            return f(None);
 5856        };
 5857        if completions_menu.id != id {
 5858            return f(None);
 5859        }
 5860        f(Some(completions_menu))
 5861    }
 5862
 5863    pub fn confirm_completion(
 5864        &mut self,
 5865        action: &ConfirmCompletion,
 5866        window: &mut Window,
 5867        cx: &mut Context<Self>,
 5868    ) -> Option<Task<Result<()>>> {
 5869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5870        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5871    }
 5872
 5873    pub fn confirm_completion_insert(
 5874        &mut self,
 5875        _: &ConfirmCompletionInsert,
 5876        window: &mut Window,
 5877        cx: &mut Context<Self>,
 5878    ) -> Option<Task<Result<()>>> {
 5879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5880        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5881    }
 5882
 5883    pub fn confirm_completion_replace(
 5884        &mut self,
 5885        _: &ConfirmCompletionReplace,
 5886        window: &mut Window,
 5887        cx: &mut Context<Self>,
 5888    ) -> Option<Task<Result<()>>> {
 5889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5890        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5891    }
 5892
 5893    pub fn compose_completion(
 5894        &mut self,
 5895        action: &ComposeCompletion,
 5896        window: &mut Window,
 5897        cx: &mut Context<Self>,
 5898    ) -> Option<Task<Result<()>>> {
 5899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5900        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5901    }
 5902
 5903    fn do_completion(
 5904        &mut self,
 5905        item_ix: Option<usize>,
 5906        intent: CompletionIntent,
 5907        window: &mut Window,
 5908        cx: &mut Context<Editor>,
 5909    ) -> Option<Task<Result<()>>> {
 5910        use language::ToOffset as _;
 5911
 5912        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5913        else {
 5914            return None;
 5915        };
 5916
 5917        let candidate_id = {
 5918            let entries = completions_menu.entries.borrow();
 5919            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5920            if self.show_edit_predictions_in_menu() {
 5921                self.discard_edit_prediction(true, cx);
 5922            }
 5923            mat.candidate_id
 5924        };
 5925
 5926        let completion = completions_menu
 5927            .completions
 5928            .borrow()
 5929            .get(candidate_id)?
 5930            .clone();
 5931        cx.stop_propagation();
 5932
 5933        let buffer_handle = completions_menu.buffer.clone();
 5934
 5935        let CompletionEdit {
 5936            new_text,
 5937            snippet,
 5938            replace_range,
 5939        } = process_completion_for_edit(
 5940            &completion,
 5941            intent,
 5942            &buffer_handle,
 5943            &completions_menu.initial_position.text_anchor,
 5944            cx,
 5945        );
 5946
 5947        let buffer = buffer_handle.read(cx);
 5948        let snapshot = self.buffer.read(cx).snapshot(cx);
 5949        let newest_anchor = self.selections.newest_anchor();
 5950        let replace_range_multibuffer = {
 5951            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5952            let multibuffer_anchor = snapshot
 5953                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5954                .unwrap()
 5955                ..snapshot
 5956                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5957                    .unwrap();
 5958            multibuffer_anchor.start.to_offset(&snapshot)
 5959                ..multibuffer_anchor.end.to_offset(&snapshot)
 5960        };
 5961        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5962            return None;
 5963        }
 5964
 5965        let old_text = buffer
 5966            .text_for_range(replace_range.clone())
 5967            .collect::<String>();
 5968        let lookbehind = newest_anchor
 5969            .start
 5970            .text_anchor
 5971            .to_offset(buffer)
 5972            .saturating_sub(replace_range.start);
 5973        let lookahead = replace_range
 5974            .end
 5975            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5976        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5977        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5978
 5979        let selections = self.selections.all::<usize>(cx);
 5980        let mut ranges = Vec::new();
 5981        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5982
 5983        for selection in &selections {
 5984            let range = if selection.id == newest_anchor.id {
 5985                replace_range_multibuffer.clone()
 5986            } else {
 5987                let mut range = selection.range();
 5988
 5989                // if prefix is present, don't duplicate it
 5990                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5991                    range.start = range.start.saturating_sub(lookbehind);
 5992
 5993                    // if suffix is also present, mimic the newest cursor and replace it
 5994                    if selection.id != newest_anchor.id
 5995                        && snapshot.contains_str_at(range.end, suffix)
 5996                    {
 5997                        range.end += lookahead;
 5998                    }
 5999                }
 6000                range
 6001            };
 6002
 6003            ranges.push(range.clone());
 6004
 6005            if !self.linked_edit_ranges.is_empty() {
 6006                let start_anchor = snapshot.anchor_before(range.start);
 6007                let end_anchor = snapshot.anchor_after(range.end);
 6008                if let Some(ranges) = self
 6009                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6010                {
 6011                    for (buffer, edits) in ranges {
 6012                        linked_edits
 6013                            .entry(buffer.clone())
 6014                            .or_default()
 6015                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6016                    }
 6017                }
 6018            }
 6019        }
 6020
 6021        let common_prefix_len = old_text
 6022            .chars()
 6023            .zip(new_text.chars())
 6024            .take_while(|(a, b)| a == b)
 6025            .map(|(a, _)| a.len_utf8())
 6026            .sum::<usize>();
 6027
 6028        cx.emit(EditorEvent::InputHandled {
 6029            utf16_range_to_replace: None,
 6030            text: new_text[common_prefix_len..].into(),
 6031        });
 6032
 6033        self.transact(window, cx, |editor, window, cx| {
 6034            if let Some(mut snippet) = snippet {
 6035                snippet.text = new_text.to_string();
 6036                editor
 6037                    .insert_snippet(&ranges, snippet, window, cx)
 6038                    .log_err();
 6039            } else {
 6040                editor.buffer.update(cx, |multi_buffer, cx| {
 6041                    let auto_indent = match completion.insert_text_mode {
 6042                        Some(InsertTextMode::AS_IS) => None,
 6043                        _ => editor.autoindent_mode.clone(),
 6044                    };
 6045                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6046                    multi_buffer.edit(edits, auto_indent, cx);
 6047                });
 6048            }
 6049            for (buffer, edits) in linked_edits {
 6050                buffer.update(cx, |buffer, cx| {
 6051                    let snapshot = buffer.snapshot();
 6052                    let edits = edits
 6053                        .into_iter()
 6054                        .map(|(range, text)| {
 6055                            use text::ToPoint as TP;
 6056                            let end_point = TP::to_point(&range.end, &snapshot);
 6057                            let start_point = TP::to_point(&range.start, &snapshot);
 6058                            (start_point..end_point, text)
 6059                        })
 6060                        .sorted_by_key(|(range, _)| range.start);
 6061                    buffer.edit(edits, None, cx);
 6062                })
 6063            }
 6064
 6065            editor.refresh_edit_prediction(true, false, window, cx);
 6066        });
 6067        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6068
 6069        let show_new_completions_on_confirm = completion
 6070            .confirm
 6071            .as_ref()
 6072            .is_some_and(|confirm| confirm(intent, window, cx));
 6073        if show_new_completions_on_confirm {
 6074            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6075        }
 6076
 6077        let provider = self.completion_provider.as_ref()?;
 6078        drop(completion);
 6079        let apply_edits = provider.apply_additional_edits_for_completion(
 6080            buffer_handle,
 6081            completions_menu.completions.clone(),
 6082            candidate_id,
 6083            true,
 6084            cx,
 6085        );
 6086
 6087        let editor_settings = EditorSettings::get_global(cx);
 6088        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6089            // After the code completion is finished, users often want to know what signatures are needed.
 6090            // so we should automatically call signature_help
 6091            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6092        }
 6093
 6094        Some(cx.foreground_executor().spawn(async move {
 6095            apply_edits.await?;
 6096            Ok(())
 6097        }))
 6098    }
 6099
 6100    pub fn toggle_code_actions(
 6101        &mut self,
 6102        action: &ToggleCodeActions,
 6103        window: &mut Window,
 6104        cx: &mut Context<Self>,
 6105    ) {
 6106        let quick_launch = action.quick_launch;
 6107        let mut context_menu = self.context_menu.borrow_mut();
 6108        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6109            if code_actions.deployed_from == action.deployed_from {
 6110                // Toggle if we're selecting the same one
 6111                *context_menu = None;
 6112                cx.notify();
 6113                return;
 6114            } else {
 6115                // Otherwise, clear it and start a new one
 6116                *context_menu = None;
 6117                cx.notify();
 6118            }
 6119        }
 6120        drop(context_menu);
 6121        let snapshot = self.snapshot(window, cx);
 6122        let deployed_from = action.deployed_from.clone();
 6123        let action = action.clone();
 6124        self.completion_tasks.clear();
 6125        self.discard_edit_prediction(false, cx);
 6126
 6127        let multibuffer_point = match &action.deployed_from {
 6128            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6129                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6130            }
 6131            _ => self.selections.newest::<Point>(cx).head(),
 6132        };
 6133        let Some((buffer, buffer_row)) = snapshot
 6134            .buffer_snapshot
 6135            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6136            .and_then(|(buffer_snapshot, range)| {
 6137                self.buffer()
 6138                    .read(cx)
 6139                    .buffer(buffer_snapshot.remote_id())
 6140                    .map(|buffer| (buffer, range.start.row))
 6141            })
 6142        else {
 6143            return;
 6144        };
 6145        let buffer_id = buffer.read(cx).remote_id();
 6146        let tasks = self
 6147            .tasks
 6148            .get(&(buffer_id, buffer_row))
 6149            .map(|t| Arc::new(t.to_owned()));
 6150
 6151        if !self.focus_handle.is_focused(window) {
 6152            return;
 6153        }
 6154        let project = self.project.clone();
 6155
 6156        let code_actions_task = match deployed_from {
 6157            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6158            _ => self.code_actions(buffer_row, window, cx),
 6159        };
 6160
 6161        let runnable_task = match deployed_from {
 6162            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6163            _ => {
 6164                let mut task_context_task = Task::ready(None);
 6165                if let Some(tasks) = &tasks
 6166                    && let Some(project) = project
 6167                {
 6168                    task_context_task =
 6169                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6170                }
 6171
 6172                cx.spawn_in(window, {
 6173                    let buffer = buffer.clone();
 6174                    async move |editor, cx| {
 6175                        let task_context = task_context_task.await;
 6176
 6177                        let resolved_tasks =
 6178                            tasks
 6179                                .zip(task_context.clone())
 6180                                .map(|(tasks, task_context)| ResolvedTasks {
 6181                                    templates: tasks.resolve(&task_context).collect(),
 6182                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6183                                        multibuffer_point.row,
 6184                                        tasks.column,
 6185                                    )),
 6186                                });
 6187                        let debug_scenarios = editor
 6188                            .update(cx, |editor, cx| {
 6189                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6190                            })?
 6191                            .await;
 6192                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6193                    }
 6194                })
 6195            }
 6196        };
 6197
 6198        cx.spawn_in(window, async move |editor, cx| {
 6199            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6200            let code_actions = code_actions_task.await;
 6201            let spawn_straight_away = quick_launch
 6202                && resolved_tasks
 6203                    .as_ref()
 6204                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6205                && code_actions
 6206                    .as_ref()
 6207                    .is_none_or(|actions| actions.is_empty())
 6208                && debug_scenarios.is_empty();
 6209
 6210            editor.update_in(cx, |editor, window, cx| {
 6211                crate::hover_popover::hide_hover(editor, cx);
 6212                let actions = CodeActionContents::new(
 6213                    resolved_tasks,
 6214                    code_actions,
 6215                    debug_scenarios,
 6216                    task_context.unwrap_or_default(),
 6217                );
 6218
 6219                // Don't show the menu if there are no actions available
 6220                if actions.is_empty() {
 6221                    cx.notify();
 6222                    return Task::ready(Ok(()));
 6223                }
 6224
 6225                *editor.context_menu.borrow_mut() =
 6226                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6227                        buffer,
 6228                        actions,
 6229                        selected_item: Default::default(),
 6230                        scroll_handle: UniformListScrollHandle::default(),
 6231                        deployed_from,
 6232                    }));
 6233                cx.notify();
 6234                if spawn_straight_away
 6235                    && let Some(task) = editor.confirm_code_action(
 6236                        &ConfirmCodeAction { item_ix: Some(0) },
 6237                        window,
 6238                        cx,
 6239                    )
 6240                {
 6241                    return task;
 6242                }
 6243
 6244                Task::ready(Ok(()))
 6245            })
 6246        })
 6247        .detach_and_log_err(cx);
 6248    }
 6249
 6250    fn debug_scenarios(
 6251        &mut self,
 6252        resolved_tasks: &Option<ResolvedTasks>,
 6253        buffer: &Entity<Buffer>,
 6254        cx: &mut App,
 6255    ) -> Task<Vec<task::DebugScenario>> {
 6256        maybe!({
 6257            let project = self.project()?;
 6258            let dap_store = project.read(cx).dap_store();
 6259            let mut scenarios = vec![];
 6260            let resolved_tasks = resolved_tasks.as_ref()?;
 6261            let buffer = buffer.read(cx);
 6262            let language = buffer.language()?;
 6263            let file = buffer.file();
 6264            let debug_adapter = language_settings(language.name().into(), file, cx)
 6265                .debuggers
 6266                .first()
 6267                .map(SharedString::from)
 6268                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6269
 6270            dap_store.update(cx, |dap_store, cx| {
 6271                for (_, task) in &resolved_tasks.templates {
 6272                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6273                        task.original_task().clone(),
 6274                        debug_adapter.clone().into(),
 6275                        task.display_label().to_owned().into(),
 6276                        cx,
 6277                    );
 6278                    scenarios.push(maybe_scenario);
 6279                }
 6280            });
 6281            Some(cx.background_spawn(async move {
 6282                futures::future::join_all(scenarios)
 6283                    .await
 6284                    .into_iter()
 6285                    .flatten()
 6286                    .collect::<Vec<_>>()
 6287            }))
 6288        })
 6289        .unwrap_or_else(|| Task::ready(vec![]))
 6290    }
 6291
 6292    fn code_actions(
 6293        &mut self,
 6294        buffer_row: u32,
 6295        window: &mut Window,
 6296        cx: &mut Context<Self>,
 6297    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6298        let mut task = self.code_actions_task.take();
 6299        cx.spawn_in(window, async move |editor, cx| {
 6300            while let Some(prev_task) = task {
 6301                prev_task.await.log_err();
 6302                task = editor
 6303                    .update(cx, |this, _| this.code_actions_task.take())
 6304                    .ok()?;
 6305            }
 6306
 6307            editor
 6308                .update(cx, |editor, cx| {
 6309                    editor
 6310                        .available_code_actions
 6311                        .clone()
 6312                        .and_then(|(location, code_actions)| {
 6313                            let snapshot = location.buffer.read(cx).snapshot();
 6314                            let point_range = location.range.to_point(&snapshot);
 6315                            let point_range = point_range.start.row..=point_range.end.row;
 6316                            if point_range.contains(&buffer_row) {
 6317                                Some(code_actions)
 6318                            } else {
 6319                                None
 6320                            }
 6321                        })
 6322                })
 6323                .ok()
 6324                .flatten()
 6325        })
 6326    }
 6327
 6328    pub fn confirm_code_action(
 6329        &mut self,
 6330        action: &ConfirmCodeAction,
 6331        window: &mut Window,
 6332        cx: &mut Context<Self>,
 6333    ) -> Option<Task<Result<()>>> {
 6334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6335
 6336        let actions_menu =
 6337            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6338                menu
 6339            } else {
 6340                return None;
 6341            };
 6342
 6343        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6344        let action = actions_menu.actions.get(action_ix)?;
 6345        let title = action.label();
 6346        let buffer = actions_menu.buffer;
 6347        let workspace = self.workspace()?;
 6348
 6349        match action {
 6350            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6351                workspace.update(cx, |workspace, cx| {
 6352                    workspace.schedule_resolved_task(
 6353                        task_source_kind,
 6354                        resolved_task,
 6355                        false,
 6356                        window,
 6357                        cx,
 6358                    );
 6359
 6360                    Some(Task::ready(Ok(())))
 6361                })
 6362            }
 6363            CodeActionsItem::CodeAction {
 6364                excerpt_id,
 6365                action,
 6366                provider,
 6367            } => {
 6368                let apply_code_action =
 6369                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6370                let workspace = workspace.downgrade();
 6371                Some(cx.spawn_in(window, async move |editor, cx| {
 6372                    let project_transaction = apply_code_action.await?;
 6373                    Self::open_project_transaction(
 6374                        &editor,
 6375                        workspace,
 6376                        project_transaction,
 6377                        title,
 6378                        cx,
 6379                    )
 6380                    .await
 6381                }))
 6382            }
 6383            CodeActionsItem::DebugScenario(scenario) => {
 6384                let context = actions_menu.actions.context;
 6385
 6386                workspace.update(cx, |workspace, cx| {
 6387                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6388                    workspace.start_debug_session(
 6389                        scenario,
 6390                        context,
 6391                        Some(buffer),
 6392                        None,
 6393                        window,
 6394                        cx,
 6395                    );
 6396                });
 6397                Some(Task::ready(Ok(())))
 6398            }
 6399        }
 6400    }
 6401
 6402    pub async fn open_project_transaction(
 6403        editor: &WeakEntity<Editor>,
 6404        workspace: WeakEntity<Workspace>,
 6405        transaction: ProjectTransaction,
 6406        title: String,
 6407        cx: &mut AsyncWindowContext,
 6408    ) -> Result<()> {
 6409        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6410        cx.update(|_, cx| {
 6411            entries.sort_unstable_by_key(|(buffer, _)| {
 6412                buffer.read(cx).file().map(|f| f.path().clone())
 6413            });
 6414        })?;
 6415
 6416        // If the project transaction's edits are all contained within this editor, then
 6417        // avoid opening a new editor to display them.
 6418
 6419        if let Some((buffer, transaction)) = entries.first() {
 6420            if entries.len() == 1 {
 6421                let excerpt = editor.update(cx, |editor, cx| {
 6422                    editor
 6423                        .buffer()
 6424                        .read(cx)
 6425                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6426                })?;
 6427                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6428                    && excerpted_buffer == *buffer
 6429                {
 6430                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6431                        let excerpt_range = excerpt_range.to_offset(buffer);
 6432                        buffer
 6433                            .edited_ranges_for_transaction::<usize>(transaction)
 6434                            .all(|range| {
 6435                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6436                            })
 6437                    })?;
 6438
 6439                    if all_edits_within_excerpt {
 6440                        return Ok(());
 6441                    }
 6442                }
 6443            }
 6444        } else {
 6445            return Ok(());
 6446        }
 6447
 6448        let mut ranges_to_highlight = Vec::new();
 6449        let excerpt_buffer = cx.new(|cx| {
 6450            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6451            for (buffer_handle, transaction) in &entries {
 6452                let edited_ranges = buffer_handle
 6453                    .read(cx)
 6454                    .edited_ranges_for_transaction::<Point>(transaction)
 6455                    .collect::<Vec<_>>();
 6456                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6457                    PathKey::for_buffer(buffer_handle, cx),
 6458                    buffer_handle.clone(),
 6459                    edited_ranges,
 6460                    multibuffer_context_lines(cx),
 6461                    cx,
 6462                );
 6463
 6464                ranges_to_highlight.extend(ranges);
 6465            }
 6466            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6467            multibuffer
 6468        })?;
 6469
 6470        workspace.update_in(cx, |workspace, window, cx| {
 6471            let project = workspace.project().clone();
 6472            let editor =
 6473                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6474            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6475            editor.update(cx, |editor, cx| {
 6476                editor.highlight_background::<Self>(
 6477                    &ranges_to_highlight,
 6478                    |theme| theme.colors().editor_highlighted_line_background,
 6479                    cx,
 6480                );
 6481            });
 6482        })?;
 6483
 6484        Ok(())
 6485    }
 6486
 6487    pub fn clear_code_action_providers(&mut self) {
 6488        self.code_action_providers.clear();
 6489        self.available_code_actions.take();
 6490    }
 6491
 6492    pub fn add_code_action_provider(
 6493        &mut self,
 6494        provider: Rc<dyn CodeActionProvider>,
 6495        window: &mut Window,
 6496        cx: &mut Context<Self>,
 6497    ) {
 6498        if self
 6499            .code_action_providers
 6500            .iter()
 6501            .any(|existing_provider| existing_provider.id() == provider.id())
 6502        {
 6503            return;
 6504        }
 6505
 6506        self.code_action_providers.push(provider);
 6507        self.refresh_code_actions(window, cx);
 6508    }
 6509
 6510    pub fn remove_code_action_provider(
 6511        &mut self,
 6512        id: Arc<str>,
 6513        window: &mut Window,
 6514        cx: &mut Context<Self>,
 6515    ) {
 6516        self.code_action_providers
 6517            .retain(|provider| provider.id() != id);
 6518        self.refresh_code_actions(window, cx);
 6519    }
 6520
 6521    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6522        !self.code_action_providers.is_empty()
 6523            && EditorSettings::get_global(cx).toolbar.code_actions
 6524    }
 6525
 6526    pub fn has_available_code_actions(&self) -> bool {
 6527        self.available_code_actions
 6528            .as_ref()
 6529            .is_some_and(|(_, actions)| !actions.is_empty())
 6530    }
 6531
 6532    fn render_inline_code_actions(
 6533        &self,
 6534        icon_size: ui::IconSize,
 6535        display_row: DisplayRow,
 6536        is_active: bool,
 6537        cx: &mut Context<Self>,
 6538    ) -> AnyElement {
 6539        let show_tooltip = !self.context_menu_visible();
 6540        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6541            .icon_size(icon_size)
 6542            .shape(ui::IconButtonShape::Square)
 6543            .icon_color(ui::Color::Hidden)
 6544            .toggle_state(is_active)
 6545            .when(show_tooltip, |this| {
 6546                this.tooltip({
 6547                    let focus_handle = self.focus_handle.clone();
 6548                    move |window, cx| {
 6549                        Tooltip::for_action_in(
 6550                            "Toggle Code Actions",
 6551                            &ToggleCodeActions {
 6552                                deployed_from: None,
 6553                                quick_launch: false,
 6554                            },
 6555                            &focus_handle,
 6556                            window,
 6557                            cx,
 6558                        )
 6559                    }
 6560                })
 6561            })
 6562            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6563                window.focus(&editor.focus_handle(cx));
 6564                editor.toggle_code_actions(
 6565                    &crate::actions::ToggleCodeActions {
 6566                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6567                            display_row,
 6568                        )),
 6569                        quick_launch: false,
 6570                    },
 6571                    window,
 6572                    cx,
 6573                );
 6574            }))
 6575            .into_any_element()
 6576    }
 6577
 6578    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6579        &self.context_menu
 6580    }
 6581
 6582    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6583        let newest_selection = self.selections.newest_anchor().clone();
 6584        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6585        let buffer = self.buffer.read(cx);
 6586        if newest_selection.head().diff_base_anchor.is_some() {
 6587            return None;
 6588        }
 6589        let (start_buffer, start) =
 6590            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6591        let (end_buffer, end) =
 6592            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6593        if start_buffer != end_buffer {
 6594            return None;
 6595        }
 6596
 6597        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6598            cx.background_executor()
 6599                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6600                .await;
 6601
 6602            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6603                let providers = this.code_action_providers.clone();
 6604                let tasks = this
 6605                    .code_action_providers
 6606                    .iter()
 6607                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6608                    .collect::<Vec<_>>();
 6609                (providers, tasks)
 6610            })?;
 6611
 6612            let mut actions = Vec::new();
 6613            for (provider, provider_actions) in
 6614                providers.into_iter().zip(future::join_all(tasks).await)
 6615            {
 6616                if let Some(provider_actions) = provider_actions.log_err() {
 6617                    actions.extend(provider_actions.into_iter().map(|action| {
 6618                        AvailableCodeAction {
 6619                            excerpt_id: newest_selection.start.excerpt_id,
 6620                            action,
 6621                            provider: provider.clone(),
 6622                        }
 6623                    }));
 6624                }
 6625            }
 6626
 6627            this.update(cx, |this, cx| {
 6628                this.available_code_actions = if actions.is_empty() {
 6629                    None
 6630                } else {
 6631                    Some((
 6632                        Location {
 6633                            buffer: start_buffer,
 6634                            range: start..end,
 6635                        },
 6636                        actions.into(),
 6637                    ))
 6638                };
 6639                cx.notify();
 6640            })
 6641        }));
 6642        None
 6643    }
 6644
 6645    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6646        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6647            self.show_git_blame_inline = false;
 6648
 6649            self.show_git_blame_inline_delay_task =
 6650                Some(cx.spawn_in(window, async move |this, cx| {
 6651                    cx.background_executor().timer(delay).await;
 6652
 6653                    this.update(cx, |this, cx| {
 6654                        this.show_git_blame_inline = true;
 6655                        cx.notify();
 6656                    })
 6657                    .log_err();
 6658                }));
 6659        }
 6660    }
 6661
 6662    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6663        let snapshot = self.snapshot(window, cx);
 6664        let cursor = self.selections.newest::<Point>(cx).head();
 6665        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6666        else {
 6667            return;
 6668        };
 6669
 6670        let Some(blame) = self.blame.as_ref() else {
 6671            return;
 6672        };
 6673
 6674        let row_info = RowInfo {
 6675            buffer_id: Some(buffer.remote_id()),
 6676            buffer_row: Some(point.row),
 6677            ..Default::default()
 6678        };
 6679        let Some((buffer, blame_entry)) = blame
 6680            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6681            .flatten()
 6682        else {
 6683            return;
 6684        };
 6685
 6686        let anchor = self.selections.newest_anchor().head();
 6687        let position = self.to_pixel_point(anchor, &snapshot, window);
 6688        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6689            self.show_blame_popover(
 6690                buffer,
 6691                &blame_entry,
 6692                position + last_bounds.origin,
 6693                true,
 6694                cx,
 6695            );
 6696        };
 6697    }
 6698
 6699    fn show_blame_popover(
 6700        &mut self,
 6701        buffer: BufferId,
 6702        blame_entry: &BlameEntry,
 6703        position: gpui::Point<Pixels>,
 6704        ignore_timeout: bool,
 6705        cx: &mut Context<Self>,
 6706    ) {
 6707        if let Some(state) = &mut self.inline_blame_popover {
 6708            state.hide_task.take();
 6709        } else {
 6710            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6711            let blame_entry = blame_entry.clone();
 6712            let show_task = cx.spawn(async move |editor, cx| {
 6713                if !ignore_timeout {
 6714                    cx.background_executor()
 6715                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6716                        .await;
 6717                }
 6718                editor
 6719                    .update(cx, |editor, cx| {
 6720                        editor.inline_blame_popover_show_task.take();
 6721                        let Some(blame) = editor.blame.as_ref() else {
 6722                            return;
 6723                        };
 6724                        let blame = blame.read(cx);
 6725                        let details = blame.details_for_entry(buffer, &blame_entry);
 6726                        let markdown = cx.new(|cx| {
 6727                            Markdown::new(
 6728                                details
 6729                                    .as_ref()
 6730                                    .map(|message| message.message.clone())
 6731                                    .unwrap_or_default(),
 6732                                None,
 6733                                None,
 6734                                cx,
 6735                            )
 6736                        });
 6737                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6738                            position,
 6739                            hide_task: None,
 6740                            popover_bounds: None,
 6741                            popover_state: InlineBlamePopoverState {
 6742                                scroll_handle: ScrollHandle::new(),
 6743                                commit_message: details,
 6744                                markdown,
 6745                            },
 6746                            keyboard_grace: ignore_timeout,
 6747                        });
 6748                        cx.notify();
 6749                    })
 6750                    .ok();
 6751            });
 6752            self.inline_blame_popover_show_task = Some(show_task);
 6753        }
 6754    }
 6755
 6756    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6757        self.inline_blame_popover_show_task.take();
 6758        if let Some(state) = &mut self.inline_blame_popover {
 6759            let hide_task = cx.spawn(async move |editor, cx| {
 6760                cx.background_executor()
 6761                    .timer(std::time::Duration::from_millis(100))
 6762                    .await;
 6763                editor
 6764                    .update(cx, |editor, cx| {
 6765                        editor.inline_blame_popover.take();
 6766                        cx.notify();
 6767                    })
 6768                    .ok();
 6769            });
 6770            state.hide_task = Some(hide_task);
 6771        }
 6772    }
 6773
 6774    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6775        if self.pending_rename.is_some() {
 6776            return None;
 6777        }
 6778
 6779        let provider = self.semantics_provider.clone()?;
 6780        let buffer = self.buffer.read(cx);
 6781        let newest_selection = self.selections.newest_anchor().clone();
 6782        let cursor_position = newest_selection.head();
 6783        let (cursor_buffer, cursor_buffer_position) =
 6784            buffer.text_anchor_for_position(cursor_position, cx)?;
 6785        let (tail_buffer, tail_buffer_position) =
 6786            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6787        if cursor_buffer != tail_buffer {
 6788            return None;
 6789        }
 6790
 6791        let snapshot = cursor_buffer.read(cx).snapshot();
 6792        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6793        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6794        if start_word_range != end_word_range {
 6795            self.document_highlights_task.take();
 6796            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6797            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6798            return None;
 6799        }
 6800
 6801        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6802        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6803            cx.background_executor()
 6804                .timer(Duration::from_millis(debounce))
 6805                .await;
 6806
 6807            let highlights = if let Some(highlights) = cx
 6808                .update(|cx| {
 6809                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6810                })
 6811                .ok()
 6812                .flatten()
 6813            {
 6814                highlights.await.log_err()
 6815            } else {
 6816                None
 6817            };
 6818
 6819            if let Some(highlights) = highlights {
 6820                this.update(cx, |this, cx| {
 6821                    if this.pending_rename.is_some() {
 6822                        return;
 6823                    }
 6824
 6825                    let buffer = this.buffer.read(cx);
 6826                    if buffer
 6827                        .text_anchor_for_position(cursor_position, cx)
 6828                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6829                    {
 6830                        return;
 6831                    }
 6832
 6833                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6834                    let mut write_ranges = Vec::new();
 6835                    let mut read_ranges = Vec::new();
 6836                    for highlight in highlights {
 6837                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6838                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6839                        {
 6840                            let start = highlight
 6841                                .range
 6842                                .start
 6843                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6844                            let end = highlight
 6845                                .range
 6846                                .end
 6847                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6848                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6849                                continue;
 6850                            }
 6851
 6852                            let range = Anchor {
 6853                                buffer_id: Some(buffer_id),
 6854                                excerpt_id,
 6855                                text_anchor: start,
 6856                                diff_base_anchor: None,
 6857                            }..Anchor {
 6858                                buffer_id: Some(buffer_id),
 6859                                excerpt_id,
 6860                                text_anchor: end,
 6861                                diff_base_anchor: None,
 6862                            };
 6863                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6864                                write_ranges.push(range);
 6865                            } else {
 6866                                read_ranges.push(range);
 6867                            }
 6868                        }
 6869                    }
 6870
 6871                    this.highlight_background::<DocumentHighlightRead>(
 6872                        &read_ranges,
 6873                        |theme| theme.colors().editor_document_highlight_read_background,
 6874                        cx,
 6875                    );
 6876                    this.highlight_background::<DocumentHighlightWrite>(
 6877                        &write_ranges,
 6878                        |theme| theme.colors().editor_document_highlight_write_background,
 6879                        cx,
 6880                    );
 6881                    cx.notify();
 6882                })
 6883                .log_err();
 6884            }
 6885        }));
 6886        None
 6887    }
 6888
 6889    fn prepare_highlight_query_from_selection(
 6890        &mut self,
 6891        cx: &mut Context<Editor>,
 6892    ) -> Option<(String, Range<Anchor>)> {
 6893        if matches!(self.mode, EditorMode::SingleLine) {
 6894            return None;
 6895        }
 6896        if !EditorSettings::get_global(cx).selection_highlight {
 6897            return None;
 6898        }
 6899        if self.selections.count() != 1 || self.selections.line_mode {
 6900            return None;
 6901        }
 6902        let selection = self.selections.newest::<Point>(cx);
 6903        if selection.is_empty() || selection.start.row != selection.end.row {
 6904            return None;
 6905        }
 6906        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6907        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6908        let query = multi_buffer_snapshot
 6909            .text_for_range(selection_anchor_range.clone())
 6910            .collect::<String>();
 6911        if query.trim().is_empty() {
 6912            return None;
 6913        }
 6914        Some((query, selection_anchor_range))
 6915    }
 6916
 6917    fn update_selection_occurrence_highlights(
 6918        &mut self,
 6919        query_text: String,
 6920        query_range: Range<Anchor>,
 6921        multi_buffer_range_to_query: Range<Point>,
 6922        use_debounce: bool,
 6923        window: &mut Window,
 6924        cx: &mut Context<Editor>,
 6925    ) -> Task<()> {
 6926        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6927        cx.spawn_in(window, async move |editor, cx| {
 6928            if use_debounce {
 6929                cx.background_executor()
 6930                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6931                    .await;
 6932            }
 6933            let match_task = cx.background_spawn(async move {
 6934                let buffer_ranges = multi_buffer_snapshot
 6935                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6936                    .into_iter()
 6937                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6938                let mut match_ranges = Vec::new();
 6939                let Ok(regex) = project::search::SearchQuery::text(
 6940                    query_text.clone(),
 6941                    false,
 6942                    false,
 6943                    false,
 6944                    Default::default(),
 6945                    Default::default(),
 6946                    false,
 6947                    None,
 6948                ) else {
 6949                    return Vec::default();
 6950                };
 6951                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6952                    match_ranges.extend(
 6953                        regex
 6954                            .search(buffer_snapshot, Some(search_range.clone()))
 6955                            .await
 6956                            .into_iter()
 6957                            .filter_map(|match_range| {
 6958                                let match_start = buffer_snapshot
 6959                                    .anchor_after(search_range.start + match_range.start);
 6960                                let match_end = buffer_snapshot
 6961                                    .anchor_before(search_range.start + match_range.end);
 6962                                let match_anchor_range = Anchor::range_in_buffer(
 6963                                    excerpt_id,
 6964                                    buffer_snapshot.remote_id(),
 6965                                    match_start..match_end,
 6966                                );
 6967                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6968                            }),
 6969                    );
 6970                }
 6971                match_ranges
 6972            });
 6973            let match_ranges = match_task.await;
 6974            editor
 6975                .update_in(cx, |editor, _, cx| {
 6976                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6977                    if !match_ranges.is_empty() {
 6978                        editor.highlight_background::<SelectedTextHighlight>(
 6979                            &match_ranges,
 6980                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6981                            cx,
 6982                        )
 6983                    }
 6984                })
 6985                .log_err();
 6986        })
 6987    }
 6988
 6989    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6990        struct NewlineFold;
 6991        let type_id = std::any::TypeId::of::<NewlineFold>();
 6992        if !self.mode.is_single_line() {
 6993            return;
 6994        }
 6995        let snapshot = self.snapshot(window, cx);
 6996        if snapshot.buffer_snapshot.max_point().row == 0 {
 6997            return;
 6998        }
 6999        let task = cx.background_spawn(async move {
 7000            let new_newlines = snapshot
 7001                .buffer_chars_at(0)
 7002                .filter_map(|(c, i)| {
 7003                    if c == '\n' {
 7004                        Some(
 7005                            snapshot.buffer_snapshot.anchor_after(i)
 7006                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7007                        )
 7008                    } else {
 7009                        None
 7010                    }
 7011                })
 7012                .collect::<Vec<_>>();
 7013            let existing_newlines = snapshot
 7014                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7015                .filter_map(|fold| {
 7016                    if fold.placeholder.type_tag == Some(type_id) {
 7017                        Some(fold.range.start..fold.range.end)
 7018                    } else {
 7019                        None
 7020                    }
 7021                })
 7022                .collect::<Vec<_>>();
 7023
 7024            (new_newlines, existing_newlines)
 7025        });
 7026        self.folding_newlines = cx.spawn(async move |this, cx| {
 7027            let (new_newlines, existing_newlines) = task.await;
 7028            if new_newlines == existing_newlines {
 7029                return;
 7030            }
 7031            let placeholder = FoldPlaceholder {
 7032                render: Arc::new(move |_, _, cx| {
 7033                    div()
 7034                        .bg(cx.theme().status().hint_background)
 7035                        .border_b_1()
 7036                        .size_full()
 7037                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7038                        .border_color(cx.theme().status().hint)
 7039                        .child("\\n")
 7040                        .into_any()
 7041                }),
 7042                constrain_width: false,
 7043                merge_adjacent: false,
 7044                type_tag: Some(type_id),
 7045            };
 7046            let creases = new_newlines
 7047                .into_iter()
 7048                .map(|range| Crease::simple(range, placeholder.clone()))
 7049                .collect();
 7050            this.update(cx, |this, cx| {
 7051                this.display_map.update(cx, |display_map, cx| {
 7052                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7053                    display_map.fold(creases, cx);
 7054                });
 7055            })
 7056            .ok();
 7057        });
 7058    }
 7059
 7060    fn refresh_selected_text_highlights(
 7061        &mut self,
 7062        on_buffer_edit: bool,
 7063        window: &mut Window,
 7064        cx: &mut Context<Editor>,
 7065    ) {
 7066        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7067        else {
 7068            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7069            self.quick_selection_highlight_task.take();
 7070            self.debounced_selection_highlight_task.take();
 7071            return;
 7072        };
 7073        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7074        if on_buffer_edit
 7075            || self
 7076                .quick_selection_highlight_task
 7077                .as_ref()
 7078                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7079        {
 7080            let multi_buffer_visible_start = self
 7081                .scroll_manager
 7082                .anchor()
 7083                .anchor
 7084                .to_point(&multi_buffer_snapshot);
 7085            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7086                multi_buffer_visible_start
 7087                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7088                Bias::Left,
 7089            );
 7090            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7091            self.quick_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text.clone(),
 7095                    query_range.clone(),
 7096                    multi_buffer_visible_range,
 7097                    false,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103        if on_buffer_edit
 7104            || self
 7105                .debounced_selection_highlight_task
 7106                .as_ref()
 7107                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7108        {
 7109            let multi_buffer_start = multi_buffer_snapshot
 7110                .anchor_before(0)
 7111                .to_point(&multi_buffer_snapshot);
 7112            let multi_buffer_end = multi_buffer_snapshot
 7113                .anchor_after(multi_buffer_snapshot.len())
 7114                .to_point(&multi_buffer_snapshot);
 7115            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7116            self.debounced_selection_highlight_task = Some((
 7117                query_range.clone(),
 7118                self.update_selection_occurrence_highlights(
 7119                    query_text,
 7120                    query_range,
 7121                    multi_buffer_full_range,
 7122                    true,
 7123                    window,
 7124                    cx,
 7125                ),
 7126            ));
 7127        }
 7128    }
 7129
 7130    pub fn refresh_edit_prediction(
 7131        &mut self,
 7132        debounce: bool,
 7133        user_requested: bool,
 7134        window: &mut Window,
 7135        cx: &mut Context<Self>,
 7136    ) -> Option<()> {
 7137        if DisableAiSettings::get_global(cx).disable_ai {
 7138            return None;
 7139        }
 7140
 7141        let provider = self.edit_prediction_provider()?;
 7142        let cursor = self.selections.newest_anchor().head();
 7143        let (buffer, cursor_buffer_position) =
 7144            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7145
 7146        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7147            self.discard_edit_prediction(false, cx);
 7148            return None;
 7149        }
 7150
 7151        if !user_requested
 7152            && (!self.should_show_edit_predictions()
 7153                || !self.is_focused(window)
 7154                || buffer.read(cx).is_empty())
 7155        {
 7156            self.discard_edit_prediction(false, cx);
 7157            return None;
 7158        }
 7159
 7160        self.update_visible_edit_prediction(window, cx);
 7161        provider.refresh(
 7162            self.project.clone(),
 7163            buffer,
 7164            cursor_buffer_position,
 7165            debounce,
 7166            cx,
 7167        );
 7168        Some(())
 7169    }
 7170
 7171    fn show_edit_predictions_in_menu(&self) -> bool {
 7172        match self.edit_prediction_settings {
 7173            EditPredictionSettings::Disabled => false,
 7174            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7175        }
 7176    }
 7177
 7178    pub fn edit_predictions_enabled(&self) -> bool {
 7179        match self.edit_prediction_settings {
 7180            EditPredictionSettings::Disabled => false,
 7181            EditPredictionSettings::Enabled { .. } => true,
 7182        }
 7183    }
 7184
 7185    fn edit_prediction_requires_modifier(&self) -> bool {
 7186        match self.edit_prediction_settings {
 7187            EditPredictionSettings::Disabled => false,
 7188            EditPredictionSettings::Enabled {
 7189                preview_requires_modifier,
 7190                ..
 7191            } => preview_requires_modifier,
 7192        }
 7193    }
 7194
 7195    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7196        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7197            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7198            self.discard_edit_prediction(false, cx);
 7199        } else {
 7200            let selection = self.selections.newest_anchor();
 7201            let cursor = selection.head();
 7202
 7203            if let Some((buffer, cursor_buffer_position)) =
 7204                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7205            {
 7206                self.edit_prediction_settings =
 7207                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7208            }
 7209        }
 7210    }
 7211
 7212    fn edit_prediction_settings_at_position(
 7213        &self,
 7214        buffer: &Entity<Buffer>,
 7215        buffer_position: language::Anchor,
 7216        cx: &App,
 7217    ) -> EditPredictionSettings {
 7218        if !self.mode.is_full()
 7219            || !self.show_edit_predictions_override.unwrap_or(true)
 7220            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7221        {
 7222            return EditPredictionSettings::Disabled;
 7223        }
 7224
 7225        let buffer = buffer.read(cx);
 7226
 7227        let file = buffer.file();
 7228
 7229        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7230            return EditPredictionSettings::Disabled;
 7231        };
 7232
 7233        let by_provider = matches!(
 7234            self.menu_edit_predictions_policy,
 7235            MenuEditPredictionsPolicy::ByProvider
 7236        );
 7237
 7238        let show_in_menu = by_provider
 7239            && self
 7240                .edit_prediction_provider
 7241                .as_ref()
 7242                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7243
 7244        let preview_requires_modifier =
 7245            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7246
 7247        EditPredictionSettings::Enabled {
 7248            show_in_menu,
 7249            preview_requires_modifier,
 7250        }
 7251    }
 7252
 7253    fn should_show_edit_predictions(&self) -> bool {
 7254        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7255    }
 7256
 7257    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7258        matches!(
 7259            self.edit_prediction_preview,
 7260            EditPredictionPreview::Active { .. }
 7261        )
 7262    }
 7263
 7264    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7265        let cursor = self.selections.newest_anchor().head();
 7266        if let Some((buffer, cursor_position)) =
 7267            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7268        {
 7269            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7270        } else {
 7271            false
 7272        }
 7273    }
 7274
 7275    pub fn supports_minimap(&self, cx: &App) -> bool {
 7276        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7277    }
 7278
 7279    fn edit_predictions_enabled_in_buffer(
 7280        &self,
 7281        buffer: &Entity<Buffer>,
 7282        buffer_position: language::Anchor,
 7283        cx: &App,
 7284    ) -> bool {
 7285        maybe!({
 7286            if self.read_only(cx) {
 7287                return Some(false);
 7288            }
 7289            let provider = self.edit_prediction_provider()?;
 7290            if !provider.is_enabled(buffer, buffer_position, cx) {
 7291                return Some(false);
 7292            }
 7293            let buffer = buffer.read(cx);
 7294            let Some(file) = buffer.file() else {
 7295                return Some(true);
 7296            };
 7297            let settings = all_language_settings(Some(file), cx);
 7298            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7299        })
 7300        .unwrap_or(false)
 7301    }
 7302
 7303    fn cycle_edit_prediction(
 7304        &mut self,
 7305        direction: Direction,
 7306        window: &mut Window,
 7307        cx: &mut Context<Self>,
 7308    ) -> Option<()> {
 7309        let provider = self.edit_prediction_provider()?;
 7310        let cursor = self.selections.newest_anchor().head();
 7311        let (buffer, cursor_buffer_position) =
 7312            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7313        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7314            return None;
 7315        }
 7316
 7317        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7318        self.update_visible_edit_prediction(window, cx);
 7319
 7320        Some(())
 7321    }
 7322
 7323    pub fn show_edit_prediction(
 7324        &mut self,
 7325        _: &ShowEditPrediction,
 7326        window: &mut Window,
 7327        cx: &mut Context<Self>,
 7328    ) {
 7329        if !self.has_active_edit_prediction() {
 7330            self.refresh_edit_prediction(false, true, window, cx);
 7331            return;
 7332        }
 7333
 7334        self.update_visible_edit_prediction(window, cx);
 7335    }
 7336
 7337    pub fn display_cursor_names(
 7338        &mut self,
 7339        _: &DisplayCursorNames,
 7340        window: &mut Window,
 7341        cx: &mut Context<Self>,
 7342    ) {
 7343        self.show_cursor_names(window, cx);
 7344    }
 7345
 7346    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7347        self.show_cursor_names = true;
 7348        cx.notify();
 7349        cx.spawn_in(window, async move |this, cx| {
 7350            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7351            this.update(cx, |this, cx| {
 7352                this.show_cursor_names = false;
 7353                cx.notify()
 7354            })
 7355            .ok()
 7356        })
 7357        .detach();
 7358    }
 7359
 7360    pub fn next_edit_prediction(
 7361        &mut self,
 7362        _: &NextEditPrediction,
 7363        window: &mut Window,
 7364        cx: &mut Context<Self>,
 7365    ) {
 7366        if self.has_active_edit_prediction() {
 7367            self.cycle_edit_prediction(Direction::Next, window, cx);
 7368        } else {
 7369            let is_copilot_disabled = self
 7370                .refresh_edit_prediction(false, true, window, cx)
 7371                .is_none();
 7372            if is_copilot_disabled {
 7373                cx.propagate();
 7374            }
 7375        }
 7376    }
 7377
 7378    pub fn previous_edit_prediction(
 7379        &mut self,
 7380        _: &PreviousEditPrediction,
 7381        window: &mut Window,
 7382        cx: &mut Context<Self>,
 7383    ) {
 7384        if self.has_active_edit_prediction() {
 7385            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7386        } else {
 7387            let is_copilot_disabled = self
 7388                .refresh_edit_prediction(false, true, window, cx)
 7389                .is_none();
 7390            if is_copilot_disabled {
 7391                cx.propagate();
 7392            }
 7393        }
 7394    }
 7395
 7396    pub fn accept_edit_prediction(
 7397        &mut self,
 7398        _: &AcceptEditPrediction,
 7399        window: &mut Window,
 7400        cx: &mut Context<Self>,
 7401    ) {
 7402        if self.show_edit_predictions_in_menu() {
 7403            self.hide_context_menu(window, cx);
 7404        }
 7405
 7406        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7407            return;
 7408        };
 7409
 7410        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7411
 7412        match &active_edit_prediction.completion {
 7413            EditPrediction::Move { target, .. } => {
 7414                let target = *target;
 7415
 7416                if let Some(position_map) = &self.last_position_map {
 7417                    if position_map
 7418                        .visible_row_range
 7419                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7420                        || !self.edit_prediction_requires_modifier()
 7421                    {
 7422                        self.unfold_ranges(&[target..target], true, false, cx);
 7423                        // Note that this is also done in vim's handler of the Tab action.
 7424                        self.change_selections(
 7425                            SelectionEffects::scroll(Autoscroll::newest()),
 7426                            window,
 7427                            cx,
 7428                            |selections| {
 7429                                selections.select_anchor_ranges([target..target]);
 7430                            },
 7431                        );
 7432                        self.clear_row_highlights::<EditPredictionPreview>();
 7433
 7434                        self.edit_prediction_preview
 7435                            .set_previous_scroll_position(None);
 7436                    } else {
 7437                        self.edit_prediction_preview
 7438                            .set_previous_scroll_position(Some(
 7439                                position_map.snapshot.scroll_anchor,
 7440                            ));
 7441
 7442                        self.highlight_rows::<EditPredictionPreview>(
 7443                            target..target,
 7444                            cx.theme().colors().editor_highlighted_line_background,
 7445                            RowHighlightOptions {
 7446                                autoscroll: true,
 7447                                ..Default::default()
 7448                            },
 7449                            cx,
 7450                        );
 7451                        self.request_autoscroll(Autoscroll::fit(), cx);
 7452                    }
 7453                }
 7454            }
 7455            EditPrediction::Edit { edits, .. } => {
 7456                if let Some(provider) = self.edit_prediction_provider() {
 7457                    provider.accept(cx);
 7458                }
 7459
 7460                // Store the transaction ID and selections before applying the edit
 7461                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7462
 7463                let snapshot = self.buffer.read(cx).snapshot(cx);
 7464                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7465
 7466                self.buffer.update(cx, |buffer, cx| {
 7467                    buffer.edit(edits.iter().cloned(), None, cx)
 7468                });
 7469
 7470                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7471                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7472                });
 7473
 7474                let selections = self.selections.disjoint_anchors_arc();
 7475                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7476                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7477                    if has_new_transaction {
 7478                        self.selection_history
 7479                            .insert_transaction(transaction_id_now, selections);
 7480                    }
 7481                }
 7482
 7483                self.update_visible_edit_prediction(window, cx);
 7484                if self.active_edit_prediction.is_none() {
 7485                    self.refresh_edit_prediction(true, true, window, cx);
 7486                }
 7487
 7488                cx.notify();
 7489            }
 7490        }
 7491
 7492        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7493    }
 7494
 7495    pub fn accept_partial_edit_prediction(
 7496        &mut self,
 7497        _: &AcceptPartialEditPrediction,
 7498        window: &mut Window,
 7499        cx: &mut Context<Self>,
 7500    ) {
 7501        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7502            return;
 7503        };
 7504        if self.selections.count() != 1 {
 7505            return;
 7506        }
 7507
 7508        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7509
 7510        match &active_edit_prediction.completion {
 7511            EditPrediction::Move { target, .. } => {
 7512                let target = *target;
 7513                self.change_selections(
 7514                    SelectionEffects::scroll(Autoscroll::newest()),
 7515                    window,
 7516                    cx,
 7517                    |selections| {
 7518                        selections.select_anchor_ranges([target..target]);
 7519                    },
 7520                );
 7521            }
 7522            EditPrediction::Edit { edits, .. } => {
 7523                // Find an insertion that starts at the cursor position.
 7524                let snapshot = self.buffer.read(cx).snapshot(cx);
 7525                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7526                let insertion = edits.iter().find_map(|(range, text)| {
 7527                    let range = range.to_offset(&snapshot);
 7528                    if range.is_empty() && range.start == cursor_offset {
 7529                        Some(text)
 7530                    } else {
 7531                        None
 7532                    }
 7533                });
 7534
 7535                if let Some(text) = insertion {
 7536                    let mut partial_completion = text
 7537                        .chars()
 7538                        .by_ref()
 7539                        .take_while(|c| c.is_alphabetic())
 7540                        .collect::<String>();
 7541                    if partial_completion.is_empty() {
 7542                        partial_completion = text
 7543                            .chars()
 7544                            .by_ref()
 7545                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7546                            .collect::<String>();
 7547                    }
 7548
 7549                    cx.emit(EditorEvent::InputHandled {
 7550                        utf16_range_to_replace: None,
 7551                        text: partial_completion.clone().into(),
 7552                    });
 7553
 7554                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7555
 7556                    self.refresh_edit_prediction(true, true, window, cx);
 7557                    cx.notify();
 7558                } else {
 7559                    self.accept_edit_prediction(&Default::default(), window, cx);
 7560                }
 7561            }
 7562        }
 7563    }
 7564
 7565    fn discard_edit_prediction(
 7566        &mut self,
 7567        should_report_edit_prediction_event: bool,
 7568        cx: &mut Context<Self>,
 7569    ) -> bool {
 7570        if should_report_edit_prediction_event {
 7571            let completion_id = self
 7572                .active_edit_prediction
 7573                .as_ref()
 7574                .and_then(|active_completion| active_completion.completion_id.clone());
 7575
 7576            self.report_edit_prediction_event(completion_id, false, cx);
 7577        }
 7578
 7579        if let Some(provider) = self.edit_prediction_provider() {
 7580            provider.discard(cx);
 7581        }
 7582
 7583        self.take_active_edit_prediction(cx)
 7584    }
 7585
 7586    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7587        let Some(provider) = self.edit_prediction_provider() else {
 7588            return;
 7589        };
 7590
 7591        let Some((_, buffer, _)) = self
 7592            .buffer
 7593            .read(cx)
 7594            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7595        else {
 7596            return;
 7597        };
 7598
 7599        let extension = buffer
 7600            .read(cx)
 7601            .file()
 7602            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7603
 7604        let event_type = match accepted {
 7605            true => "Edit Prediction Accepted",
 7606            false => "Edit Prediction Discarded",
 7607        };
 7608        telemetry::event!(
 7609            event_type,
 7610            provider = provider.name(),
 7611            prediction_id = id,
 7612            suggestion_accepted = accepted,
 7613            file_extension = extension,
 7614        );
 7615    }
 7616
 7617    pub fn has_active_edit_prediction(&self) -> bool {
 7618        self.active_edit_prediction.is_some()
 7619    }
 7620
 7621    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7622        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7623            return false;
 7624        };
 7625
 7626        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7627        self.clear_highlights::<EditPredictionHighlight>(cx);
 7628        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7629        true
 7630    }
 7631
 7632    /// Returns true when we're displaying the edit prediction popover below the cursor
 7633    /// like we are not previewing and the LSP autocomplete menu is visible
 7634    /// or we are in `when_holding_modifier` mode.
 7635    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7636        if self.edit_prediction_preview_is_active()
 7637            || !self.show_edit_predictions_in_menu()
 7638            || !self.edit_predictions_enabled()
 7639        {
 7640            return false;
 7641        }
 7642
 7643        if self.has_visible_completions_menu() {
 7644            return true;
 7645        }
 7646
 7647        has_completion && self.edit_prediction_requires_modifier()
 7648    }
 7649
 7650    fn handle_modifiers_changed(
 7651        &mut self,
 7652        modifiers: Modifiers,
 7653        position_map: &PositionMap,
 7654        window: &mut Window,
 7655        cx: &mut Context<Self>,
 7656    ) {
 7657        if self.show_edit_predictions_in_menu() {
 7658            self.update_edit_prediction_preview(&modifiers, window, cx);
 7659        }
 7660
 7661        self.update_selection_mode(&modifiers, position_map, window, cx);
 7662
 7663        let mouse_position = window.mouse_position();
 7664        if !position_map.text_hitbox.is_hovered(window) {
 7665            return;
 7666        }
 7667
 7668        self.update_hovered_link(
 7669            position_map.point_for_position(mouse_position),
 7670            &position_map.snapshot,
 7671            modifiers,
 7672            window,
 7673            cx,
 7674        )
 7675    }
 7676
 7677    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7678        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7679        if invert {
 7680            match multi_cursor_setting {
 7681                MultiCursorModifier::Alt => modifiers.alt,
 7682                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7683            }
 7684        } else {
 7685            match multi_cursor_setting {
 7686                MultiCursorModifier::Alt => modifiers.secondary(),
 7687                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7688            }
 7689        }
 7690    }
 7691
 7692    fn columnar_selection_mode(
 7693        modifiers: &Modifiers,
 7694        cx: &mut Context<Self>,
 7695    ) -> Option<ColumnarMode> {
 7696        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7697            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7698                Some(ColumnarMode::FromMouse)
 7699            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7700                Some(ColumnarMode::FromSelection)
 7701            } else {
 7702                None
 7703            }
 7704        } else {
 7705            None
 7706        }
 7707    }
 7708
 7709    fn update_selection_mode(
 7710        &mut self,
 7711        modifiers: &Modifiers,
 7712        position_map: &PositionMap,
 7713        window: &mut Window,
 7714        cx: &mut Context<Self>,
 7715    ) {
 7716        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7717            return;
 7718        };
 7719        if self.selections.pending_anchor().is_none() {
 7720            return;
 7721        }
 7722
 7723        let mouse_position = window.mouse_position();
 7724        let point_for_position = position_map.point_for_position(mouse_position);
 7725        let position = point_for_position.previous_valid;
 7726
 7727        self.select(
 7728            SelectPhase::BeginColumnar {
 7729                position,
 7730                reset: false,
 7731                mode,
 7732                goal_column: point_for_position.exact_unclipped.column(),
 7733            },
 7734            window,
 7735            cx,
 7736        );
 7737    }
 7738
 7739    fn update_edit_prediction_preview(
 7740        &mut self,
 7741        modifiers: &Modifiers,
 7742        window: &mut Window,
 7743        cx: &mut Context<Self>,
 7744    ) {
 7745        let mut modifiers_held = false;
 7746        if let Some(accept_keystroke) = self
 7747            .accept_edit_prediction_keybind(false, window, cx)
 7748            .keystroke()
 7749        {
 7750            modifiers_held = modifiers_held
 7751                || (accept_keystroke.modifiers() == modifiers
 7752                    && accept_keystroke.modifiers().modified());
 7753        };
 7754        if let Some(accept_partial_keystroke) = self
 7755            .accept_edit_prediction_keybind(true, window, cx)
 7756            .keystroke()
 7757        {
 7758            modifiers_held = modifiers_held
 7759                || (accept_partial_keystroke.modifiers() == modifiers
 7760                    && accept_partial_keystroke.modifiers().modified());
 7761        }
 7762
 7763        if modifiers_held {
 7764            if matches!(
 7765                self.edit_prediction_preview,
 7766                EditPredictionPreview::Inactive { .. }
 7767            ) {
 7768                self.edit_prediction_preview = EditPredictionPreview::Active {
 7769                    previous_scroll_position: None,
 7770                    since: Instant::now(),
 7771                };
 7772
 7773                self.update_visible_edit_prediction(window, cx);
 7774                cx.notify();
 7775            }
 7776        } else if let EditPredictionPreview::Active {
 7777            previous_scroll_position,
 7778            since,
 7779        } = self.edit_prediction_preview
 7780        {
 7781            if let (Some(previous_scroll_position), Some(position_map)) =
 7782                (previous_scroll_position, self.last_position_map.as_ref())
 7783            {
 7784                self.set_scroll_position(
 7785                    previous_scroll_position
 7786                        .scroll_position(&position_map.snapshot.display_snapshot),
 7787                    window,
 7788                    cx,
 7789                );
 7790            }
 7791
 7792            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7793                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7794            };
 7795            self.clear_row_highlights::<EditPredictionPreview>();
 7796            self.update_visible_edit_prediction(window, cx);
 7797            cx.notify();
 7798        }
 7799    }
 7800
 7801    fn update_visible_edit_prediction(
 7802        &mut self,
 7803        _window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) -> Option<()> {
 7806        if DisableAiSettings::get_global(cx).disable_ai {
 7807            return None;
 7808        }
 7809
 7810        if self.ime_transaction.is_some() {
 7811            self.discard_edit_prediction(false, cx);
 7812            return None;
 7813        }
 7814
 7815        let selection = self.selections.newest_anchor();
 7816        let cursor = selection.head();
 7817        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7818        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7819        let excerpt_id = cursor.excerpt_id;
 7820
 7821        let show_in_menu = self.show_edit_predictions_in_menu();
 7822        let completions_menu_has_precedence = !show_in_menu
 7823            && (self.context_menu.borrow().is_some()
 7824                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7825
 7826        if completions_menu_has_precedence
 7827            || !offset_selection.is_empty()
 7828            || self
 7829                .active_edit_prediction
 7830                .as_ref()
 7831                .is_some_and(|completion| {
 7832                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7833                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7834                    !invalidation_range.contains(&offset_selection.head())
 7835                })
 7836        {
 7837            self.discard_edit_prediction(false, cx);
 7838            return None;
 7839        }
 7840
 7841        self.take_active_edit_prediction(cx);
 7842        let Some(provider) = self.edit_prediction_provider() else {
 7843            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7844            return None;
 7845        };
 7846
 7847        let (buffer, cursor_buffer_position) =
 7848            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7849
 7850        self.edit_prediction_settings =
 7851            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7852
 7853        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7854            self.discard_edit_prediction(false, cx);
 7855            return None;
 7856        };
 7857
 7858        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7859
 7860        if self.edit_prediction_indent_conflict {
 7861            let cursor_point = cursor.to_point(&multibuffer);
 7862
 7863            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7864
 7865            if let Some((_, indent)) = indents.iter().next()
 7866                && indent.len == cursor_point.column
 7867            {
 7868                self.edit_prediction_indent_conflict = false;
 7869            }
 7870        }
 7871
 7872        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7873        let edits = edit_prediction
 7874            .edits
 7875            .into_iter()
 7876            .flat_map(|(range, new_text)| {
 7877                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7878                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7879                Some((start..end, new_text))
 7880            })
 7881            .collect::<Vec<_>>();
 7882        if edits.is_empty() {
 7883            return None;
 7884        }
 7885
 7886        let first_edit_start = edits.first().unwrap().0.start;
 7887        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7888        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7889
 7890        let last_edit_end = edits.last().unwrap().0.end;
 7891        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7892        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7893
 7894        let cursor_row = cursor.to_point(&multibuffer).row;
 7895
 7896        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7897
 7898        let mut inlay_ids = Vec::new();
 7899        let invalidation_row_range;
 7900        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7901            Some(cursor_row..edit_end_row)
 7902        } else if cursor_row > edit_end_row {
 7903            Some(edit_start_row..cursor_row)
 7904        } else {
 7905            None
 7906        };
 7907        let supports_jump = self
 7908            .edit_prediction_provider
 7909            .as_ref()
 7910            .map(|provider| provider.provider.supports_jump_to_edit())
 7911            .unwrap_or(true);
 7912
 7913        let is_move = supports_jump
 7914            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7915        let completion = if is_move {
 7916            invalidation_row_range =
 7917                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7918            let target = first_edit_start;
 7919            EditPrediction::Move { target, snapshot }
 7920        } else {
 7921            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7922                && !self.edit_predictions_hidden_for_vim_mode;
 7923
 7924            if show_completions_in_buffer {
 7925                if edits
 7926                    .iter()
 7927                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7928                {
 7929                    let mut inlays = Vec::new();
 7930                    for (range, new_text) in &edits {
 7931                        let inlay = Inlay::edit_prediction(
 7932                            post_inc(&mut self.next_inlay_id),
 7933                            range.start,
 7934                            new_text.as_str(),
 7935                        );
 7936                        inlay_ids.push(inlay.id);
 7937                        inlays.push(inlay);
 7938                    }
 7939
 7940                    self.splice_inlays(&[], inlays, cx);
 7941                } else {
 7942                    let background_color = cx.theme().status().deleted_background;
 7943                    self.highlight_text::<EditPredictionHighlight>(
 7944                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7945                        HighlightStyle {
 7946                            background_color: Some(background_color),
 7947                            ..Default::default()
 7948                        },
 7949                        cx,
 7950                    );
 7951                }
 7952            }
 7953
 7954            invalidation_row_range = edit_start_row..edit_end_row;
 7955
 7956            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7957                if provider.show_tab_accept_marker() {
 7958                    EditDisplayMode::TabAccept
 7959                } else {
 7960                    EditDisplayMode::Inline
 7961                }
 7962            } else {
 7963                EditDisplayMode::DiffPopover
 7964            };
 7965
 7966            EditPrediction::Edit {
 7967                edits,
 7968                edit_preview: edit_prediction.edit_preview,
 7969                display_mode,
 7970                snapshot,
 7971            }
 7972        };
 7973
 7974        let invalidation_range = multibuffer
 7975            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7976            ..multibuffer.anchor_after(Point::new(
 7977                invalidation_row_range.end,
 7978                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7979            ));
 7980
 7981        self.stale_edit_prediction_in_menu = None;
 7982        self.active_edit_prediction = Some(EditPredictionState {
 7983            inlay_ids,
 7984            completion,
 7985            completion_id: edit_prediction.id,
 7986            invalidation_range,
 7987        });
 7988
 7989        cx.notify();
 7990
 7991        Some(())
 7992    }
 7993
 7994    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7995        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7996    }
 7997
 7998    fn clear_tasks(&mut self) {
 7999        self.tasks.clear()
 8000    }
 8001
 8002    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8003        if self.tasks.insert(key, value).is_some() {
 8004            // This case should hopefully be rare, but just in case...
 8005            log::error!(
 8006                "multiple different run targets found on a single line, only the last target will be rendered"
 8007            )
 8008        }
 8009    }
 8010
 8011    /// Get all display points of breakpoints that will be rendered within editor
 8012    ///
 8013    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8014    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8015    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8016    fn active_breakpoints(
 8017        &self,
 8018        range: Range<DisplayRow>,
 8019        window: &mut Window,
 8020        cx: &mut Context<Self>,
 8021    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8022        let mut breakpoint_display_points = HashMap::default();
 8023
 8024        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8025            return breakpoint_display_points;
 8026        };
 8027
 8028        let snapshot = self.snapshot(window, cx);
 8029
 8030        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8031        let Some(project) = self.project() else {
 8032            return breakpoint_display_points;
 8033        };
 8034
 8035        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8036            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8037
 8038        for (buffer_snapshot, range, excerpt_id) in
 8039            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8040        {
 8041            let Some(buffer) = project
 8042                .read(cx)
 8043                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8044            else {
 8045                continue;
 8046            };
 8047            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8048                &buffer,
 8049                Some(
 8050                    buffer_snapshot.anchor_before(range.start)
 8051                        ..buffer_snapshot.anchor_after(range.end),
 8052                ),
 8053                buffer_snapshot,
 8054                cx,
 8055            );
 8056            for (breakpoint, state) in breakpoints {
 8057                let multi_buffer_anchor =
 8058                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8059                let position = multi_buffer_anchor
 8060                    .to_point(multi_buffer_snapshot)
 8061                    .to_display_point(&snapshot);
 8062
 8063                breakpoint_display_points.insert(
 8064                    position.row(),
 8065                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8066                );
 8067            }
 8068        }
 8069
 8070        breakpoint_display_points
 8071    }
 8072
 8073    fn breakpoint_context_menu(
 8074        &self,
 8075        anchor: Anchor,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) -> Entity<ui::ContextMenu> {
 8079        let weak_editor = cx.weak_entity();
 8080        let focus_handle = self.focus_handle(cx);
 8081
 8082        let row = self
 8083            .buffer
 8084            .read(cx)
 8085            .snapshot(cx)
 8086            .summary_for_anchor::<Point>(&anchor)
 8087            .row;
 8088
 8089        let breakpoint = self
 8090            .breakpoint_at_row(row, window, cx)
 8091            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8092
 8093        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8094            "Edit Log Breakpoint"
 8095        } else {
 8096            "Set Log Breakpoint"
 8097        };
 8098
 8099        let condition_breakpoint_msg = if breakpoint
 8100            .as_ref()
 8101            .is_some_and(|bp| bp.1.condition.is_some())
 8102        {
 8103            "Edit Condition Breakpoint"
 8104        } else {
 8105            "Set Condition Breakpoint"
 8106        };
 8107
 8108        let hit_condition_breakpoint_msg = if breakpoint
 8109            .as_ref()
 8110            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8111        {
 8112            "Edit Hit Condition Breakpoint"
 8113        } else {
 8114            "Set Hit Condition Breakpoint"
 8115        };
 8116
 8117        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8118            "Unset Breakpoint"
 8119        } else {
 8120            "Set Breakpoint"
 8121        };
 8122
 8123        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8124
 8125        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8126            BreakpointState::Enabled => Some("Disable"),
 8127            BreakpointState::Disabled => Some("Enable"),
 8128        });
 8129
 8130        let (anchor, breakpoint) =
 8131            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8132
 8133        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8134            menu.on_blur_subscription(Subscription::new(|| {}))
 8135                .context(focus_handle)
 8136                .when(run_to_cursor, |this| {
 8137                    let weak_editor = weak_editor.clone();
 8138                    this.entry("Run to cursor", None, move |window, cx| {
 8139                        weak_editor
 8140                            .update(cx, |editor, cx| {
 8141                                editor.change_selections(
 8142                                    SelectionEffects::no_scroll(),
 8143                                    window,
 8144                                    cx,
 8145                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8146                                );
 8147                            })
 8148                            .ok();
 8149
 8150                        window.dispatch_action(Box::new(RunToCursor), cx);
 8151                    })
 8152                    .separator()
 8153                })
 8154                .when_some(toggle_state_msg, |this, msg| {
 8155                    this.entry(msg, None, {
 8156                        let weak_editor = weak_editor.clone();
 8157                        let breakpoint = breakpoint.clone();
 8158                        move |_window, cx| {
 8159                            weak_editor
 8160                                .update(cx, |this, cx| {
 8161                                    this.edit_breakpoint_at_anchor(
 8162                                        anchor,
 8163                                        breakpoint.as_ref().clone(),
 8164                                        BreakpointEditAction::InvertState,
 8165                                        cx,
 8166                                    );
 8167                                })
 8168                                .log_err();
 8169                        }
 8170                    })
 8171                })
 8172                .entry(set_breakpoint_msg, None, {
 8173                    let weak_editor = weak_editor.clone();
 8174                    let breakpoint = breakpoint.clone();
 8175                    move |_window, cx| {
 8176                        weak_editor
 8177                            .update(cx, |this, cx| {
 8178                                this.edit_breakpoint_at_anchor(
 8179                                    anchor,
 8180                                    breakpoint.as_ref().clone(),
 8181                                    BreakpointEditAction::Toggle,
 8182                                    cx,
 8183                                );
 8184                            })
 8185                            .log_err();
 8186                    }
 8187                })
 8188                .entry(log_breakpoint_msg, None, {
 8189                    let breakpoint = breakpoint.clone();
 8190                    let weak_editor = weak_editor.clone();
 8191                    move |window, cx| {
 8192                        weak_editor
 8193                            .update(cx, |this, cx| {
 8194                                this.add_edit_breakpoint_block(
 8195                                    anchor,
 8196                                    breakpoint.as_ref(),
 8197                                    BreakpointPromptEditAction::Log,
 8198                                    window,
 8199                                    cx,
 8200                                );
 8201                            })
 8202                            .log_err();
 8203                    }
 8204                })
 8205                .entry(condition_breakpoint_msg, None, {
 8206                    let breakpoint = breakpoint.clone();
 8207                    let weak_editor = weak_editor.clone();
 8208                    move |window, cx| {
 8209                        weak_editor
 8210                            .update(cx, |this, cx| {
 8211                                this.add_edit_breakpoint_block(
 8212                                    anchor,
 8213                                    breakpoint.as_ref(),
 8214                                    BreakpointPromptEditAction::Condition,
 8215                                    window,
 8216                                    cx,
 8217                                );
 8218                            })
 8219                            .log_err();
 8220                    }
 8221                })
 8222                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8223                    weak_editor
 8224                        .update(cx, |this, cx| {
 8225                            this.add_edit_breakpoint_block(
 8226                                anchor,
 8227                                breakpoint.as_ref(),
 8228                                BreakpointPromptEditAction::HitCondition,
 8229                                window,
 8230                                cx,
 8231                            );
 8232                        })
 8233                        .log_err();
 8234                })
 8235        })
 8236    }
 8237
 8238    fn render_breakpoint(
 8239        &self,
 8240        position: Anchor,
 8241        row: DisplayRow,
 8242        breakpoint: &Breakpoint,
 8243        state: Option<BreakpointSessionState>,
 8244        cx: &mut Context<Self>,
 8245    ) -> IconButton {
 8246        let is_rejected = state.is_some_and(|s| !s.verified);
 8247        // Is it a breakpoint that shows up when hovering over gutter?
 8248        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8249            (false, false),
 8250            |PhantomBreakpointIndicator {
 8251                 is_active,
 8252                 display_row,
 8253                 collides_with_existing_breakpoint,
 8254             }| {
 8255                (
 8256                    is_active && display_row == row,
 8257                    collides_with_existing_breakpoint,
 8258                )
 8259            },
 8260        );
 8261
 8262        let (color, icon) = {
 8263            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8264                (false, false) => ui::IconName::DebugBreakpoint,
 8265                (true, false) => ui::IconName::DebugLogBreakpoint,
 8266                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8267                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8268            };
 8269
 8270            let color = if is_phantom {
 8271                Color::Hint
 8272            } else if is_rejected {
 8273                Color::Disabled
 8274            } else {
 8275                Color::Debugger
 8276            };
 8277
 8278            (color, icon)
 8279        };
 8280
 8281        let breakpoint = Arc::from(breakpoint.clone());
 8282
 8283        let alt_as_text = gpui::Keystroke {
 8284            modifiers: Modifiers::secondary_key(),
 8285            ..Default::default()
 8286        };
 8287        let primary_action_text = if breakpoint.is_disabled() {
 8288            "Enable breakpoint"
 8289        } else if is_phantom && !collides_with_existing {
 8290            "Set breakpoint"
 8291        } else {
 8292            "Unset breakpoint"
 8293        };
 8294        let focus_handle = self.focus_handle.clone();
 8295
 8296        let meta = if is_rejected {
 8297            SharedString::from("No executable code is associated with this line.")
 8298        } else if collides_with_existing && !breakpoint.is_disabled() {
 8299            SharedString::from(format!(
 8300                "{alt_as_text}-click to disable,\nright-click for more options."
 8301            ))
 8302        } else {
 8303            SharedString::from("Right-click for more options.")
 8304        };
 8305        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8306            .icon_size(IconSize::XSmall)
 8307            .size(ui::ButtonSize::None)
 8308            .when(is_rejected, |this| {
 8309                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8310            })
 8311            .icon_color(color)
 8312            .style(ButtonStyle::Transparent)
 8313            .on_click(cx.listener({
 8314                move |editor, event: &ClickEvent, window, cx| {
 8315                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8316                        BreakpointEditAction::InvertState
 8317                    } else {
 8318                        BreakpointEditAction::Toggle
 8319                    };
 8320
 8321                    window.focus(&editor.focus_handle(cx));
 8322                    editor.edit_breakpoint_at_anchor(
 8323                        position,
 8324                        breakpoint.as_ref().clone(),
 8325                        edit_action,
 8326                        cx,
 8327                    );
 8328                }
 8329            }))
 8330            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8331                editor.set_breakpoint_context_menu(
 8332                    row,
 8333                    Some(position),
 8334                    event.position(),
 8335                    window,
 8336                    cx,
 8337                );
 8338            }))
 8339            .tooltip(move |window, cx| {
 8340                Tooltip::with_meta_in(
 8341                    primary_action_text,
 8342                    Some(&ToggleBreakpoint),
 8343                    meta.clone(),
 8344                    &focus_handle,
 8345                    window,
 8346                    cx,
 8347                )
 8348            })
 8349    }
 8350
 8351    fn build_tasks_context(
 8352        project: &Entity<Project>,
 8353        buffer: &Entity<Buffer>,
 8354        buffer_row: u32,
 8355        tasks: &Arc<RunnableTasks>,
 8356        cx: &mut Context<Self>,
 8357    ) -> Task<Option<task::TaskContext>> {
 8358        let position = Point::new(buffer_row, tasks.column);
 8359        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8360        let location = Location {
 8361            buffer: buffer.clone(),
 8362            range: range_start..range_start,
 8363        };
 8364        // Fill in the environmental variables from the tree-sitter captures
 8365        let mut captured_task_variables = TaskVariables::default();
 8366        for (capture_name, value) in tasks.extra_variables.clone() {
 8367            captured_task_variables.insert(
 8368                task::VariableName::Custom(capture_name.into()),
 8369                value.clone(),
 8370            );
 8371        }
 8372        project.update(cx, |project, cx| {
 8373            project.task_store().update(cx, |task_store, cx| {
 8374                task_store.task_context_for_location(captured_task_variables, location, cx)
 8375            })
 8376        })
 8377    }
 8378
 8379    pub fn spawn_nearest_task(
 8380        &mut self,
 8381        action: &SpawnNearestTask,
 8382        window: &mut Window,
 8383        cx: &mut Context<Self>,
 8384    ) {
 8385        let Some((workspace, _)) = self.workspace.clone() else {
 8386            return;
 8387        };
 8388        let Some(project) = self.project.clone() else {
 8389            return;
 8390        };
 8391
 8392        // Try to find a closest, enclosing node using tree-sitter that has a task
 8393        let Some((buffer, buffer_row, tasks)) = self
 8394            .find_enclosing_node_task(cx)
 8395            // Or find the task that's closest in row-distance.
 8396            .or_else(|| self.find_closest_task(cx))
 8397        else {
 8398            return;
 8399        };
 8400
 8401        let reveal_strategy = action.reveal;
 8402        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8403        cx.spawn_in(window, async move |_, cx| {
 8404            let context = task_context.await?;
 8405            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8406
 8407            let resolved = &mut resolved_task.resolved;
 8408            resolved.reveal = reveal_strategy;
 8409
 8410            workspace
 8411                .update_in(cx, |workspace, window, cx| {
 8412                    workspace.schedule_resolved_task(
 8413                        task_source_kind,
 8414                        resolved_task,
 8415                        false,
 8416                        window,
 8417                        cx,
 8418                    );
 8419                })
 8420                .ok()
 8421        })
 8422        .detach();
 8423    }
 8424
 8425    fn find_closest_task(
 8426        &mut self,
 8427        cx: &mut Context<Self>,
 8428    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8429        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8430
 8431        let ((buffer_id, row), tasks) = self
 8432            .tasks
 8433            .iter()
 8434            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8435
 8436        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8437        let tasks = Arc::new(tasks.to_owned());
 8438        Some((buffer, *row, tasks))
 8439    }
 8440
 8441    fn find_enclosing_node_task(
 8442        &mut self,
 8443        cx: &mut Context<Self>,
 8444    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8445        let snapshot = self.buffer.read(cx).snapshot(cx);
 8446        let offset = self.selections.newest::<usize>(cx).head();
 8447        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8448        let buffer_id = excerpt.buffer().remote_id();
 8449
 8450        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8451        let mut cursor = layer.node().walk();
 8452
 8453        while cursor.goto_first_child_for_byte(offset).is_some() {
 8454            if cursor.node().end_byte() == offset {
 8455                cursor.goto_next_sibling();
 8456            }
 8457        }
 8458
 8459        // Ascend to the smallest ancestor that contains the range and has a task.
 8460        loop {
 8461            let node = cursor.node();
 8462            let node_range = node.byte_range();
 8463            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8464
 8465            // Check if this node contains our offset
 8466            if node_range.start <= offset && node_range.end >= offset {
 8467                // If it contains offset, check for task
 8468                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8469                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8470                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8471                }
 8472            }
 8473
 8474            if !cursor.goto_parent() {
 8475                break;
 8476            }
 8477        }
 8478        None
 8479    }
 8480
 8481    fn render_run_indicator(
 8482        &self,
 8483        _style: &EditorStyle,
 8484        is_active: bool,
 8485        row: DisplayRow,
 8486        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8487        cx: &mut Context<Self>,
 8488    ) -> IconButton {
 8489        let color = Color::Muted;
 8490        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8491
 8492        IconButton::new(
 8493            ("run_indicator", row.0 as usize),
 8494            ui::IconName::PlayOutlined,
 8495        )
 8496        .shape(ui::IconButtonShape::Square)
 8497        .icon_size(IconSize::XSmall)
 8498        .icon_color(color)
 8499        .toggle_state(is_active)
 8500        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8501            let quick_launch = match e {
 8502                ClickEvent::Keyboard(_) => true,
 8503                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8504            };
 8505
 8506            window.focus(&editor.focus_handle(cx));
 8507            editor.toggle_code_actions(
 8508                &ToggleCodeActions {
 8509                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8510                    quick_launch,
 8511                },
 8512                window,
 8513                cx,
 8514            );
 8515        }))
 8516        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8517            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8518        }))
 8519    }
 8520
 8521    pub fn context_menu_visible(&self) -> bool {
 8522        !self.edit_prediction_preview_is_active()
 8523            && self
 8524                .context_menu
 8525                .borrow()
 8526                .as_ref()
 8527                .is_some_and(|menu| menu.visible())
 8528    }
 8529
 8530    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8531        self.context_menu
 8532            .borrow()
 8533            .as_ref()
 8534            .map(|menu| menu.origin())
 8535    }
 8536
 8537    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8538        self.context_menu_options = Some(options);
 8539    }
 8540
 8541    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8542    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8543
 8544    fn render_edit_prediction_popover(
 8545        &mut self,
 8546        text_bounds: &Bounds<Pixels>,
 8547        content_origin: gpui::Point<Pixels>,
 8548        right_margin: Pixels,
 8549        editor_snapshot: &EditorSnapshot,
 8550        visible_row_range: Range<DisplayRow>,
 8551        scroll_top: f32,
 8552        scroll_bottom: f32,
 8553        line_layouts: &[LineWithInvisibles],
 8554        line_height: Pixels,
 8555        scroll_pixel_position: gpui::Point<Pixels>,
 8556        newest_selection_head: Option<DisplayPoint>,
 8557        editor_width: Pixels,
 8558        style: &EditorStyle,
 8559        window: &mut Window,
 8560        cx: &mut App,
 8561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8562        if self.mode().is_minimap() {
 8563            return None;
 8564        }
 8565        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8566
 8567        if self.edit_prediction_visible_in_cursor_popover(true) {
 8568            return None;
 8569        }
 8570
 8571        match &active_edit_prediction.completion {
 8572            EditPrediction::Move { target, .. } => {
 8573                let target_display_point = target.to_display_point(editor_snapshot);
 8574
 8575                if self.edit_prediction_requires_modifier() {
 8576                    if !self.edit_prediction_preview_is_active() {
 8577                        return None;
 8578                    }
 8579
 8580                    self.render_edit_prediction_modifier_jump_popover(
 8581                        text_bounds,
 8582                        content_origin,
 8583                        visible_row_range,
 8584                        line_layouts,
 8585                        line_height,
 8586                        scroll_pixel_position,
 8587                        newest_selection_head,
 8588                        target_display_point,
 8589                        window,
 8590                        cx,
 8591                    )
 8592                } else {
 8593                    self.render_edit_prediction_eager_jump_popover(
 8594                        text_bounds,
 8595                        content_origin,
 8596                        editor_snapshot,
 8597                        visible_row_range,
 8598                        scroll_top,
 8599                        scroll_bottom,
 8600                        line_height,
 8601                        scroll_pixel_position,
 8602                        target_display_point,
 8603                        editor_width,
 8604                        window,
 8605                        cx,
 8606                    )
 8607                }
 8608            }
 8609            EditPrediction::Edit {
 8610                display_mode: EditDisplayMode::Inline,
 8611                ..
 8612            } => None,
 8613            EditPrediction::Edit {
 8614                display_mode: EditDisplayMode::TabAccept,
 8615                edits,
 8616                ..
 8617            } => {
 8618                let range = &edits.first()?.0;
 8619                let target_display_point = range.end.to_display_point(editor_snapshot);
 8620
 8621                self.render_edit_prediction_end_of_line_popover(
 8622                    "Accept",
 8623                    editor_snapshot,
 8624                    visible_row_range,
 8625                    target_display_point,
 8626                    line_height,
 8627                    scroll_pixel_position,
 8628                    content_origin,
 8629                    editor_width,
 8630                    window,
 8631                    cx,
 8632                )
 8633            }
 8634            EditPrediction::Edit {
 8635                edits,
 8636                edit_preview,
 8637                display_mode: EditDisplayMode::DiffPopover,
 8638                snapshot,
 8639            } => self.render_edit_prediction_diff_popover(
 8640                text_bounds,
 8641                content_origin,
 8642                right_margin,
 8643                editor_snapshot,
 8644                visible_row_range,
 8645                line_layouts,
 8646                line_height,
 8647                scroll_pixel_position,
 8648                newest_selection_head,
 8649                editor_width,
 8650                style,
 8651                edits,
 8652                edit_preview,
 8653                snapshot,
 8654                window,
 8655                cx,
 8656            ),
 8657        }
 8658    }
 8659
 8660    fn render_edit_prediction_modifier_jump_popover(
 8661        &mut self,
 8662        text_bounds: &Bounds<Pixels>,
 8663        content_origin: gpui::Point<Pixels>,
 8664        visible_row_range: Range<DisplayRow>,
 8665        line_layouts: &[LineWithInvisibles],
 8666        line_height: Pixels,
 8667        scroll_pixel_position: gpui::Point<Pixels>,
 8668        newest_selection_head: Option<DisplayPoint>,
 8669        target_display_point: DisplayPoint,
 8670        window: &mut Window,
 8671        cx: &mut App,
 8672    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8673        let scrolled_content_origin =
 8674            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8675
 8676        const SCROLL_PADDING_Y: Pixels = px(12.);
 8677
 8678        if target_display_point.row() < visible_row_range.start {
 8679            return self.render_edit_prediction_scroll_popover(
 8680                |_| SCROLL_PADDING_Y,
 8681                IconName::ArrowUp,
 8682                visible_row_range,
 8683                line_layouts,
 8684                newest_selection_head,
 8685                scrolled_content_origin,
 8686                window,
 8687                cx,
 8688            );
 8689        } else if target_display_point.row() >= visible_row_range.end {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8692                IconName::ArrowDown,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        }
 8701
 8702        const POLE_WIDTH: Pixels = px(2.);
 8703
 8704        let line_layout =
 8705            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8706        let target_column = target_display_point.column() as usize;
 8707
 8708        let target_x = line_layout.x_for_index(target_column);
 8709        let target_y =
 8710            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8711
 8712        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8713
 8714        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8715        border_color.l += 0.001;
 8716
 8717        let mut element = v_flex()
 8718            .items_end()
 8719            .when(flag_on_right, |el| el.items_start())
 8720            .child(if flag_on_right {
 8721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8722                    .rounded_bl(px(0.))
 8723                    .rounded_tl(px(0.))
 8724                    .border_l_2()
 8725                    .border_color(border_color)
 8726            } else {
 8727                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8728                    .rounded_br(px(0.))
 8729                    .rounded_tr(px(0.))
 8730                    .border_r_2()
 8731                    .border_color(border_color)
 8732            })
 8733            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8734            .into_any();
 8735
 8736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8737
 8738        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8739            - point(
 8740                if flag_on_right {
 8741                    POLE_WIDTH
 8742                } else {
 8743                    size.width - POLE_WIDTH
 8744                },
 8745                size.height - line_height,
 8746            );
 8747
 8748        origin.x = origin.x.max(content_origin.x);
 8749
 8750        element.prepaint_at(origin, window, cx);
 8751
 8752        Some((element, origin))
 8753    }
 8754
 8755    fn render_edit_prediction_scroll_popover(
 8756        &mut self,
 8757        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8758        scroll_icon: IconName,
 8759        visible_row_range: Range<DisplayRow>,
 8760        line_layouts: &[LineWithInvisibles],
 8761        newest_selection_head: Option<DisplayPoint>,
 8762        scrolled_content_origin: gpui::Point<Pixels>,
 8763        window: &mut Window,
 8764        cx: &mut App,
 8765    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8766        let mut element = self
 8767            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8768            .into_any();
 8769
 8770        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8771
 8772        let cursor = newest_selection_head?;
 8773        let cursor_row_layout =
 8774            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8775        let cursor_column = cursor.column() as usize;
 8776
 8777        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8778
 8779        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8780
 8781        element.prepaint_at(origin, window, cx);
 8782        Some((element, origin))
 8783    }
 8784
 8785    fn render_edit_prediction_eager_jump_popover(
 8786        &mut self,
 8787        text_bounds: &Bounds<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        scroll_top: f32,
 8792        scroll_bottom: f32,
 8793        line_height: Pixels,
 8794        scroll_pixel_position: gpui::Point<Pixels>,
 8795        target_display_point: DisplayPoint,
 8796        editor_width: Pixels,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        if target_display_point.row().as_f32() < scroll_top {
 8801            let mut element = self
 8802                .render_edit_prediction_line_popover(
 8803                    "Jump to Edit",
 8804                    Some(IconName::ArrowUp),
 8805                    window,
 8806                    cx,
 8807                )?
 8808                .into_any();
 8809
 8810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8811            let offset = point(
 8812                (text_bounds.size.width - size.width) / 2.,
 8813                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8814            );
 8815
 8816            let origin = text_bounds.origin + offset;
 8817            element.prepaint_at(origin, window, cx);
 8818            Some((element, origin))
 8819        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8820            let mut element = self
 8821                .render_edit_prediction_line_popover(
 8822                    "Jump to Edit",
 8823                    Some(IconName::ArrowDown),
 8824                    window,
 8825                    cx,
 8826                )?
 8827                .into_any();
 8828
 8829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830            let offset = point(
 8831                (text_bounds.size.width - size.width) / 2.,
 8832                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8833            );
 8834
 8835            let origin = text_bounds.origin + offset;
 8836            element.prepaint_at(origin, window, cx);
 8837            Some((element, origin))
 8838        } else {
 8839            self.render_edit_prediction_end_of_line_popover(
 8840                "Jump to Edit",
 8841                editor_snapshot,
 8842                visible_row_range,
 8843                target_display_point,
 8844                line_height,
 8845                scroll_pixel_position,
 8846                content_origin,
 8847                editor_width,
 8848                window,
 8849                cx,
 8850            )
 8851        }
 8852    }
 8853
 8854    fn render_edit_prediction_end_of_line_popover(
 8855        self: &mut Editor,
 8856        label: &'static str,
 8857        editor_snapshot: &EditorSnapshot,
 8858        visible_row_range: Range<DisplayRow>,
 8859        target_display_point: DisplayPoint,
 8860        line_height: Pixels,
 8861        scroll_pixel_position: gpui::Point<Pixels>,
 8862        content_origin: gpui::Point<Pixels>,
 8863        editor_width: Pixels,
 8864        window: &mut Window,
 8865        cx: &mut App,
 8866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8867        let target_line_end = DisplayPoint::new(
 8868            target_display_point.row(),
 8869            editor_snapshot.line_len(target_display_point.row()),
 8870        );
 8871
 8872        let mut element = self
 8873            .render_edit_prediction_line_popover(label, None, window, cx)?
 8874            .into_any();
 8875
 8876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8879
 8880        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8881        let mut origin = start_point
 8882            + line_origin
 8883            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8884        origin.x = origin.x.max(content_origin.x);
 8885
 8886        let max_x = content_origin.x + editor_width - size.width;
 8887
 8888        if origin.x > max_x {
 8889            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8890
 8891            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8892                origin.y += offset;
 8893                IconName::ArrowUp
 8894            } else {
 8895                origin.y -= offset;
 8896                IconName::ArrowDown
 8897            };
 8898
 8899            element = self
 8900                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8901                .into_any();
 8902
 8903            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8904
 8905            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8906        }
 8907
 8908        element.prepaint_at(origin, window, cx);
 8909        Some((element, origin))
 8910    }
 8911
 8912    fn render_edit_prediction_diff_popover(
 8913        self: &Editor,
 8914        text_bounds: &Bounds<Pixels>,
 8915        content_origin: gpui::Point<Pixels>,
 8916        right_margin: Pixels,
 8917        editor_snapshot: &EditorSnapshot,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        line_height: Pixels,
 8921        scroll_pixel_position: gpui::Point<Pixels>,
 8922        newest_selection_head: Option<DisplayPoint>,
 8923        editor_width: Pixels,
 8924        style: &EditorStyle,
 8925        edits: &Vec<(Range<Anchor>, String)>,
 8926        edit_preview: &Option<language::EditPreview>,
 8927        snapshot: &language::BufferSnapshot,
 8928        window: &mut Window,
 8929        cx: &mut App,
 8930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8931        let edit_start = edits
 8932            .first()
 8933            .unwrap()
 8934            .0
 8935            .start
 8936            .to_display_point(editor_snapshot);
 8937        let edit_end = edits
 8938            .last()
 8939            .unwrap()
 8940            .0
 8941            .end
 8942            .to_display_point(editor_snapshot);
 8943
 8944        let is_visible = visible_row_range.contains(&edit_start.row())
 8945            || visible_row_range.contains(&edit_end.row());
 8946        if !is_visible {
 8947            return None;
 8948        }
 8949
 8950        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8951            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8952        } else {
 8953            // Fallback for providers without edit_preview
 8954            crate::edit_prediction_fallback_text(edits, cx)
 8955        };
 8956
 8957        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8958        let line_count = highlighted_edits.text.lines().count();
 8959
 8960        const BORDER_WIDTH: Pixels = px(1.);
 8961
 8962        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8963        let has_keybind = keybind.is_some();
 8964
 8965        let mut element = h_flex()
 8966            .items_start()
 8967            .child(
 8968                h_flex()
 8969                    .bg(cx.theme().colors().editor_background)
 8970                    .border(BORDER_WIDTH)
 8971                    .shadow_xs()
 8972                    .border_color(cx.theme().colors().border)
 8973                    .rounded_l_lg()
 8974                    .when(line_count > 1, |el| el.rounded_br_lg())
 8975                    .pr_1()
 8976                    .child(styled_text),
 8977            )
 8978            .child(
 8979                h_flex()
 8980                    .h(line_height + BORDER_WIDTH * 2.)
 8981                    .px_1p5()
 8982                    .gap_1()
 8983                    // Workaround: For some reason, there's a gap if we don't do this
 8984                    .ml(-BORDER_WIDTH)
 8985                    .shadow(vec![gpui::BoxShadow {
 8986                        color: gpui::black().opacity(0.05),
 8987                        offset: point(px(1.), px(1.)),
 8988                        blur_radius: px(2.),
 8989                        spread_radius: px(0.),
 8990                    }])
 8991                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8992                    .border(BORDER_WIDTH)
 8993                    .border_color(cx.theme().colors().border)
 8994                    .rounded_r_lg()
 8995                    .id("edit_prediction_diff_popover_keybind")
 8996                    .when(!has_keybind, |el| {
 8997                        let status_colors = cx.theme().status();
 8998
 8999                        el.bg(status_colors.error_background)
 9000                            .border_color(status_colors.error.opacity(0.6))
 9001                            .child(Icon::new(IconName::Info).color(Color::Error))
 9002                            .cursor_default()
 9003                            .hoverable_tooltip(move |_window, cx| {
 9004                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9005                            })
 9006                    })
 9007                    .children(keybind),
 9008            )
 9009            .into_any();
 9010
 9011        let longest_row =
 9012            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9013        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9014            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9015        } else {
 9016            layout_line(
 9017                longest_row,
 9018                editor_snapshot,
 9019                style,
 9020                editor_width,
 9021                |_| false,
 9022                window,
 9023                cx,
 9024            )
 9025            .width
 9026        };
 9027
 9028        let viewport_bounds =
 9029            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9030                right: -right_margin,
 9031                ..Default::default()
 9032            });
 9033
 9034        let x_after_longest =
 9035            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9036                - scroll_pixel_position.x;
 9037
 9038        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9039
 9040        // Fully visible if it can be displayed within the window (allow overlapping other
 9041        // panes). However, this is only allowed if the popover starts within text_bounds.
 9042        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9043            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9044
 9045        let mut origin = if can_position_to_the_right {
 9046            point(
 9047                x_after_longest,
 9048                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9049                    - scroll_pixel_position.y,
 9050            )
 9051        } else {
 9052            let cursor_row = newest_selection_head.map(|head| head.row());
 9053            let above_edit = edit_start
 9054                .row()
 9055                .0
 9056                .checked_sub(line_count as u32)
 9057                .map(DisplayRow);
 9058            let below_edit = Some(edit_end.row() + 1);
 9059            let above_cursor =
 9060                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9061            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9062
 9063            // Place the edit popover adjacent to the edit if there is a location
 9064            // available that is onscreen and does not obscure the cursor. Otherwise,
 9065            // place it adjacent to the cursor.
 9066            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9067                .into_iter()
 9068                .flatten()
 9069                .find(|&start_row| {
 9070                    let end_row = start_row + line_count as u32;
 9071                    visible_row_range.contains(&start_row)
 9072                        && visible_row_range.contains(&end_row)
 9073                        && cursor_row
 9074                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9075                })?;
 9076
 9077            content_origin
 9078                + point(
 9079                    -scroll_pixel_position.x,
 9080                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9081                )
 9082        };
 9083
 9084        origin.x -= BORDER_WIDTH;
 9085
 9086        window.defer_draw(element, origin, 1);
 9087
 9088        // Do not return an element, since it will already be drawn due to defer_draw.
 9089        None
 9090    }
 9091
 9092    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9093        px(30.)
 9094    }
 9095
 9096    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9097        if self.read_only(cx) {
 9098            cx.theme().players().read_only()
 9099        } else {
 9100            self.style.as_ref().unwrap().local_player
 9101        }
 9102    }
 9103
 9104    fn render_edit_prediction_accept_keybind(
 9105        &self,
 9106        window: &mut Window,
 9107        cx: &App,
 9108    ) -> Option<AnyElement> {
 9109        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9110        let accept_keystroke = accept_binding.keystroke()?;
 9111
 9112        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9113
 9114        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9115            Color::Accent
 9116        } else {
 9117            Color::Muted
 9118        };
 9119
 9120        h_flex()
 9121            .px_0p5()
 9122            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9123            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9124            .text_size(TextSize::XSmall.rems(cx))
 9125            .child(h_flex().children(ui::render_modifiers(
 9126                accept_keystroke.modifiers(),
 9127                PlatformStyle::platform(),
 9128                Some(modifiers_color),
 9129                Some(IconSize::XSmall.rems().into()),
 9130                true,
 9131            )))
 9132            .when(is_platform_style_mac, |parent| {
 9133                parent.child(accept_keystroke.key().to_string())
 9134            })
 9135            .when(!is_platform_style_mac, |parent| {
 9136                parent.child(
 9137                    Key::new(
 9138                        util::capitalize(accept_keystroke.key()),
 9139                        Some(Color::Default),
 9140                    )
 9141                    .size(Some(IconSize::XSmall.rems().into())),
 9142                )
 9143            })
 9144            .into_any()
 9145            .into()
 9146    }
 9147
 9148    fn render_edit_prediction_line_popover(
 9149        &self,
 9150        label: impl Into<SharedString>,
 9151        icon: Option<IconName>,
 9152        window: &mut Window,
 9153        cx: &App,
 9154    ) -> Option<Stateful<Div>> {
 9155        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        let result = h_flex()
 9161            .id("ep-line-popover")
 9162            .py_0p5()
 9163            .pl_1()
 9164            .pr(padding_right)
 9165            .gap_1()
 9166            .rounded_md()
 9167            .border_1()
 9168            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9169            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9170            .shadow_xs()
 9171            .when(!has_keybind, |el| {
 9172                let status_colors = cx.theme().status();
 9173
 9174                el.bg(status_colors.error_background)
 9175                    .border_color(status_colors.error.opacity(0.6))
 9176                    .pl_2()
 9177                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9178                    .cursor_default()
 9179                    .hoverable_tooltip(move |_window, cx| {
 9180                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9181                    })
 9182            })
 9183            .children(keybind)
 9184            .child(
 9185                Label::new(label)
 9186                    .size(LabelSize::Small)
 9187                    .when(!has_keybind, |el| {
 9188                        el.color(cx.theme().status().error.into()).strikethrough()
 9189                    }),
 9190            )
 9191            .when(!has_keybind, |el| {
 9192                el.child(
 9193                    h_flex().ml_1().child(
 9194                        Icon::new(IconName::Info)
 9195                            .size(IconSize::Small)
 9196                            .color(cx.theme().status().error.into()),
 9197                    ),
 9198                )
 9199            })
 9200            .when_some(icon, |element, icon| {
 9201                element.child(
 9202                    div()
 9203                        .mt(px(1.5))
 9204                        .child(Icon::new(icon).size(IconSize::Small)),
 9205                )
 9206            });
 9207
 9208        Some(result)
 9209    }
 9210
 9211    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9212        let accent_color = cx.theme().colors().text_accent;
 9213        let editor_bg_color = cx.theme().colors().editor_background;
 9214        editor_bg_color.blend(accent_color.opacity(0.1))
 9215    }
 9216
 9217    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9218        let accent_color = cx.theme().colors().text_accent;
 9219        let editor_bg_color = cx.theme().colors().editor_background;
 9220        editor_bg_color.blend(accent_color.opacity(0.6))
 9221    }
 9222    fn get_prediction_provider_icon_name(
 9223        provider: &Option<RegisteredEditPredictionProvider>,
 9224    ) -> IconName {
 9225        match provider {
 9226            Some(provider) => match provider.provider.name() {
 9227                "copilot" => IconName::Copilot,
 9228                "supermaven" => IconName::Supermaven,
 9229                _ => IconName::ZedPredict,
 9230            },
 9231            None => IconName::ZedPredict,
 9232        }
 9233    }
 9234
 9235    fn render_edit_prediction_cursor_popover(
 9236        &self,
 9237        min_width: Pixels,
 9238        max_width: Pixels,
 9239        cursor_point: Point,
 9240        style: &EditorStyle,
 9241        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9242        _window: &Window,
 9243        cx: &mut Context<Editor>,
 9244    ) -> Option<AnyElement> {
 9245        let provider = self.edit_prediction_provider.as_ref()?;
 9246        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9247
 9248        let is_refreshing = provider.provider.is_refreshing(cx);
 9249
 9250        fn pending_completion_container(icon: IconName) -> Div {
 9251            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9252        }
 9253
 9254        let completion = match &self.active_edit_prediction {
 9255            Some(prediction) => {
 9256                if !self.has_visible_completions_menu() {
 9257                    const RADIUS: Pixels = px(6.);
 9258                    const BORDER_WIDTH: Pixels = px(1.);
 9259
 9260                    return Some(
 9261                        h_flex()
 9262                            .elevation_2(cx)
 9263                            .border(BORDER_WIDTH)
 9264                            .border_color(cx.theme().colors().border)
 9265                            .when(accept_keystroke.is_none(), |el| {
 9266                                el.border_color(cx.theme().status().error)
 9267                            })
 9268                            .rounded(RADIUS)
 9269                            .rounded_tl(px(0.))
 9270                            .overflow_hidden()
 9271                            .child(div().px_1p5().child(match &prediction.completion {
 9272                                EditPrediction::Move { target, snapshot } => {
 9273                                    use text::ToPoint as _;
 9274                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9275                                    {
 9276                                        Icon::new(IconName::ZedPredictDown)
 9277                                    } else {
 9278                                        Icon::new(IconName::ZedPredictUp)
 9279                                    }
 9280                                }
 9281                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9282                            }))
 9283                            .child(
 9284                                h_flex()
 9285                                    .gap_1()
 9286                                    .py_1()
 9287                                    .px_2()
 9288                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9289                                    .border_l_1()
 9290                                    .border_color(cx.theme().colors().border)
 9291                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9292                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9293                                        el.child(
 9294                                            Label::new("Hold")
 9295                                                .size(LabelSize::Small)
 9296                                                .when(accept_keystroke.is_none(), |el| {
 9297                                                    el.strikethrough()
 9298                                                })
 9299                                                .line_height_style(LineHeightStyle::UiLabel),
 9300                                        )
 9301                                    })
 9302                                    .id("edit_prediction_cursor_popover_keybind")
 9303                                    .when(accept_keystroke.is_none(), |el| {
 9304                                        let status_colors = cx.theme().status();
 9305
 9306                                        el.bg(status_colors.error_background)
 9307                                            .border_color(status_colors.error.opacity(0.6))
 9308                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9309                                            .cursor_default()
 9310                                            .hoverable_tooltip(move |_window, cx| {
 9311                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9312                                                    .into()
 9313                                            })
 9314                                    })
 9315                                    .when_some(
 9316                                        accept_keystroke.as_ref(),
 9317                                        |el, accept_keystroke| {
 9318                                            el.child(h_flex().children(ui::render_modifiers(
 9319                                                accept_keystroke.modifiers(),
 9320                                                PlatformStyle::platform(),
 9321                                                Some(Color::Default),
 9322                                                Some(IconSize::XSmall.rems().into()),
 9323                                                false,
 9324                                            )))
 9325                                        },
 9326                                    ),
 9327                            )
 9328                            .into_any(),
 9329                    );
 9330                }
 9331
 9332                self.render_edit_prediction_cursor_popover_preview(
 9333                    prediction,
 9334                    cursor_point,
 9335                    style,
 9336                    cx,
 9337                )?
 9338            }
 9339
 9340            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9341                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9342                    stale_completion,
 9343                    cursor_point,
 9344                    style,
 9345                    cx,
 9346                )?,
 9347
 9348                None => pending_completion_container(provider_icon)
 9349                    .child(Label::new("...").size(LabelSize::Small)),
 9350            },
 9351
 9352            None => pending_completion_container(provider_icon)
 9353                .child(Label::new("...").size(LabelSize::Small)),
 9354        };
 9355
 9356        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9357            completion
 9358                .with_animation(
 9359                    "loading-completion",
 9360                    Animation::new(Duration::from_secs(2))
 9361                        .repeat()
 9362                        .with_easing(pulsating_between(0.4, 0.8)),
 9363                    |label, delta| label.opacity(delta),
 9364                )
 9365                .into_any_element()
 9366        } else {
 9367            completion.into_any_element()
 9368        };
 9369
 9370        let has_completion = self.active_edit_prediction.is_some();
 9371
 9372        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9373        Some(
 9374            h_flex()
 9375                .min_w(min_width)
 9376                .max_w(max_width)
 9377                .flex_1()
 9378                .elevation_2(cx)
 9379                .border_color(cx.theme().colors().border)
 9380                .child(
 9381                    div()
 9382                        .flex_1()
 9383                        .py_1()
 9384                        .px_2()
 9385                        .overflow_hidden()
 9386                        .child(completion),
 9387                )
 9388                .when_some(accept_keystroke, |el, accept_keystroke| {
 9389                    if !accept_keystroke.modifiers().modified() {
 9390                        return el;
 9391                    }
 9392
 9393                    el.child(
 9394                        h_flex()
 9395                            .h_full()
 9396                            .border_l_1()
 9397                            .rounded_r_lg()
 9398                            .border_color(cx.theme().colors().border)
 9399                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9400                            .gap_1()
 9401                            .py_1()
 9402                            .px_2()
 9403                            .child(
 9404                                h_flex()
 9405                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9406                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9407                                    .child(h_flex().children(ui::render_modifiers(
 9408                                        accept_keystroke.modifiers(),
 9409                                        PlatformStyle::platform(),
 9410                                        Some(if !has_completion {
 9411                                            Color::Muted
 9412                                        } else {
 9413                                            Color::Default
 9414                                        }),
 9415                                        None,
 9416                                        false,
 9417                                    ))),
 9418                            )
 9419                            .child(Label::new("Preview").into_any_element())
 9420                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9421                    )
 9422                })
 9423                .into_any(),
 9424        )
 9425    }
 9426
 9427    fn render_edit_prediction_cursor_popover_preview(
 9428        &self,
 9429        completion: &EditPredictionState,
 9430        cursor_point: Point,
 9431        style: &EditorStyle,
 9432        cx: &mut Context<Editor>,
 9433    ) -> Option<Div> {
 9434        use text::ToPoint as _;
 9435
 9436        fn render_relative_row_jump(
 9437            prefix: impl Into<String>,
 9438            current_row: u32,
 9439            target_row: u32,
 9440        ) -> Div {
 9441            let (row_diff, arrow) = if target_row < current_row {
 9442                (current_row - target_row, IconName::ArrowUp)
 9443            } else {
 9444                (target_row - current_row, IconName::ArrowDown)
 9445            };
 9446
 9447            h_flex()
 9448                .child(
 9449                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9450                        .color(Color::Muted)
 9451                        .size(LabelSize::Small),
 9452                )
 9453                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9454        }
 9455
 9456        let supports_jump = self
 9457            .edit_prediction_provider
 9458            .as_ref()
 9459            .map(|provider| provider.provider.supports_jump_to_edit())
 9460            .unwrap_or(true);
 9461
 9462        match &completion.completion {
 9463            EditPrediction::Move {
 9464                target, snapshot, ..
 9465            } => {
 9466                if !supports_jump {
 9467                    return None;
 9468                }
 9469
 9470                Some(
 9471                    h_flex()
 9472                        .px_2()
 9473                        .gap_2()
 9474                        .flex_1()
 9475                        .child(
 9476                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9477                                Icon::new(IconName::ZedPredictDown)
 9478                            } else {
 9479                                Icon::new(IconName::ZedPredictUp)
 9480                            },
 9481                        )
 9482                        .child(Label::new("Jump to Edit")),
 9483                )
 9484            }
 9485
 9486            EditPrediction::Edit {
 9487                edits,
 9488                edit_preview,
 9489                snapshot,
 9490                display_mode: _,
 9491            } => {
 9492                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9493
 9494                let (highlighted_edits, has_more_lines) =
 9495                    if let Some(edit_preview) = edit_preview.as_ref() {
 9496                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9497                            .first_line_preview()
 9498                    } else {
 9499                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9500                    };
 9501
 9502                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9503                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9504
 9505                let preview = h_flex()
 9506                    .gap_1()
 9507                    .min_w_16()
 9508                    .child(styled_text)
 9509                    .when(has_more_lines, |parent| parent.child(""));
 9510
 9511                let left = if supports_jump && first_edit_row != cursor_point.row {
 9512                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9513                        .into_any_element()
 9514                } else {
 9515                    let icon_name =
 9516                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9517                    Icon::new(icon_name).into_any_element()
 9518                };
 9519
 9520                Some(
 9521                    h_flex()
 9522                        .h_full()
 9523                        .flex_1()
 9524                        .gap_2()
 9525                        .pr_1()
 9526                        .overflow_x_hidden()
 9527                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9528                        .child(left)
 9529                        .child(preview),
 9530                )
 9531            }
 9532        }
 9533    }
 9534
 9535    pub fn render_context_menu(
 9536        &self,
 9537        style: &EditorStyle,
 9538        max_height_in_lines: u32,
 9539        window: &mut Window,
 9540        cx: &mut Context<Editor>,
 9541    ) -> Option<AnyElement> {
 9542        let menu = self.context_menu.borrow();
 9543        let menu = menu.as_ref()?;
 9544        if !menu.visible() {
 9545            return None;
 9546        };
 9547        Some(menu.render(style, max_height_in_lines, window, cx))
 9548    }
 9549
 9550    fn render_context_menu_aside(
 9551        &mut self,
 9552        max_size: Size<Pixels>,
 9553        window: &mut Window,
 9554        cx: &mut Context<Editor>,
 9555    ) -> Option<AnyElement> {
 9556        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9557            if menu.visible() {
 9558                menu.render_aside(max_size, window, cx)
 9559            } else {
 9560                None
 9561            }
 9562        })
 9563    }
 9564
 9565    fn hide_context_menu(
 9566        &mut self,
 9567        window: &mut Window,
 9568        cx: &mut Context<Self>,
 9569    ) -> Option<CodeContextMenu> {
 9570        cx.notify();
 9571        self.completion_tasks.clear();
 9572        let context_menu = self.context_menu.borrow_mut().take();
 9573        self.stale_edit_prediction_in_menu.take();
 9574        self.update_visible_edit_prediction(window, cx);
 9575        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9576            && let Some(completion_provider) = &self.completion_provider
 9577        {
 9578            completion_provider.selection_changed(None, window, cx);
 9579        }
 9580        context_menu
 9581    }
 9582
 9583    fn show_snippet_choices(
 9584        &mut self,
 9585        choices: &Vec<String>,
 9586        selection: Range<Anchor>,
 9587        cx: &mut Context<Self>,
 9588    ) {
 9589        let Some((_, buffer, _)) = self
 9590            .buffer()
 9591            .read(cx)
 9592            .excerpt_containing(selection.start, cx)
 9593        else {
 9594            return;
 9595        };
 9596        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9597        else {
 9598            return;
 9599        };
 9600        if buffer != end_buffer {
 9601            log::error!("expected anchor range to have matching buffer IDs");
 9602            return;
 9603        }
 9604
 9605        let id = post_inc(&mut self.next_completion_id);
 9606        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9607        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9608            CompletionsMenu::new_snippet_choices(
 9609                id,
 9610                true,
 9611                choices,
 9612                selection,
 9613                buffer,
 9614                snippet_sort_order,
 9615            ),
 9616        ));
 9617    }
 9618
 9619    pub fn insert_snippet(
 9620        &mut self,
 9621        insertion_ranges: &[Range<usize>],
 9622        snippet: Snippet,
 9623        window: &mut Window,
 9624        cx: &mut Context<Self>,
 9625    ) -> Result<()> {
 9626        struct Tabstop<T> {
 9627            is_end_tabstop: bool,
 9628            ranges: Vec<Range<T>>,
 9629            choices: Option<Vec<String>>,
 9630        }
 9631
 9632        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9633            let snippet_text: Arc<str> = snippet.text.clone().into();
 9634            let edits = insertion_ranges
 9635                .iter()
 9636                .cloned()
 9637                .map(|range| (range, snippet_text.clone()));
 9638            let autoindent_mode = AutoindentMode::Block {
 9639                original_indent_columns: Vec::new(),
 9640            };
 9641            buffer.edit(edits, Some(autoindent_mode), cx);
 9642
 9643            let snapshot = &*buffer.read(cx);
 9644            let snippet = &snippet;
 9645            snippet
 9646                .tabstops
 9647                .iter()
 9648                .map(|tabstop| {
 9649                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9650                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9651                    });
 9652                    let mut tabstop_ranges = tabstop
 9653                        .ranges
 9654                        .iter()
 9655                        .flat_map(|tabstop_range| {
 9656                            let mut delta = 0_isize;
 9657                            insertion_ranges.iter().map(move |insertion_range| {
 9658                                let insertion_start = insertion_range.start as isize + delta;
 9659                                delta +=
 9660                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9661
 9662                                let start = ((insertion_start + tabstop_range.start) as usize)
 9663                                    .min(snapshot.len());
 9664                                let end = ((insertion_start + tabstop_range.end) as usize)
 9665                                    .min(snapshot.len());
 9666                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9667                            })
 9668                        })
 9669                        .collect::<Vec<_>>();
 9670                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9671
 9672                    Tabstop {
 9673                        is_end_tabstop,
 9674                        ranges: tabstop_ranges,
 9675                        choices: tabstop.choices.clone(),
 9676                    }
 9677                })
 9678                .collect::<Vec<_>>()
 9679        });
 9680        if let Some(tabstop) = tabstops.first() {
 9681            self.change_selections(Default::default(), window, cx, |s| {
 9682                // Reverse order so that the first range is the newest created selection.
 9683                // Completions will use it and autoscroll will prioritize it.
 9684                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9685            });
 9686
 9687            if let Some(choices) = &tabstop.choices
 9688                && let Some(selection) = tabstop.ranges.first()
 9689            {
 9690                self.show_snippet_choices(choices, selection.clone(), cx)
 9691            }
 9692
 9693            // If we're already at the last tabstop and it's at the end of the snippet,
 9694            // we're done, we don't need to keep the state around.
 9695            if !tabstop.is_end_tabstop {
 9696                let choices = tabstops
 9697                    .iter()
 9698                    .map(|tabstop| tabstop.choices.clone())
 9699                    .collect();
 9700
 9701                let ranges = tabstops
 9702                    .into_iter()
 9703                    .map(|tabstop| tabstop.ranges)
 9704                    .collect::<Vec<_>>();
 9705
 9706                self.snippet_stack.push(SnippetState {
 9707                    active_index: 0,
 9708                    ranges,
 9709                    choices,
 9710                });
 9711            }
 9712
 9713            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9714            if self.autoclose_regions.is_empty() {
 9715                let snapshot = self.buffer.read(cx).snapshot(cx);
 9716                let mut all_selections = self.selections.all::<Point>(cx);
 9717                for selection in &mut all_selections {
 9718                    let selection_head = selection.head();
 9719                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9720                        continue;
 9721                    };
 9722
 9723                    let mut bracket_pair = None;
 9724                    let max_lookup_length = scope
 9725                        .brackets()
 9726                        .map(|(pair, _)| {
 9727                            pair.start
 9728                                .as_str()
 9729                                .chars()
 9730                                .count()
 9731                                .max(pair.end.as_str().chars().count())
 9732                        })
 9733                        .max();
 9734                    if let Some(max_lookup_length) = max_lookup_length {
 9735                        let next_text = snapshot
 9736                            .chars_at(selection_head)
 9737                            .take(max_lookup_length)
 9738                            .collect::<String>();
 9739                        let prev_text = snapshot
 9740                            .reversed_chars_at(selection_head)
 9741                            .take(max_lookup_length)
 9742                            .collect::<String>();
 9743
 9744                        for (pair, enabled) in scope.brackets() {
 9745                            if enabled
 9746                                && pair.close
 9747                                && prev_text.starts_with(pair.start.as_str())
 9748                                && next_text.starts_with(pair.end.as_str())
 9749                            {
 9750                                bracket_pair = Some(pair.clone());
 9751                                break;
 9752                            }
 9753                        }
 9754                    }
 9755
 9756                    if let Some(pair) = bracket_pair {
 9757                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9758                        let autoclose_enabled =
 9759                            self.use_autoclose && snapshot_settings.use_autoclose;
 9760                        if autoclose_enabled {
 9761                            let start = snapshot.anchor_after(selection_head);
 9762                            let end = snapshot.anchor_after(selection_head);
 9763                            self.autoclose_regions.push(AutocloseRegion {
 9764                                selection_id: selection.id,
 9765                                range: start..end,
 9766                                pair,
 9767                            });
 9768                        }
 9769                    }
 9770                }
 9771            }
 9772        }
 9773        Ok(())
 9774    }
 9775
 9776    pub fn move_to_next_snippet_tabstop(
 9777        &mut self,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) -> bool {
 9781        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9782    }
 9783
 9784    pub fn move_to_prev_snippet_tabstop(
 9785        &mut self,
 9786        window: &mut Window,
 9787        cx: &mut Context<Self>,
 9788    ) -> bool {
 9789        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9790    }
 9791
 9792    pub fn move_to_snippet_tabstop(
 9793        &mut self,
 9794        bias: Bias,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) -> bool {
 9798        if let Some(mut snippet) = self.snippet_stack.pop() {
 9799            match bias {
 9800                Bias::Left => {
 9801                    if snippet.active_index > 0 {
 9802                        snippet.active_index -= 1;
 9803                    } else {
 9804                        self.snippet_stack.push(snippet);
 9805                        return false;
 9806                    }
 9807                }
 9808                Bias::Right => {
 9809                    if snippet.active_index + 1 < snippet.ranges.len() {
 9810                        snippet.active_index += 1;
 9811                    } else {
 9812                        self.snippet_stack.push(snippet);
 9813                        return false;
 9814                    }
 9815                }
 9816            }
 9817            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9818                self.change_selections(Default::default(), window, cx, |s| {
 9819                    // Reverse order so that the first range is the newest created selection.
 9820                    // Completions will use it and autoscroll will prioritize it.
 9821                    s.select_ranges(current_ranges.iter().rev().cloned())
 9822                });
 9823
 9824                if let Some(choices) = &snippet.choices[snippet.active_index]
 9825                    && let Some(selection) = current_ranges.first()
 9826                {
 9827                    self.show_snippet_choices(choices, selection.clone(), cx);
 9828                }
 9829
 9830                // If snippet state is not at the last tabstop, push it back on the stack
 9831                if snippet.active_index + 1 < snippet.ranges.len() {
 9832                    self.snippet_stack.push(snippet);
 9833                }
 9834                return true;
 9835            }
 9836        }
 9837
 9838        false
 9839    }
 9840
 9841    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9842        self.transact(window, cx, |this, window, cx| {
 9843            this.select_all(&SelectAll, window, cx);
 9844            this.insert("", window, cx);
 9845        });
 9846    }
 9847
 9848    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9849        if self.read_only(cx) {
 9850            return;
 9851        }
 9852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_autoclose_pair(window, cx);
 9855            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9856            if !this.linked_edit_ranges.is_empty() {
 9857                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9858                let snapshot = this.buffer.read(cx).snapshot(cx);
 9859
 9860                for selection in selections.iter() {
 9861                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9862                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9863                    if selection_start.buffer_id != selection_end.buffer_id {
 9864                        continue;
 9865                    }
 9866                    if let Some(ranges) =
 9867                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9868                    {
 9869                        for (buffer, entries) in ranges {
 9870                            linked_ranges.entry(buffer).or_default().extend(entries);
 9871                        }
 9872                    }
 9873                }
 9874            }
 9875
 9876            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9877            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9878            for selection in &mut selections {
 9879                if selection.is_empty() {
 9880                    let old_head = selection.head();
 9881                    let mut new_head =
 9882                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9883                            .to_point(&display_map);
 9884                    if let Some((buffer, line_buffer_range)) = display_map
 9885                        .buffer_snapshot
 9886                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9887                    {
 9888                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9889                        let indent_len = match indent_size.kind {
 9890                            IndentKind::Space => {
 9891                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9892                            }
 9893                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9894                        };
 9895                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9896                            let indent_len = indent_len.get();
 9897                            new_head = cmp::min(
 9898                                new_head,
 9899                                MultiBufferPoint::new(
 9900                                    old_head.row,
 9901                                    ((old_head.column - 1) / indent_len) * indent_len,
 9902                                ),
 9903                            );
 9904                        }
 9905                    }
 9906
 9907                    selection.set_head(new_head, SelectionGoal::None);
 9908                }
 9909            }
 9910
 9911            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9912            this.insert("", window, cx);
 9913            let empty_str: Arc<str> = Arc::from("");
 9914            for (buffer, edits) in linked_ranges {
 9915                let snapshot = buffer.read(cx).snapshot();
 9916                use text::ToPoint as TP;
 9917
 9918                let edits = edits
 9919                    .into_iter()
 9920                    .map(|range| {
 9921                        let end_point = TP::to_point(&range.end, &snapshot);
 9922                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9923
 9924                        if end_point == start_point {
 9925                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9926                                .saturating_sub(1);
 9927                            start_point =
 9928                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9929                        };
 9930
 9931                        (start_point..end_point, empty_str.clone())
 9932                    })
 9933                    .sorted_by_key(|(range, _)| range.start)
 9934                    .collect::<Vec<_>>();
 9935                buffer.update(cx, |this, cx| {
 9936                    this.edit(edits, None, cx);
 9937                })
 9938            }
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.change_selections(Default::default(), window, cx, |s| {
 9951                s.move_with(|map, selection| {
 9952                    if selection.is_empty() {
 9953                        let cursor = movement::right(map, selection.head());
 9954                        selection.end = cursor;
 9955                        selection.reversed = true;
 9956                        selection.goal = SelectionGoal::None;
 9957                    }
 9958                })
 9959            });
 9960            this.insert("", window, cx);
 9961            this.refresh_edit_prediction(true, false, window, cx);
 9962        });
 9963    }
 9964
 9965    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9966        if self.mode.is_single_line() {
 9967            cx.propagate();
 9968            return;
 9969        }
 9970
 9971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9972        if self.move_to_prev_snippet_tabstop(window, cx) {
 9973            return;
 9974        }
 9975        self.outdent(&Outdent, window, cx);
 9976    }
 9977
 9978    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.mode.is_single_line() {
 9980            cx.propagate();
 9981            return;
 9982        }
 9983
 9984        if self.move_to_next_snippet_tabstop(window, cx) {
 9985            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9986            return;
 9987        }
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9992        let mut selections = self.selections.all_adjusted(cx);
 9993        let buffer = self.buffer.read(cx);
 9994        let snapshot = buffer.snapshot(cx);
 9995        let rows_iter = selections.iter().map(|s| s.head().row);
 9996        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9997
 9998        let has_some_cursor_in_whitespace = selections
 9999            .iter()
10000            .filter(|selection| selection.is_empty())
10001            .any(|selection| {
10002                let cursor = selection.head();
10003                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004                cursor.column < current_indent.len
10005            });
10006
10007        let mut edits = Vec::new();
10008        let mut prev_edited_row = 0;
10009        let mut row_delta = 0;
10010        for selection in &mut selections {
10011            if selection.start.row != prev_edited_row {
10012                row_delta = 0;
10013            }
10014            prev_edited_row = selection.end.row;
10015
10016            // If the selection is non-empty, then increase the indentation of the selected lines.
10017            if !selection.is_empty() {
10018                row_delta =
10019                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10020                continue;
10021            }
10022
10023            let cursor = selection.head();
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10025            if let Some(suggested_indent) =
10026                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10027            {
10028                // Don't do anything if already at suggested indent
10029                // and there is any other cursor which is not
10030                if has_some_cursor_in_whitespace
10031                    && cursor.column == current_indent.len
10032                    && current_indent.len == suggested_indent.len
10033                {
10034                    continue;
10035                }
10036
10037                // Adjust line and move cursor to suggested indent
10038                // if cursor is not at suggested indent
10039                if cursor.column < suggested_indent.len
10040                    && cursor.column <= current_indent.len
10041                    && current_indent.len <= suggested_indent.len
10042                {
10043                    selection.start = Point::new(cursor.row, suggested_indent.len);
10044                    selection.end = selection.start;
10045                    if row_delta == 0 {
10046                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10047                            cursor.row,
10048                            current_indent,
10049                            suggested_indent,
10050                        ));
10051                        row_delta = suggested_indent.len - current_indent.len;
10052                    }
10053                    continue;
10054                }
10055
10056                // If current indent is more than suggested indent
10057                // only move cursor to current indent and skip indent
10058                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10059                    selection.start = Point::new(cursor.row, current_indent.len);
10060                    selection.end = selection.start;
10061                    continue;
10062                }
10063            }
10064
10065            // Otherwise, insert a hard or soft tab.
10066            let settings = buffer.language_settings_at(cursor, cx);
10067            let tab_size = if settings.hard_tabs {
10068                IndentSize::tab()
10069            } else {
10070                let tab_size = settings.tab_size.get();
10071                let indent_remainder = snapshot
10072                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10073                    .flat_map(str::chars)
10074                    .fold(row_delta % tab_size, |counter: u32, c| {
10075                        if c == '\t' {
10076                            0
10077                        } else {
10078                            (counter + 1) % tab_size
10079                        }
10080                    });
10081
10082                let chars_to_next_tab_stop = tab_size - indent_remainder;
10083                IndentSize::spaces(chars_to_next_tab_stop)
10084            };
10085            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10086            selection.end = selection.start;
10087            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10088            row_delta += tab_size.len;
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.refresh_edit_prediction(true, false, window, cx);
10095        });
10096    }
10097
10098    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut selections = self.selections.all::<Point>(cx);
10109        let mut prev_edited_row = 0;
10110        let mut row_delta = 0;
10111        let mut edits = Vec::new();
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        for selection in &mut selections {
10115            if selection.start.row != prev_edited_row {
10116                row_delta = 0;
10117            }
10118            prev_edited_row = selection.end.row;
10119
10120            row_delta =
10121                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10122        }
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10126            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10127        });
10128    }
10129
10130    fn indent_selection(
10131        buffer: &MultiBuffer,
10132        snapshot: &MultiBufferSnapshot,
10133        selection: &mut Selection<Point>,
10134        edits: &mut Vec<(Range<Point>, String)>,
10135        delta_for_start_row: u32,
10136        cx: &App,
10137    ) -> u32 {
10138        let settings = buffer.language_settings_at(selection.start, cx);
10139        let tab_size = settings.tab_size.get();
10140        let indent_kind = if settings.hard_tabs {
10141            IndentKind::Tab
10142        } else {
10143            IndentKind::Space
10144        };
10145        let mut start_row = selection.start.row;
10146        let mut end_row = selection.end.row + 1;
10147
10148        // If a selection ends at the beginning of a line, don't indent
10149        // that last line.
10150        if selection.end.column == 0 && selection.end.row > selection.start.row {
10151            end_row -= 1;
10152        }
10153
10154        // Avoid re-indenting a row that has already been indented by a
10155        // previous selection, but still update this selection's column
10156        // to reflect that indentation.
10157        if delta_for_start_row > 0 {
10158            start_row += 1;
10159            selection.start.column += delta_for_start_row;
10160            if selection.end.row == selection.start.row {
10161                selection.end.column += delta_for_start_row;
10162            }
10163        }
10164
10165        let mut delta_for_end_row = 0;
10166        let has_multiple_rows = start_row + 1 != end_row;
10167        for row in start_row..end_row {
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10169            let indent_delta = match (current_indent.kind, indent_kind) {
10170                (IndentKind::Space, IndentKind::Space) => {
10171                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10172                    IndentSize::spaces(columns_to_next_tab_stop)
10173                }
10174                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10175                (_, IndentKind::Tab) => IndentSize::tab(),
10176            };
10177
10178            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10179                0
10180            } else {
10181                selection.start.column
10182            };
10183            let row_start = Point::new(row, start);
10184            edits.push((
10185                row_start..row_start,
10186                indent_delta.chars().collect::<String>(),
10187            ));
10188
10189            // Update this selection's endpoints to reflect the indentation.
10190            if row == selection.start.row {
10191                selection.start.column += indent_delta.len;
10192            }
10193            if row == selection.end.row {
10194                selection.end.column += indent_delta.len;
10195                delta_for_end_row = indent_delta.len;
10196            }
10197        }
10198
10199        if selection.start.row == selection.end.row {
10200            delta_for_start_row + delta_for_end_row
10201        } else {
10202            delta_for_end_row
10203        }
10204    }
10205
10206    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10216        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10217        let selections = self.selections.all::<Point>(cx);
10218        let mut deletion_ranges = Vec::new();
10219        let mut last_outdent = None;
10220        {
10221            let buffer = self.buffer.read(cx);
10222            let snapshot = buffer.snapshot(cx);
10223            for selection in &selections {
10224                let settings = buffer.language_settings_at(selection.start, cx);
10225                let tab_size = settings.tab_size.get();
10226                let mut rows = selection.spanned_rows(false, &display_map);
10227
10228                // Avoid re-outdenting a row that has already been outdented by a
10229                // previous selection.
10230                if let Some(last_row) = last_outdent
10231                    && last_row == rows.start
10232                {
10233                    rows.start = rows.start.next_row();
10234                }
10235                let has_multiple_rows = rows.len() > 1;
10236                for row in rows.iter_rows() {
10237                    let indent_size = snapshot.indent_size_for_line(row);
10238                    if indent_size.len > 0 {
10239                        let deletion_len = match indent_size.kind {
10240                            IndentKind::Space => {
10241                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10242                                if columns_to_prev_tab_stop == 0 {
10243                                    tab_size
10244                                } else {
10245                                    columns_to_prev_tab_stop
10246                                }
10247                            }
10248                            IndentKind::Tab => 1,
10249                        };
10250                        let start = if has_multiple_rows
10251                            || deletion_len > selection.start.column
10252                            || indent_size.len < selection.start.column
10253                        {
10254                            0
10255                        } else {
10256                            selection.start.column - deletion_len
10257                        };
10258                        deletion_ranges.push(
10259                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10260                        );
10261                        last_outdent = Some(row);
10262                    }
10263                }
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, window, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                let empty_str: Arc<str> = Arc::default();
10270                buffer.edit(
10271                    deletion_ranges
10272                        .into_iter()
10273                        .map(|range| (range, empty_str.clone())),
10274                    None,
10275                    cx,
10276                );
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10284        if self.read_only(cx) {
10285            return;
10286        }
10287        if self.mode.is_single_line() {
10288            cx.propagate();
10289            return;
10290        }
10291
10292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10293        let selections = self
10294            .selections
10295            .all::<usize>(cx)
10296            .into_iter()
10297            .map(|s| s.range());
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |buffer, cx| {
10301                buffer.autoindent_ranges(selections, cx);
10302            });
10303            let selections = this.selections.all::<usize>(cx);
10304            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10305        });
10306    }
10307
10308    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10311        let selections = self.selections.all::<Point>(cx);
10312
10313        let mut new_cursors = Vec::new();
10314        let mut edit_ranges = Vec::new();
10315        let mut selections = selections.iter().peekable();
10316        while let Some(selection) = selections.next() {
10317            let mut rows = selection.spanned_rows(false, &display_map);
10318            let goal_display_column = selection.head().to_display_point(&display_map).column();
10319
10320            // Accumulate contiguous regions of rows that we want to delete.
10321            while let Some(next_selection) = selections.peek() {
10322                let next_rows = next_selection.spanned_rows(false, &display_map);
10323                if next_rows.start <= rows.end {
10324                    rows.end = next_rows.end;
10325                    selections.next().unwrap();
10326                } else {
10327                    break;
10328                }
10329            }
10330
10331            let buffer = &display_map.buffer_snapshot;
10332            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10333            let edit_end;
10334            let cursor_buffer_row;
10335            if buffer.max_point().row >= rows.end.0 {
10336                // If there's a line after the range, delete the \n from the end of the row range
10337                // and position the cursor on the next line.
10338                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10339                cursor_buffer_row = rows.end;
10340            } else {
10341                // If there isn't a line after the range, delete the \n from the line before the
10342                // start of the row range and position the cursor there.
10343                edit_start = edit_start.saturating_sub(1);
10344                edit_end = buffer.len();
10345                cursor_buffer_row = rows.start.previous_row();
10346            }
10347
10348            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10349            *cursor.column_mut() =
10350                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10351
10352            new_cursors.push((
10353                selection.id,
10354                buffer.anchor_after(cursor.to_point(&display_map)),
10355            ));
10356            edit_ranges.push(edit_start..edit_end);
10357        }
10358
10359        self.transact(window, cx, |this, window, cx| {
10360            let buffer = this.buffer.update(cx, |buffer, cx| {
10361                let empty_str: Arc<str> = Arc::default();
10362                buffer.edit(
10363                    edit_ranges
10364                        .into_iter()
10365                        .map(|range| (range, empty_str.clone())),
10366                    None,
10367                    cx,
10368                );
10369                buffer.snapshot(cx)
10370            });
10371            let new_selections = new_cursors
10372                .into_iter()
10373                .map(|(id, cursor)| {
10374                    let cursor = cursor.to_point(&buffer);
10375                    Selection {
10376                        id,
10377                        start: cursor,
10378                        end: cursor,
10379                        reversed: false,
10380                        goal: SelectionGoal::None,
10381                    }
10382                })
10383                .collect();
10384
10385            this.change_selections(Default::default(), window, cx, |s| {
10386                s.select(new_selections);
10387            });
10388        });
10389    }
10390
10391    pub fn join_lines_impl(
10392        &mut self,
10393        insert_whitespace: bool,
10394        window: &mut Window,
10395        cx: &mut Context<Self>,
10396    ) {
10397        if self.read_only(cx) {
10398            return;
10399        }
10400        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10401        for selection in self.selections.all::<Point>(cx) {
10402            let start = MultiBufferRow(selection.start.row);
10403            // Treat single line selections as if they include the next line. Otherwise this action
10404            // would do nothing for single line selections individual cursors.
10405            let end = if selection.start.row == selection.end.row {
10406                MultiBufferRow(selection.start.row + 1)
10407            } else {
10408                MultiBufferRow(selection.end.row)
10409            };
10410
10411            if let Some(last_row_range) = row_ranges.last_mut()
10412                && start <= last_row_range.end
10413            {
10414                last_row_range.end = end;
10415                continue;
10416            }
10417            row_ranges.push(start..end);
10418        }
10419
10420        let snapshot = self.buffer.read(cx).snapshot(cx);
10421        let mut cursor_positions = Vec::new();
10422        for row_range in &row_ranges {
10423            let anchor = snapshot.anchor_before(Point::new(
10424                row_range.end.previous_row().0,
10425                snapshot.line_len(row_range.end.previous_row()),
10426            ));
10427            cursor_positions.push(anchor..anchor);
10428        }
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            for row_range in row_ranges.into_iter().rev() {
10432                for row in row_range.iter_rows().rev() {
10433                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10434                    let next_line_row = row.next_row();
10435                    let indent = snapshot.indent_size_for_line(next_line_row);
10436                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10437
10438                    let replace =
10439                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10440                            " "
10441                        } else {
10442                            ""
10443                        };
10444
10445                    this.buffer.update(cx, |buffer, cx| {
10446                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10447                    });
10448                }
10449            }
10450
10451            this.change_selections(Default::default(), window, cx, |s| {
10452                s.select_anchor_ranges(cursor_positions)
10453            });
10454        });
10455    }
10456
10457    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        self.join_lines_impl(true, window, cx);
10460    }
10461
10462    pub fn sort_lines_case_sensitive(
10463        &mut self,
10464        _: &SortLinesCaseSensitive,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10469    }
10470
10471    pub fn sort_lines_by_length(
10472        &mut self,
10473        _: &SortLinesByLength,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        self.manipulate_immutable_lines(window, cx, |lines| {
10478            lines.sort_by_key(|&line| line.chars().count())
10479        })
10480    }
10481
10482    pub fn sort_lines_case_insensitive(
10483        &mut self,
10484        _: &SortLinesCaseInsensitive,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|line| line.to_lowercase())
10490        })
10491    }
10492
10493    pub fn unique_lines_case_insensitive(
10494        &mut self,
10495        _: &UniqueLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            let mut seen = HashSet::default();
10501            lines.retain(|line| seen.insert(line.to_lowercase()));
10502        })
10503    }
10504
10505    pub fn unique_lines_case_sensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseSensitive,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_immutable_lines(window, cx, |lines| {
10512            let mut seen = HashSet::default();
10513            lines.retain(|line| seen.insert(*line));
10514        })
10515    }
10516
10517    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10518        let snapshot = self.buffer.read(cx).snapshot(cx);
10519        for selection in self.selections.disjoint_anchors_arc().iter() {
10520            if snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.as_ref())
10523                .is_some()
10524            {
10525                return true;
10526            }
10527        }
10528        false
10529    }
10530
10531    fn wrap_selections_in_tag(
10532        &mut self,
10533        _: &WrapSelectionsInTag,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) {
10537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10538
10539        let snapshot = self.buffer.read(cx).snapshot(cx);
10540
10541        let mut edits = Vec::new();
10542        let mut boundaries = Vec::new();
10543
10544        for selection in self.selections.all::<Point>(cx).iter() {
10545            let Some(wrap_config) = snapshot
10546                .language_at(selection.start)
10547                .and_then(|lang| lang.config().wrap_characters.clone())
10548            else {
10549                continue;
10550            };
10551
10552            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10553            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10554
10555            let start_before = snapshot.anchor_before(selection.start);
10556            let end_after = snapshot.anchor_after(selection.end);
10557
10558            edits.push((start_before..start_before, open_tag));
10559            edits.push((end_after..end_after, close_tag));
10560
10561            boundaries.push((
10562                start_before,
10563                end_after,
10564                wrap_config.start_prefix.len(),
10565                wrap_config.end_suffix.len(),
10566            ));
10567        }
10568
10569        if edits.is_empty() {
10570            return;
10571        }
10572
10573        self.transact(window, cx, |this, window, cx| {
10574            let buffer = this.buffer.update(cx, |buffer, cx| {
10575                buffer.edit(edits, None, cx);
10576                buffer.snapshot(cx)
10577            });
10578
10579            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10580            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10581                boundaries.into_iter()
10582            {
10583                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10584                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10585                new_selections.push(open_offset..open_offset);
10586                new_selections.push(close_offset..close_offset);
10587            }
10588
10589            this.change_selections(Default::default(), window, cx, |s| {
10590                s.select_ranges(new_selections);
10591            });
10592
10593            this.request_autoscroll(Autoscroll::fit(), cx);
10594        });
10595    }
10596
10597    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10598        let Some(project) = self.project.clone() else {
10599            return;
10600        };
10601        self.reload(project, window, cx)
10602            .detach_and_notify_err(window, cx);
10603    }
10604
10605    pub fn restore_file(
10606        &mut self,
10607        _: &::git::RestoreFile,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let mut buffer_ids = HashSet::default();
10613        let snapshot = self.buffer().read(cx).snapshot(cx);
10614        for selection in self.selections.all::<usize>(cx) {
10615            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10616        }
10617
10618        let buffer = self.buffer().read(cx);
10619        let ranges = buffer_ids
10620            .into_iter()
10621            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10622            .collect::<Vec<_>>();
10623
10624        self.restore_hunks_in_ranges(ranges, window, cx);
10625    }
10626
10627    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629        let selections = self
10630            .selections
10631            .all(cx)
10632            .into_iter()
10633            .map(|s| s.range())
10634            .collect();
10635        self.restore_hunks_in_ranges(selections, window, cx);
10636    }
10637
10638    pub fn restore_hunks_in_ranges(
10639        &mut self,
10640        ranges: Vec<Range<Point>>,
10641        window: &mut Window,
10642        cx: &mut Context<Editor>,
10643    ) {
10644        let mut revert_changes = HashMap::default();
10645        let chunk_by = self
10646            .snapshot(window, cx)
10647            .hunks_for_ranges(ranges)
10648            .into_iter()
10649            .chunk_by(|hunk| hunk.buffer_id);
10650        for (buffer_id, hunks) in &chunk_by {
10651            let hunks = hunks.collect::<Vec<_>>();
10652            for hunk in &hunks {
10653                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10654            }
10655            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10656        }
10657        drop(chunk_by);
10658        if !revert_changes.is_empty() {
10659            self.transact(window, cx, |editor, window, cx| {
10660                editor.restore(revert_changes, window, cx);
10661            });
10662        }
10663    }
10664
10665    pub fn open_active_item_in_terminal(
10666        &mut self,
10667        _: &OpenInTerminal,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10672            let project_path = buffer.read(cx).project_path(cx)?;
10673            let project = self.project()?.read(cx);
10674            let entry = project.entry_for_path(&project_path, cx)?;
10675            let parent = match &entry.canonical_path {
10676                Some(canonical_path) => canonical_path.to_path_buf(),
10677                None => project.absolute_path(&project_path, cx)?,
10678            }
10679            .parent()?
10680            .to_path_buf();
10681            Some(parent)
10682        }) {
10683            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10684        }
10685    }
10686
10687    fn set_breakpoint_context_menu(
10688        &mut self,
10689        display_row: DisplayRow,
10690        position: Option<Anchor>,
10691        clicked_point: gpui::Point<Pixels>,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let source = self
10696            .buffer
10697            .read(cx)
10698            .snapshot(cx)
10699            .anchor_before(Point::new(display_row.0, 0u32));
10700
10701        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10702
10703        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10704            self,
10705            source,
10706            clicked_point,
10707            context_menu,
10708            window,
10709            cx,
10710        );
10711    }
10712
10713    fn add_edit_breakpoint_block(
10714        &mut self,
10715        anchor: Anchor,
10716        breakpoint: &Breakpoint,
10717        edit_action: BreakpointPromptEditAction,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        let weak_editor = cx.weak_entity();
10722        let bp_prompt = cx.new(|cx| {
10723            BreakpointPromptEditor::new(
10724                weak_editor,
10725                anchor,
10726                breakpoint.clone(),
10727                edit_action,
10728                window,
10729                cx,
10730            )
10731        });
10732
10733        let height = bp_prompt.update(cx, |this, cx| {
10734            this.prompt
10735                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10736        });
10737        let cloned_prompt = bp_prompt.clone();
10738        let blocks = vec![BlockProperties {
10739            style: BlockStyle::Sticky,
10740            placement: BlockPlacement::Above(anchor),
10741            height: Some(height),
10742            render: Arc::new(move |cx| {
10743                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10744                cloned_prompt.clone().into_any_element()
10745            }),
10746            priority: 0,
10747        }];
10748
10749        let focus_handle = bp_prompt.focus_handle(cx);
10750        window.focus(&focus_handle);
10751
10752        let block_ids = self.insert_blocks(blocks, None, cx);
10753        bp_prompt.update(cx, |prompt, _| {
10754            prompt.add_block_ids(block_ids);
10755        });
10756    }
10757
10758    pub(crate) fn breakpoint_at_row(
10759        &self,
10760        row: u32,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) -> Option<(Anchor, Breakpoint)> {
10764        let snapshot = self.snapshot(window, cx);
10765        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10766
10767        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10768    }
10769
10770    pub(crate) fn breakpoint_at_anchor(
10771        &self,
10772        breakpoint_position: Anchor,
10773        snapshot: &EditorSnapshot,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let buffer = self
10777            .buffer
10778            .read(cx)
10779            .buffer_for_anchor(breakpoint_position, cx)?;
10780
10781        let enclosing_excerpt = breakpoint_position.excerpt_id;
10782        let buffer_snapshot = buffer.read(cx).snapshot();
10783
10784        let row = buffer_snapshot
10785            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10786            .row;
10787
10788        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10789        let anchor_end = snapshot
10790            .buffer_snapshot
10791            .anchor_after(Point::new(row, line_len));
10792
10793        self.breakpoint_store
10794            .as_ref()?
10795            .read_with(cx, |breakpoint_store, cx| {
10796                breakpoint_store
10797                    .breakpoints(
10798                        &buffer,
10799                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10800                        &buffer_snapshot,
10801                        cx,
10802                    )
10803                    .next()
10804                    .and_then(|(bp, _)| {
10805                        let breakpoint_row = buffer_snapshot
10806                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10807                            .row;
10808
10809                        if breakpoint_row == row {
10810                            snapshot
10811                                .buffer_snapshot
10812                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10813                                .map(|position| (position, bp.bp.clone()))
10814                        } else {
10815                            None
10816                        }
10817                    })
10818            })
10819    }
10820
10821    pub fn edit_log_breakpoint(
10822        &mut self,
10823        _: &EditLogBreakpoint,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10828            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10829                message: None,
10830                state: BreakpointState::Enabled,
10831                condition: None,
10832                hit_condition: None,
10833            });
10834
10835            self.add_edit_breakpoint_block(
10836                anchor,
10837                &breakpoint,
10838                BreakpointPromptEditAction::Log,
10839                window,
10840                cx,
10841            );
10842        }
10843    }
10844
10845    fn breakpoints_at_cursors(
10846        &self,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10850        let snapshot = self.snapshot(window, cx);
10851        let cursors = self
10852            .selections
10853            .disjoint_anchors_arc()
10854            .iter()
10855            .map(|selection| {
10856                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10857
10858                let breakpoint_position = self
10859                    .breakpoint_at_row(cursor_position.row, window, cx)
10860                    .map(|bp| bp.0)
10861                    .unwrap_or_else(|| {
10862                        snapshot
10863                            .display_snapshot
10864                            .buffer_snapshot
10865                            .anchor_after(Point::new(cursor_position.row, 0))
10866                    });
10867
10868                let breakpoint = self
10869                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10870                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10871
10872                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10873            })
10874            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
10875            .collect::<HashMap<Anchor, _>>();
10876
10877        cursors.into_iter().collect()
10878    }
10879
10880    pub fn enable_breakpoint(
10881        &mut self,
10882        _: &crate::actions::EnableBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10888                continue;
10889            };
10890            self.edit_breakpoint_at_anchor(
10891                anchor,
10892                breakpoint,
10893                BreakpointEditAction::InvertState,
10894                cx,
10895            );
10896        }
10897    }
10898
10899    pub fn disable_breakpoint(
10900        &mut self,
10901        _: &crate::actions::DisableBreakpoint,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10906            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10907                continue;
10908            };
10909            self.edit_breakpoint_at_anchor(
10910                anchor,
10911                breakpoint,
10912                BreakpointEditAction::InvertState,
10913                cx,
10914            );
10915        }
10916    }
10917
10918    pub fn toggle_breakpoint(
10919        &mut self,
10920        _: &crate::actions::ToggleBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            if let Some(breakpoint) = breakpoint {
10926                self.edit_breakpoint_at_anchor(
10927                    anchor,
10928                    breakpoint,
10929                    BreakpointEditAction::Toggle,
10930                    cx,
10931                );
10932            } else {
10933                self.edit_breakpoint_at_anchor(
10934                    anchor,
10935                    Breakpoint::new_standard(),
10936                    BreakpointEditAction::Toggle,
10937                    cx,
10938                );
10939            }
10940        }
10941    }
10942
10943    pub fn edit_breakpoint_at_anchor(
10944        &mut self,
10945        breakpoint_position: Anchor,
10946        breakpoint: Breakpoint,
10947        edit_action: BreakpointEditAction,
10948        cx: &mut Context<Self>,
10949    ) {
10950        let Some(breakpoint_store) = &self.breakpoint_store else {
10951            return;
10952        };
10953
10954        let Some(buffer) = self
10955            .buffer
10956            .read(cx)
10957            .buffer_for_anchor(breakpoint_position, cx)
10958        else {
10959            return;
10960        };
10961
10962        breakpoint_store.update(cx, |breakpoint_store, cx| {
10963            breakpoint_store.toggle_breakpoint(
10964                buffer,
10965                BreakpointWithPosition {
10966                    position: breakpoint_position.text_anchor,
10967                    bp: breakpoint,
10968                },
10969                edit_action,
10970                cx,
10971            );
10972        });
10973
10974        cx.notify();
10975    }
10976
10977    #[cfg(any(test, feature = "test-support"))]
10978    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10979        self.breakpoint_store.clone()
10980    }
10981
10982    pub fn prepare_restore_change(
10983        &self,
10984        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10985        hunk: &MultiBufferDiffHunk,
10986        cx: &mut App,
10987    ) -> Option<()> {
10988        if hunk.is_created_file() {
10989            return None;
10990        }
10991        let buffer = self.buffer.read(cx);
10992        let diff = buffer.diff_for(hunk.buffer_id)?;
10993        let buffer = buffer.buffer(hunk.buffer_id)?;
10994        let buffer = buffer.read(cx);
10995        let original_text = diff
10996            .read(cx)
10997            .base_text()
10998            .as_rope()
10999            .slice(hunk.diff_base_byte_range.clone());
11000        let buffer_snapshot = buffer.snapshot();
11001        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11002        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11003            probe
11004                .0
11005                .start
11006                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11007                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11008        }) {
11009            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11010            Some(())
11011        } else {
11012            None
11013        }
11014    }
11015
11016    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11018    }
11019
11020    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11022    }
11023
11024    fn manipulate_lines<M>(
11025        &mut self,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028        mut manipulate: M,
11029    ) where
11030        M: FnMut(&str) -> LineManipulationResult,
11031    {
11032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11033
11034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11035        let buffer = self.buffer.read(cx).snapshot(cx);
11036
11037        let mut edits = Vec::new();
11038
11039        let selections = self.selections.all::<Point>(cx);
11040        let mut selections = selections.iter().peekable();
11041        let mut contiguous_row_selections = Vec::new();
11042        let mut new_selections = Vec::new();
11043        let mut added_lines = 0;
11044        let mut removed_lines = 0;
11045
11046        while let Some(selection) = selections.next() {
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            let start_point = Point::new(start_row.0, 0);
11055            let end_point = Point::new(
11056                end_row.previous_row().0,
11057                buffer.line_len(end_row.previous_row()),
11058            );
11059            let text = buffer
11060                .text_for_range(start_point..end_point)
11061                .collect::<String>();
11062
11063            let LineManipulationResult {
11064                new_text,
11065                line_count_before,
11066                line_count_after,
11067            } = manipulate(&text);
11068
11069            edits.push((start_point..end_point, new_text));
11070
11071            // Selections must change based on added and removed line count
11072            let start_row =
11073                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11074            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11075            new_selections.push(Selection {
11076                id: selection.id,
11077                start: start_row,
11078                end: end_row,
11079                goal: SelectionGoal::None,
11080                reversed: selection.reversed,
11081            });
11082
11083            if line_count_after > line_count_before {
11084                added_lines += line_count_after - line_count_before;
11085            } else if line_count_before > line_count_after {
11086                removed_lines += line_count_before - line_count_after;
11087            }
11088        }
11089
11090        self.transact(window, cx, |this, window, cx| {
11091            let buffer = this.buffer.update(cx, |buffer, cx| {
11092                buffer.edit(edits, None, cx);
11093                buffer.snapshot(cx)
11094            });
11095
11096            // Recalculate offsets on newly edited buffer
11097            let new_selections = new_selections
11098                .iter()
11099                .map(|s| {
11100                    let start_point = Point::new(s.start.0, 0);
11101                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11102                    Selection {
11103                        id: s.id,
11104                        start: buffer.point_to_offset(start_point),
11105                        end: buffer.point_to_offset(end_point),
11106                        goal: s.goal,
11107                        reversed: s.reversed,
11108                    }
11109                })
11110                .collect();
11111
11112            this.change_selections(Default::default(), window, cx, |s| {
11113                s.select(new_selections);
11114            });
11115
11116            this.request_autoscroll(Autoscroll::fit(), cx);
11117        });
11118    }
11119
11120    fn manipulate_immutable_lines<Fn>(
11121        &mut self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124        mut callback: Fn,
11125    ) where
11126        Fn: FnMut(&mut Vec<&str>),
11127    {
11128        self.manipulate_lines(window, cx, |text| {
11129            let mut lines: Vec<&str> = text.split('\n').collect();
11130            let line_count_before = lines.len();
11131
11132            callback(&mut lines);
11133
11134            LineManipulationResult {
11135                new_text: lines.join("\n"),
11136                line_count_before,
11137                line_count_after: lines.len(),
11138            }
11139        });
11140    }
11141
11142    fn manipulate_mutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    pub fn convert_indentation_to_spaces(
11165        &mut self,
11166        _: &ConvertIndentationToSpaces,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let settings = self.buffer.read(cx).language_settings(cx);
11171        let tab_size = settings.tab_size.get() as usize;
11172
11173        self.manipulate_mutable_lines(window, cx, |lines| {
11174            // Allocates a reasonably sized scratch buffer once for the whole loop
11175            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11176            // Avoids recomputing spaces that could be inserted many times
11177            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11178                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11179                .collect();
11180
11181            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11182                let mut chars = line.as_ref().chars();
11183                let mut col = 0;
11184                let mut changed = false;
11185
11186                for ch in chars.by_ref() {
11187                    match ch {
11188                        ' ' => {
11189                            reindented_line.push(' ');
11190                            col += 1;
11191                        }
11192                        '\t' => {
11193                            // \t are converted to spaces depending on the current column
11194                            let spaces_len = tab_size - (col % tab_size);
11195                            reindented_line.extend(&space_cache[spaces_len - 1]);
11196                            col += spaces_len;
11197                            changed = true;
11198                        }
11199                        _ => {
11200                            // If we dont append before break, the character is consumed
11201                            reindented_line.push(ch);
11202                            break;
11203                        }
11204                    }
11205                }
11206
11207                if !changed {
11208                    reindented_line.clear();
11209                    continue;
11210                }
11211                // Append the rest of the line and replace old reference with new one
11212                reindented_line.extend(chars);
11213                *line = Cow::Owned(reindented_line.clone());
11214                reindented_line.clear();
11215            }
11216        });
11217    }
11218
11219    pub fn convert_indentation_to_tabs(
11220        &mut self,
11221        _: &ConvertIndentationToTabs,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        let settings = self.buffer.read(cx).language_settings(cx);
11226        let tab_size = settings.tab_size.get() as usize;
11227
11228        self.manipulate_mutable_lines(window, cx, |lines| {
11229            // Allocates a reasonably sized buffer once for the whole loop
11230            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11231            // Avoids recomputing spaces that could be inserted many times
11232            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11233                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11234                .collect();
11235
11236            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11237                let mut chars = line.chars();
11238                let mut spaces_count = 0;
11239                let mut first_non_indent_char = None;
11240                let mut changed = false;
11241
11242                for ch in chars.by_ref() {
11243                    match ch {
11244                        ' ' => {
11245                            // Keep track of spaces. Append \t when we reach tab_size
11246                            spaces_count += 1;
11247                            changed = true;
11248                            if spaces_count == tab_size {
11249                                reindented_line.push('\t');
11250                                spaces_count = 0;
11251                            }
11252                        }
11253                        '\t' => {
11254                            reindented_line.push('\t');
11255                            spaces_count = 0;
11256                        }
11257                        _ => {
11258                            // Dont append it yet, we might have remaining spaces
11259                            first_non_indent_char = Some(ch);
11260                            break;
11261                        }
11262                    }
11263                }
11264
11265                if !changed {
11266                    reindented_line.clear();
11267                    continue;
11268                }
11269                // Remaining spaces that didn't make a full tab stop
11270                if spaces_count > 0 {
11271                    reindented_line.extend(&space_cache[spaces_count - 1]);
11272                }
11273                // If we consume an extra character that was not indentation, add it back
11274                if let Some(extra_char) = first_non_indent_char {
11275                    reindented_line.push(extra_char);
11276                }
11277                // Append the rest of the line and replace old reference with new one
11278                reindented_line.extend(chars);
11279                *line = Cow::Owned(reindented_line.clone());
11280                reindented_line.clear();
11281            }
11282        });
11283    }
11284
11285    pub fn convert_to_upper_case(
11286        &mut self,
11287        _: &ConvertToUpperCase,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.manipulate_text(window, cx, |text| text.to_uppercase())
11292    }
11293
11294    pub fn convert_to_lower_case(
11295        &mut self,
11296        _: &ConvertToLowerCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_lowercase())
11301    }
11302
11303    pub fn convert_to_title_case(
11304        &mut self,
11305        _: &ConvertToTitleCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.split('\n')
11311                .map(|line| line.to_case(Case::Title))
11312                .join("\n")
11313        })
11314    }
11315
11316    pub fn convert_to_snake_case(
11317        &mut self,
11318        _: &ConvertToSnakeCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11323    }
11324
11325    pub fn convert_to_kebab_case(
11326        &mut self,
11327        _: &ConvertToKebabCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11332    }
11333
11334    pub fn convert_to_upper_camel_case(
11335        &mut self,
11336        _: &ConvertToUpperCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| {
11341            text.split('\n')
11342                .map(|line| line.to_case(Case::UpperCamel))
11343                .join("\n")
11344        })
11345    }
11346
11347    pub fn convert_to_lower_camel_case(
11348        &mut self,
11349        _: &ConvertToLowerCamelCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11354    }
11355
11356    pub fn convert_to_opposite_case(
11357        &mut self,
11358        _: &ConvertToOppositeCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.chars()
11364                .fold(String::with_capacity(text.len()), |mut t, c| {
11365                    if c.is_uppercase() {
11366                        t.extend(c.to_lowercase());
11367                    } else {
11368                        t.extend(c.to_uppercase());
11369                    }
11370                    t
11371                })
11372        })
11373    }
11374
11375    pub fn convert_to_sentence_case(
11376        &mut self,
11377        _: &ConvertToSentenceCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11382    }
11383
11384    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11385        self.manipulate_text(window, cx, |text| {
11386            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11387            if has_upper_case_characters {
11388                text.to_lowercase()
11389            } else {
11390                text.to_uppercase()
11391            }
11392        })
11393    }
11394
11395    pub fn convert_to_rot13(
11396        &mut self,
11397        _: &ConvertToRot13,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.manipulate_text(window, cx, |text| {
11402            text.chars()
11403                .map(|c| match c {
11404                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11405                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11406                    _ => c,
11407                })
11408                .collect()
11409        })
11410    }
11411
11412    pub fn convert_to_rot47(
11413        &mut self,
11414        _: &ConvertToRot47,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.chars()
11420                .map(|c| {
11421                    let code_point = c as u32;
11422                    if code_point >= 33 && code_point <= 126 {
11423                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11424                    }
11425                    c
11426                })
11427                .collect()
11428        })
11429    }
11430
11431    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11432    where
11433        Fn: FnMut(&str) -> String,
11434    {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut new_selections = Vec::new();
11438        let mut edits = Vec::new();
11439        let mut selection_adjustment = 0i32;
11440
11441        for selection in self.selections.all_adjusted(cx) {
11442            let selection_is_empty = selection.is_empty();
11443
11444            let (start, end) = if selection_is_empty {
11445                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11446                (word_range.start, word_range.end)
11447            } else {
11448                (
11449                    buffer.point_to_offset(selection.start),
11450                    buffer.point_to_offset(selection.end),
11451                )
11452            };
11453
11454            let text = buffer.text_for_range(start..end).collect::<String>();
11455            let old_length = text.len() as i32;
11456            let text = callback(&text);
11457
11458            new_selections.push(Selection {
11459                start: (start as i32 - selection_adjustment) as usize,
11460                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11461                goal: SelectionGoal::None,
11462                id: selection.id,
11463                reversed: selection.reversed,
11464            });
11465
11466            selection_adjustment += old_length - text.len() as i32;
11467
11468            edits.push((start..end, text));
11469        }
11470
11471        self.transact(window, cx, |this, window, cx| {
11472            this.buffer.update(cx, |buffer, cx| {
11473                buffer.edit(edits, None, cx);
11474            });
11475
11476            this.change_selections(Default::default(), window, cx, |s| {
11477                s.select(new_selections);
11478            });
11479
11480            this.request_autoscroll(Autoscroll::fit(), cx);
11481        });
11482    }
11483
11484    pub fn move_selection_on_drop(
11485        &mut self,
11486        selection: &Selection<Anchor>,
11487        target: DisplayPoint,
11488        is_cut: bool,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11493        let buffer = &display_map.buffer_snapshot;
11494        let mut edits = Vec::new();
11495        let insert_point = display_map
11496            .clip_point(target, Bias::Left)
11497            .to_point(&display_map);
11498        let text = buffer
11499            .text_for_range(selection.start..selection.end)
11500            .collect::<String>();
11501        if is_cut {
11502            edits.push(((selection.start..selection.end), String::new()));
11503        }
11504        let insert_anchor = buffer.anchor_before(insert_point);
11505        edits.push(((insert_anchor..insert_anchor), text));
11506        let last_edit_start = insert_anchor.bias_left(buffer);
11507        let last_edit_end = insert_anchor.bias_right(buffer);
11508        self.transact(window, cx, |this, window, cx| {
11509            this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511            });
11512            this.change_selections(Default::default(), window, cx, |s| {
11513                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11514            });
11515        });
11516    }
11517
11518    pub fn clear_selection_drag_state(&mut self) {
11519        self.selection_drag_state = SelectionDragState::None;
11520    }
11521
11522    pub fn duplicate(
11523        &mut self,
11524        upwards: bool,
11525        whole_lines: bool,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11530
11531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11532        let buffer = &display_map.buffer_snapshot;
11533        let selections = self.selections.all::<Point>(cx);
11534
11535        let mut edits = Vec::new();
11536        let mut selections_iter = selections.iter().peekable();
11537        while let Some(selection) = selections_iter.next() {
11538            let mut rows = selection.spanned_rows(false, &display_map);
11539            // duplicate line-wise
11540            if whole_lines || selection.start == selection.end {
11541                // Avoid duplicating the same lines twice.
11542                while let Some(next_selection) = selections_iter.peek() {
11543                    let next_rows = next_selection.spanned_rows(false, &display_map);
11544                    if next_rows.start < rows.end {
11545                        rows.end = next_rows.end;
11546                        selections_iter.next().unwrap();
11547                    } else {
11548                        break;
11549                    }
11550                }
11551
11552                // Copy the text from the selected row region and splice it either at the start
11553                // or end of the region.
11554                let start = Point::new(rows.start.0, 0);
11555                let end = Point::new(
11556                    rows.end.previous_row().0,
11557                    buffer.line_len(rows.end.previous_row()),
11558                );
11559                let text = buffer
11560                    .text_for_range(start..end)
11561                    .chain(Some("\n"))
11562                    .collect::<String>();
11563                let insert_location = if upwards {
11564                    Point::new(rows.end.0, 0)
11565                } else {
11566                    start
11567                };
11568                edits.push((insert_location..insert_location, text));
11569            } else {
11570                // duplicate character-wise
11571                let start = selection.start;
11572                let end = selection.end;
11573                let text = buffer.text_for_range(start..end).collect::<String>();
11574                edits.push((selection.end..selection.end, text));
11575            }
11576        }
11577
11578        self.transact(window, cx, |this, _, cx| {
11579            this.buffer.update(cx, |buffer, cx| {
11580                buffer.edit(edits, None, cx);
11581            });
11582
11583            this.request_autoscroll(Autoscroll::fit(), cx);
11584        });
11585    }
11586
11587    pub fn duplicate_line_up(
11588        &mut self,
11589        _: &DuplicateLineUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.duplicate(true, true, window, cx);
11594    }
11595
11596    pub fn duplicate_line_down(
11597        &mut self,
11598        _: &DuplicateLineDown,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.duplicate(false, true, window, cx);
11603    }
11604
11605    pub fn duplicate_selection(
11606        &mut self,
11607        _: &DuplicateSelection,
11608        window: &mut Window,
11609        cx: &mut Context<Self>,
11610    ) {
11611        self.duplicate(false, false, window, cx);
11612    }
11613
11614    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616        if self.mode.is_single_line() {
11617            cx.propagate();
11618            return;
11619        }
11620
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut edits = Vec::new();
11625        let mut unfold_ranges = Vec::new();
11626        let mut refold_creases = Vec::new();
11627
11628        let selections = self.selections.all::<Point>(cx);
11629        let mut selections = selections.iter().peekable();
11630        let mut contiguous_row_selections = Vec::new();
11631        let mut new_selections = Vec::new();
11632
11633        while let Some(selection) = selections.next() {
11634            // Find all the selections that span a contiguous row range
11635            let (start_row, end_row) = consume_contiguous_rows(
11636                &mut contiguous_row_selections,
11637                selection,
11638                &display_map,
11639                &mut selections,
11640            );
11641
11642            // Move the text spanned by the row range to be before the line preceding the row range
11643            if start_row.0 > 0 {
11644                let range_to_move = Point::new(
11645                    start_row.previous_row().0,
11646                    buffer.line_len(start_row.previous_row()),
11647                )
11648                    ..Point::new(
11649                        end_row.previous_row().0,
11650                        buffer.line_len(end_row.previous_row()),
11651                    );
11652                let insertion_point = display_map
11653                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11654                    .0;
11655
11656                // Don't move lines across excerpts
11657                if buffer
11658                    .excerpt_containing(insertion_point..range_to_move.end)
11659                    .is_some()
11660                {
11661                    let text = buffer
11662                        .text_for_range(range_to_move.clone())
11663                        .flat_map(|s| s.chars())
11664                        .skip(1)
11665                        .chain(['\n'])
11666                        .collect::<String>();
11667
11668                    edits.push((
11669                        buffer.anchor_after(range_to_move.start)
11670                            ..buffer.anchor_before(range_to_move.end),
11671                        String::new(),
11672                    ));
11673                    let insertion_anchor = buffer.anchor_after(insertion_point);
11674                    edits.push((insertion_anchor..insertion_anchor, text));
11675
11676                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11677
11678                    // Move selections up
11679                    new_selections.extend(contiguous_row_selections.drain(..).map(
11680                        |mut selection| {
11681                            selection.start.row -= row_delta;
11682                            selection.end.row -= row_delta;
11683                            selection
11684                        },
11685                    ));
11686
11687                    // Move folds up
11688                    unfold_ranges.push(range_to_move.clone());
11689                    for fold in display_map.folds_in_range(
11690                        buffer.anchor_before(range_to_move.start)
11691                            ..buffer.anchor_after(range_to_move.end),
11692                    ) {
11693                        let mut start = fold.range.start.to_point(&buffer);
11694                        let mut end = fold.range.end.to_point(&buffer);
11695                        start.row -= row_delta;
11696                        end.row -= row_delta;
11697                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11698                    }
11699                }
11700            }
11701
11702            // If we didn't move line(s), preserve the existing selections
11703            new_selections.append(&mut contiguous_row_selections);
11704        }
11705
11706        self.transact(window, cx, |this, window, cx| {
11707            this.unfold_ranges(&unfold_ranges, true, true, cx);
11708            this.buffer.update(cx, |buffer, cx| {
11709                for (range, text) in edits {
11710                    buffer.edit([(range, text)], None, cx);
11711                }
11712            });
11713            this.fold_creases(refold_creases, true, window, cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(new_selections);
11716            })
11717        });
11718    }
11719
11720    pub fn move_line_down(
11721        &mut self,
11722        _: &MoveLineDown,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11727        if self.mode.is_single_line() {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = self.buffer.read(cx).snapshot(cx);
11734
11735        let mut edits = Vec::new();
11736        let mut unfold_ranges = Vec::new();
11737        let mut refold_creases = Vec::new();
11738
11739        let selections = self.selections.all::<Point>(cx);
11740        let mut selections = selections.iter().peekable();
11741        let mut contiguous_row_selections = Vec::new();
11742        let mut new_selections = Vec::new();
11743
11744        while let Some(selection) = selections.next() {
11745            // Find all the selections that span a contiguous row range
11746            let (start_row, end_row) = consume_contiguous_rows(
11747                &mut contiguous_row_selections,
11748                selection,
11749                &display_map,
11750                &mut selections,
11751            );
11752
11753            // Move the text spanned by the row range to be after the last line of the row range
11754            if end_row.0 <= buffer.max_point().row {
11755                let range_to_move =
11756                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11757                let insertion_point = display_map
11758                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11759                    .0;
11760
11761                // Don't move lines across excerpt boundaries
11762                if buffer
11763                    .excerpt_containing(range_to_move.start..insertion_point)
11764                    .is_some()
11765                {
11766                    let mut text = String::from("\n");
11767                    text.extend(buffer.text_for_range(range_to_move.clone()));
11768                    text.pop(); // Drop trailing newline
11769                    edits.push((
11770                        buffer.anchor_after(range_to_move.start)
11771                            ..buffer.anchor_before(range_to_move.end),
11772                        String::new(),
11773                    ));
11774                    let insertion_anchor = buffer.anchor_after(insertion_point);
11775                    edits.push((insertion_anchor..insertion_anchor, text));
11776
11777                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11778
11779                    // Move selections down
11780                    new_selections.extend(contiguous_row_selections.drain(..).map(
11781                        |mut selection| {
11782                            selection.start.row += row_delta;
11783                            selection.end.row += row_delta;
11784                            selection
11785                        },
11786                    ));
11787
11788                    // Move folds down
11789                    unfold_ranges.push(range_to_move.clone());
11790                    for fold in display_map.folds_in_range(
11791                        buffer.anchor_before(range_to_move.start)
11792                            ..buffer.anchor_after(range_to_move.end),
11793                    ) {
11794                        let mut start = fold.range.start.to_point(&buffer);
11795                        let mut end = fold.range.end.to_point(&buffer);
11796                        start.row += row_delta;
11797                        end.row += row_delta;
11798                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11799                    }
11800                }
11801            }
11802
11803            // If we didn't move line(s), preserve the existing selections
11804            new_selections.append(&mut contiguous_row_selections);
11805        }
11806
11807        self.transact(window, cx, |this, window, cx| {
11808            this.unfold_ranges(&unfold_ranges, true, true, cx);
11809            this.buffer.update(cx, |buffer, cx| {
11810                for (range, text) in edits {
11811                    buffer.edit([(range, text)], None, cx);
11812                }
11813            });
11814            this.fold_creases(refold_creases, true, window, cx);
11815            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11816        });
11817    }
11818
11819    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        let text_layout_details = &self.text_layout_details(window);
11822        self.transact(window, cx, |this, window, cx| {
11823            let edits = this.change_selections(Default::default(), window, cx, |s| {
11824                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11825                s.move_with(|display_map, selection| {
11826                    if !selection.is_empty() {
11827                        return;
11828                    }
11829
11830                    let mut head = selection.head();
11831                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11832                    if head.column() == display_map.line_len(head.row()) {
11833                        transpose_offset = display_map
11834                            .buffer_snapshot
11835                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11836                    }
11837
11838                    if transpose_offset == 0 {
11839                        return;
11840                    }
11841
11842                    *head.column_mut() += 1;
11843                    head = display_map.clip_point(head, Bias::Right);
11844                    let goal = SelectionGoal::HorizontalPosition(
11845                        display_map
11846                            .x_for_display_point(head, text_layout_details)
11847                            .into(),
11848                    );
11849                    selection.collapse_to(head, goal);
11850
11851                    let transpose_start = display_map
11852                        .buffer_snapshot
11853                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11854                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11855                        let transpose_end = display_map
11856                            .buffer_snapshot
11857                            .clip_offset(transpose_offset + 1, Bias::Right);
11858                        if let Some(ch) =
11859                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11860                        {
11861                            edits.push((transpose_start..transpose_offset, String::new()));
11862                            edits.push((transpose_end..transpose_end, ch.to_string()));
11863                        }
11864                    }
11865                });
11866                edits
11867            });
11868            this.buffer
11869                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11870            let selections = this.selections.all::<usize>(cx);
11871            this.change_selections(Default::default(), window, cx, |s| {
11872                s.select(selections);
11873            });
11874        });
11875    }
11876
11877    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11879        if self.mode.is_single_line() {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.rewrap_impl(RewrapOptions::default(), cx)
11885    }
11886
11887    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11888        let buffer = self.buffer.read(cx).snapshot(cx);
11889        let selections = self.selections.all::<Point>(cx);
11890
11891        #[derive(Clone, Debug, PartialEq)]
11892        enum CommentFormat {
11893            /// single line comment, with prefix for line
11894            Line(String),
11895            /// single line within a block comment, with prefix for line
11896            BlockLine(String),
11897            /// a single line of a block comment that includes the initial delimiter
11898            BlockCommentWithStart(BlockCommentConfig),
11899            /// a single line of a block comment that includes the ending delimiter
11900            BlockCommentWithEnd(BlockCommentConfig),
11901        }
11902
11903        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11904        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11905            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11906                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11907                .peekable();
11908
11909            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11910                row
11911            } else {
11912                return Vec::new();
11913            };
11914
11915            let language_settings = buffer.language_settings_at(selection.head(), cx);
11916            let language_scope = buffer.language_scope_at(selection.head());
11917
11918            let indent_and_prefix_for_row =
11919                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11920                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11921                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11922                        &language_scope
11923                    {
11924                        let indent_end = Point::new(row, indent.len);
11925                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11926                        let line_text_after_indent = buffer
11927                            .text_for_range(indent_end..line_end)
11928                            .collect::<String>();
11929
11930                        let is_within_comment_override = buffer
11931                            .language_scope_at(indent_end)
11932                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11933                        let comment_delimiters = if is_within_comment_override {
11934                            // we are within a comment syntax node, but we don't
11935                            // yet know what kind of comment: block, doc or line
11936                            match (
11937                                language_scope.documentation_comment(),
11938                                language_scope.block_comment(),
11939                            ) {
11940                                (Some(config), _) | (_, Some(config))
11941                                    if buffer.contains_str_at(indent_end, &config.start) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11947                                {
11948                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11949                                }
11950                                (Some(config), _) | (_, Some(config))
11951                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11952                                {
11953                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11954                                }
11955                                (_, _) => language_scope
11956                                    .line_comment_prefixes()
11957                                    .iter()
11958                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11959                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11960                            }
11961                        } else {
11962                            // we not in an overridden comment node, but we may
11963                            // be within a non-overridden line comment node
11964                            language_scope
11965                                .line_comment_prefixes()
11966                                .iter()
11967                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11968                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11969                        };
11970
11971                        let rewrap_prefix = language_scope
11972                            .rewrap_prefixes()
11973                            .iter()
11974                            .find_map(|prefix_regex| {
11975                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11976                                    if mat.start() == 0 {
11977                                        Some(mat.as_str().to_string())
11978                                    } else {
11979                                        None
11980                                    }
11981                                })
11982                            })
11983                            .flatten();
11984                        (comment_delimiters, rewrap_prefix)
11985                    } else {
11986                        (None, None)
11987                    };
11988                    (indent, comment_prefix, rewrap_prefix)
11989                };
11990
11991            let mut ranges = Vec::new();
11992            let from_empty_selection = selection.is_empty();
11993
11994            let mut current_range_start = first_row;
11995            let mut prev_row = first_row;
11996            let (
11997                mut current_range_indent,
11998                mut current_range_comment_delimiters,
11999                mut current_range_rewrap_prefix,
12000            ) = indent_and_prefix_for_row(first_row);
12001
12002            for row in non_blank_rows_iter.skip(1) {
12003                let has_paragraph_break = row > prev_row + 1;
12004
12005                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12006                    indent_and_prefix_for_row(row);
12007
12008                let has_indent_change = row_indent != current_range_indent;
12009                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12010
12011                let has_boundary_change = has_comment_change
12012                    || row_rewrap_prefix.is_some()
12013                    || (has_indent_change && current_range_comment_delimiters.is_some());
12014
12015                if has_paragraph_break || has_boundary_change {
12016                    ranges.push((
12017                        language_settings.clone(),
12018                        Point::new(current_range_start, 0)
12019                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12020                        current_range_indent,
12021                        current_range_comment_delimiters.clone(),
12022                        current_range_rewrap_prefix.clone(),
12023                        from_empty_selection,
12024                    ));
12025                    current_range_start = row;
12026                    current_range_indent = row_indent;
12027                    current_range_comment_delimiters = row_comment_delimiters;
12028                    current_range_rewrap_prefix = row_rewrap_prefix;
12029                }
12030                prev_row = row;
12031            }
12032
12033            ranges.push((
12034                language_settings.clone(),
12035                Point::new(current_range_start, 0)
12036                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12037                current_range_indent,
12038                current_range_comment_delimiters,
12039                current_range_rewrap_prefix,
12040                from_empty_selection,
12041            ));
12042
12043            ranges
12044        });
12045
12046        let mut edits = Vec::new();
12047        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12048
12049        for (
12050            language_settings,
12051            wrap_range,
12052            mut indent_size,
12053            comment_prefix,
12054            rewrap_prefix,
12055            from_empty_selection,
12056        ) in wrap_ranges
12057        {
12058            let mut start_row = wrap_range.start.row;
12059            let mut end_row = wrap_range.end.row;
12060
12061            // Skip selections that overlap with a range that has already been rewrapped.
12062            let selection_range = start_row..end_row;
12063            if rewrapped_row_ranges
12064                .iter()
12065                .any(|range| range.overlaps(&selection_range))
12066            {
12067                continue;
12068            }
12069
12070            let tab_size = language_settings.tab_size;
12071
12072            let (line_prefix, inside_comment) = match &comment_prefix {
12073                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12074                    (Some(prefix.as_str()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12077                    (Some(prefix.as_ref()), true)
12078                }
12079                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12080                    start: _,
12081                    end: _,
12082                    prefix,
12083                    tab_size,
12084                })) => {
12085                    indent_size.len += tab_size;
12086                    (Some(prefix.as_ref()), true)
12087                }
12088                None => (None, false),
12089            };
12090            let indent_prefix = indent_size.chars().collect::<String>();
12091            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12092
12093            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12094                RewrapBehavior::InComments => inside_comment,
12095                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12096                RewrapBehavior::Anywhere => true,
12097            };
12098
12099            let should_rewrap = options.override_language_settings
12100                || allow_rewrap_based_on_language
12101                || self.hard_wrap.is_some();
12102            if !should_rewrap {
12103                continue;
12104            }
12105
12106            if from_empty_selection {
12107                'expand_upwards: while start_row > 0 {
12108                    let prev_row = start_row - 1;
12109                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12110                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12111                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12112                    {
12113                        start_row = prev_row;
12114                    } else {
12115                        break 'expand_upwards;
12116                    }
12117                }
12118
12119                'expand_downwards: while end_row < buffer.max_point().row {
12120                    let next_row = end_row + 1;
12121                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12122                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12123                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12124                    {
12125                        end_row = next_row;
12126                    } else {
12127                        break 'expand_downwards;
12128                    }
12129                }
12130            }
12131
12132            let start = Point::new(start_row, 0);
12133            let start_offset = start.to_offset(&buffer);
12134            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12135            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12136            let mut first_line_delimiter = None;
12137            let mut last_line_delimiter = None;
12138            let Some(lines_without_prefixes) = selection_text
12139                .lines()
12140                .enumerate()
12141                .map(|(ix, line)| {
12142                    let line_trimmed = line.trim_start();
12143                    if rewrap_prefix.is_some() && ix > 0 {
12144                        Ok(line_trimmed)
12145                    } else if let Some(
12146                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12147                            start,
12148                            prefix,
12149                            end,
12150                            tab_size,
12151                        })
12152                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12153                            start,
12154                            prefix,
12155                            end,
12156                            tab_size,
12157                        }),
12158                    ) = &comment_prefix
12159                    {
12160                        let line_trimmed = line_trimmed
12161                            .strip_prefix(start.as_ref())
12162                            .map(|s| {
12163                                let mut indent_size = indent_size;
12164                                indent_size.len -= tab_size;
12165                                let indent_prefix: String = indent_size.chars().collect();
12166                                first_line_delimiter = Some((indent_prefix, start));
12167                                s.trim_start()
12168                            })
12169                            .unwrap_or(line_trimmed);
12170                        let line_trimmed = line_trimmed
12171                            .strip_suffix(end.as_ref())
12172                            .map(|s| {
12173                                last_line_delimiter = Some(end);
12174                                s.trim_end()
12175                            })
12176                            .unwrap_or(line_trimmed);
12177                        let line_trimmed = line_trimmed
12178                            .strip_prefix(prefix.as_ref())
12179                            .unwrap_or(line_trimmed);
12180                        Ok(line_trimmed)
12181                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12182                        line_trimmed.strip_prefix(prefix).with_context(|| {
12183                            format!("line did not start with prefix {prefix:?}: {line:?}")
12184                        })
12185                    } else {
12186                        line_trimmed
12187                            .strip_prefix(&line_prefix.trim_start())
12188                            .with_context(|| {
12189                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12190                            })
12191                    }
12192                })
12193                .collect::<Result<Vec<_>, _>>()
12194                .log_err()
12195            else {
12196                continue;
12197            };
12198
12199            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12200                buffer
12201                    .language_settings_at(Point::new(start_row, 0), cx)
12202                    .preferred_line_length as usize
12203            });
12204
12205            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12206                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12207            } else {
12208                line_prefix.clone()
12209            };
12210
12211            let wrapped_text = {
12212                let mut wrapped_text = wrap_with_prefix(
12213                    line_prefix,
12214                    subsequent_lines_prefix,
12215                    lines_without_prefixes.join("\n"),
12216                    wrap_column,
12217                    tab_size,
12218                    options.preserve_existing_whitespace,
12219                );
12220
12221                if let Some((indent, delimiter)) = first_line_delimiter {
12222                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12223                }
12224                if let Some(last_line) = last_line_delimiter {
12225                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12226                }
12227
12228                wrapped_text
12229            };
12230
12231            // TODO: should always use char-based diff while still supporting cursor behavior that
12232            // matches vim.
12233            let mut diff_options = DiffOptions::default();
12234            if options.override_language_settings {
12235                diff_options.max_word_diff_len = 0;
12236                diff_options.max_word_diff_line_count = 0;
12237            } else {
12238                diff_options.max_word_diff_len = usize::MAX;
12239                diff_options.max_word_diff_line_count = usize::MAX;
12240            }
12241
12242            for (old_range, new_text) in
12243                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12244            {
12245                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12246                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12247                edits.push((edit_start..edit_end, new_text));
12248            }
12249
12250            rewrapped_row_ranges.push(start_row..=end_row);
12251        }
12252
12253        self.buffer
12254            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12255    }
12256
12257    pub fn cut_common(
12258        &mut self,
12259        cut_no_selection_line: bool,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) -> ClipboardItem {
12263        let mut text = String::new();
12264        let buffer = self.buffer.read(cx).snapshot(cx);
12265        let mut selections = self.selections.all::<Point>(cx);
12266        let mut clipboard_selections = Vec::with_capacity(selections.len());
12267        {
12268            let max_point = buffer.max_point();
12269            let mut is_first = true;
12270            for selection in &mut selections {
12271                let is_entire_line =
12272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12273                if is_entire_line {
12274                    selection.start = Point::new(selection.start.row, 0);
12275                    if !selection.is_empty() && selection.end.column == 0 {
12276                        selection.end = cmp::min(max_point, selection.end);
12277                    } else {
12278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12279                    }
12280                    selection.goal = SelectionGoal::None;
12281                }
12282                if is_first {
12283                    is_first = false;
12284                } else {
12285                    text += "\n";
12286                }
12287                let mut len = 0;
12288                for chunk in buffer.text_for_range(selection.start..selection.end) {
12289                    text.push_str(chunk);
12290                    len += chunk.len();
12291                }
12292                clipboard_selections.push(ClipboardSelection {
12293                    len,
12294                    is_entire_line,
12295                    first_line_indent: buffer
12296                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12297                        .len,
12298                });
12299            }
12300        }
12301
12302        self.transact(window, cx, |this, window, cx| {
12303            this.change_selections(Default::default(), window, cx, |s| {
12304                s.select(selections);
12305            });
12306            this.insert("", window, cx);
12307        });
12308        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12309    }
12310
12311    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12313        let item = self.cut_common(true, window, cx);
12314        cx.write_to_clipboard(item);
12315    }
12316
12317    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12319        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12320            s.move_with(|snapshot, sel| {
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12323                }
12324                if sel.is_empty() {
12325                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12326                }
12327            });
12328        });
12329        let item = self.cut_common(true, window, cx);
12330        cx.set_global(KillRing(item))
12331    }
12332
12333    pub fn kill_ring_yank(
12334        &mut self,
12335        _: &KillRingYank,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12341            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12342                (kill_ring.text().to_string(), kill_ring.metadata_json())
12343            } else {
12344                return;
12345            }
12346        } else {
12347            return;
12348        };
12349        self.do_paste(&text, metadata, false, window, cx);
12350    }
12351
12352    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12353        self.do_copy(true, cx);
12354    }
12355
12356    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12357        self.do_copy(false, cx);
12358    }
12359
12360    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12361        let selections = self.selections.all::<Point>(cx);
12362        let buffer = self.buffer.read(cx).read(cx);
12363        let mut text = String::new();
12364
12365        let mut clipboard_selections = Vec::with_capacity(selections.len());
12366        {
12367            let max_point = buffer.max_point();
12368            let mut is_first = true;
12369            for selection in &selections {
12370                let mut start = selection.start;
12371                let mut end = selection.end;
12372                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12373                if is_entire_line {
12374                    start = Point::new(start.row, 0);
12375                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12376                }
12377
12378                let mut trimmed_selections = Vec::new();
12379                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12380                    let row = MultiBufferRow(start.row);
12381                    let first_indent = buffer.indent_size_for_line(row);
12382                    if first_indent.len == 0 || start.column > first_indent.len {
12383                        trimmed_selections.push(start..end);
12384                    } else {
12385                        trimmed_selections.push(
12386                            Point::new(row.0, first_indent.len)
12387                                ..Point::new(row.0, buffer.line_len(row)),
12388                        );
12389                        for row in start.row + 1..=end.row {
12390                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12391                            if row == end.row {
12392                                line_len = end.column;
12393                            }
12394                            if line_len == 0 {
12395                                trimmed_selections
12396                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12397                                continue;
12398                            }
12399                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12400                            if row_indent_size.len >= first_indent.len {
12401                                trimmed_selections.push(
12402                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12403                                );
12404                            } else {
12405                                trimmed_selections.clear();
12406                                trimmed_selections.push(start..end);
12407                                break;
12408                            }
12409                        }
12410                    }
12411                } else {
12412                    trimmed_selections.push(start..end);
12413                }
12414
12415                for trimmed_range in trimmed_selections {
12416                    if is_first {
12417                        is_first = false;
12418                    } else {
12419                        text += "\n";
12420                    }
12421                    let mut len = 0;
12422                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12423                        text.push_str(chunk);
12424                        len += chunk.len();
12425                    }
12426                    clipboard_selections.push(ClipboardSelection {
12427                        len,
12428                        is_entire_line,
12429                        first_line_indent: buffer
12430                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12431                            .len,
12432                    });
12433                }
12434            }
12435        }
12436
12437        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12438            text,
12439            clipboard_selections,
12440        ));
12441    }
12442
12443    pub fn do_paste(
12444        &mut self,
12445        text: &String,
12446        clipboard_selections: Option<Vec<ClipboardSelection>>,
12447        handle_entire_lines: bool,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if self.read_only(cx) {
12452            return;
12453        }
12454
12455        let clipboard_text = Cow::Borrowed(text.as_str());
12456
12457        self.transact(window, cx, |this, window, cx| {
12458            let had_active_edit_prediction = this.has_active_edit_prediction();
12459            let old_selections = this.selections.all::<usize>(cx);
12460            let cursor_offset = this.selections.last::<usize>(cx).head();
12461
12462            if let Some(mut clipboard_selections) = clipboard_selections {
12463                let all_selections_were_entire_line =
12464                    clipboard_selections.iter().all(|s| s.is_entire_line);
12465                let first_selection_indent_column =
12466                    clipboard_selections.first().map(|s| s.first_line_indent);
12467                if clipboard_selections.len() != old_selections.len() {
12468                    clipboard_selections.drain(..);
12469                }
12470                let mut auto_indent_on_paste = true;
12471
12472                this.buffer.update(cx, |buffer, cx| {
12473                    let snapshot = buffer.read(cx);
12474                    auto_indent_on_paste = snapshot
12475                        .language_settings_at(cursor_offset, cx)
12476                        .auto_indent_on_paste;
12477
12478                    let mut start_offset = 0;
12479                    let mut edits = Vec::new();
12480                    let mut original_indent_columns = Vec::new();
12481                    for (ix, selection) in old_selections.iter().enumerate() {
12482                        let to_insert;
12483                        let entire_line;
12484                        let original_indent_column;
12485                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12486                            let end_offset = start_offset + clipboard_selection.len;
12487                            to_insert = &clipboard_text[start_offset..end_offset];
12488                            entire_line = clipboard_selection.is_entire_line;
12489                            start_offset = end_offset + 1;
12490                            original_indent_column = Some(clipboard_selection.first_line_indent);
12491                        } else {
12492                            to_insert = &*clipboard_text;
12493                            entire_line = all_selections_were_entire_line;
12494                            original_indent_column = first_selection_indent_column
12495                        }
12496
12497                        let (range, to_insert) =
12498                            if selection.is_empty() && handle_entire_lines && entire_line {
12499                                // If the corresponding selection was empty when this slice of the
12500                                // clipboard text was written, then the entire line containing the
12501                                // selection was copied. If this selection is also currently empty,
12502                                // then paste the line before the current line of the buffer.
12503                                let column = selection.start.to_point(&snapshot).column as usize;
12504                                let line_start = selection.start - column;
12505                                (line_start..line_start, Cow::Borrowed(to_insert))
12506                            } else {
12507                                let language = snapshot.language_at(selection.head());
12508                                let range = selection.range();
12509                                if let Some(language) = language
12510                                    && language.name() == "Markdown".into()
12511                                {
12512                                    edit_for_markdown_paste(
12513                                        &snapshot,
12514                                        range,
12515                                        to_insert,
12516                                        url::Url::parse(to_insert).ok(),
12517                                    )
12518                                } else {
12519                                    (range, Cow::Borrowed(to_insert))
12520                                }
12521                            };
12522
12523                        edits.push((range, to_insert));
12524                        original_indent_columns.push(original_indent_column);
12525                    }
12526                    drop(snapshot);
12527
12528                    buffer.edit(
12529                        edits,
12530                        if auto_indent_on_paste {
12531                            Some(AutoindentMode::Block {
12532                                original_indent_columns,
12533                            })
12534                        } else {
12535                            None
12536                        },
12537                        cx,
12538                    );
12539                });
12540
12541                let selections = this.selections.all::<usize>(cx);
12542                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12543            } else {
12544                let url = url::Url::parse(&clipboard_text).ok();
12545
12546                let auto_indent_mode = if !clipboard_text.is_empty() {
12547                    Some(AutoindentMode::Block {
12548                        original_indent_columns: Vec::new(),
12549                    })
12550                } else {
12551                    None
12552                };
12553
12554                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12555                    let snapshot = buffer.snapshot(cx);
12556
12557                    let anchors = old_selections
12558                        .iter()
12559                        .map(|s| {
12560                            let anchor = snapshot.anchor_after(s.head());
12561                            s.map(|_| anchor)
12562                        })
12563                        .collect::<Vec<_>>();
12564
12565                    let mut edits = Vec::new();
12566
12567                    for selection in old_selections.iter() {
12568                        let language = snapshot.language_at(selection.head());
12569                        let range = selection.range();
12570
12571                        let (edit_range, edit_text) = if let Some(language) = language
12572                            && language.name() == "Markdown".into()
12573                        {
12574                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12575                        } else {
12576                            (range, clipboard_text.clone())
12577                        };
12578
12579                        edits.push((edit_range, edit_text));
12580                    }
12581
12582                    drop(snapshot);
12583                    buffer.edit(edits, auto_indent_mode, cx);
12584
12585                    anchors
12586                });
12587
12588                this.change_selections(Default::default(), window, cx, |s| {
12589                    s.select_anchors(selection_anchors);
12590                });
12591            }
12592
12593            let trigger_in_words =
12594                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12595
12596            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12597        });
12598    }
12599
12600    pub fn diff_clipboard_with_selection(
12601        &mut self,
12602        _: &DiffClipboardWithSelection,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let selections = self.selections.all::<usize>(cx);
12607
12608        if selections.is_empty() {
12609            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12610            return;
12611        };
12612
12613        let clipboard_text = match cx.read_from_clipboard() {
12614            Some(item) => match item.entries().first() {
12615                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12616                _ => None,
12617            },
12618            None => None,
12619        };
12620
12621        let Some(clipboard_text) = clipboard_text else {
12622            log::warn!("Clipboard doesn't contain text.");
12623            return;
12624        };
12625
12626        window.dispatch_action(
12627            Box::new(DiffClipboardWithSelectionData {
12628                clipboard_text,
12629                editor: cx.entity(),
12630            }),
12631            cx,
12632        );
12633    }
12634
12635    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12637        if let Some(item) = cx.read_from_clipboard() {
12638            let entries = item.entries();
12639
12640            match entries.first() {
12641                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12642                // of all the pasted entries.
12643                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12644                    .do_paste(
12645                        clipboard_string.text(),
12646                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12647                        true,
12648                        window,
12649                        cx,
12650                    ),
12651                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12652            }
12653        }
12654    }
12655
12656    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12657        if self.read_only(cx) {
12658            return;
12659        }
12660
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12662
12663        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12664            if let Some((selections, _)) =
12665                self.selection_history.transaction(transaction_id).cloned()
12666            {
12667                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12668                    s.select_anchors(selections.to_vec());
12669                });
12670            } else {
12671                log::error!(
12672                    "No entry in selection_history found for undo. \
12673                     This may correspond to a bug where undo does not update the selection. \
12674                     If this is occurring, please add details to \
12675                     https://github.com/zed-industries/zed/issues/22692"
12676                );
12677            }
12678            self.request_autoscroll(Autoscroll::fit(), cx);
12679            self.unmark_text(window, cx);
12680            self.refresh_edit_prediction(true, false, window, cx);
12681            cx.emit(EditorEvent::Edited { transaction_id });
12682            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12683        }
12684    }
12685
12686    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12687        if self.read_only(cx) {
12688            return;
12689        }
12690
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12692
12693        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12694            if let Some((_, Some(selections))) =
12695                self.selection_history.transaction(transaction_id).cloned()
12696            {
12697                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12698                    s.select_anchors(selections.to_vec());
12699                });
12700            } else {
12701                log::error!(
12702                    "No entry in selection_history found for redo. \
12703                     This may correspond to a bug where undo does not update the selection. \
12704                     If this is occurring, please add details to \
12705                     https://github.com/zed-industries/zed/issues/22692"
12706                );
12707            }
12708            self.request_autoscroll(Autoscroll::fit(), cx);
12709            self.unmark_text(window, cx);
12710            self.refresh_edit_prediction(true, false, window, cx);
12711            cx.emit(EditorEvent::Edited { transaction_id });
12712        }
12713    }
12714
12715    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12716        self.buffer
12717            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12718    }
12719
12720    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12721        self.buffer
12722            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12723    }
12724
12725    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727        self.change_selections(Default::default(), window, cx, |s| {
12728            s.move_with(|map, selection| {
12729                let cursor = if selection.is_empty() {
12730                    movement::left(map, selection.start)
12731                } else {
12732                    selection.start
12733                };
12734                selection.collapse_to(cursor, SelectionGoal::None);
12735            });
12736        })
12737    }
12738
12739    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12741        self.change_selections(Default::default(), window, cx, |s| {
12742            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12743        })
12744    }
12745
12746    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12748        self.change_selections(Default::default(), window, cx, |s| {
12749            s.move_with(|map, selection| {
12750                let cursor = if selection.is_empty() {
12751                    movement::right(map, selection.end)
12752                } else {
12753                    selection.end
12754                };
12755                selection.collapse_to(cursor, SelectionGoal::None)
12756            });
12757        })
12758    }
12759
12760    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12762        self.change_selections(Default::default(), window, cx, |s| {
12763            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12764        })
12765    }
12766
12767    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12768        if self.take_rename(true, window, cx).is_some() {
12769            return;
12770        }
12771
12772        if self.mode.is_single_line() {
12773            cx.propagate();
12774            return;
12775        }
12776
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12778
12779        let text_layout_details = &self.text_layout_details(window);
12780        let selection_count = self.selections.count();
12781        let first_selection = self.selections.first_anchor();
12782
12783        self.change_selections(Default::default(), window, cx, |s| {
12784            s.move_with(|map, selection| {
12785                if !selection.is_empty() {
12786                    selection.goal = SelectionGoal::None;
12787                }
12788                let (cursor, goal) = movement::up(
12789                    map,
12790                    selection.start,
12791                    selection.goal,
12792                    false,
12793                    text_layout_details,
12794                );
12795                selection.collapse_to(cursor, goal);
12796            });
12797        });
12798
12799        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12800        {
12801            cx.propagate();
12802        }
12803    }
12804
12805    pub fn move_up_by_lines(
12806        &mut self,
12807        action: &MoveUpByLines,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) {
12811        if self.take_rename(true, window, cx).is_some() {
12812            return;
12813        }
12814
12815        if self.mode.is_single_line() {
12816            cx.propagate();
12817            return;
12818        }
12819
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821
12822        let text_layout_details = &self.text_layout_details(window);
12823
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_with(|map, selection| {
12826                if !selection.is_empty() {
12827                    selection.goal = SelectionGoal::None;
12828                }
12829                let (cursor, goal) = movement::up_by_rows(
12830                    map,
12831                    selection.start,
12832                    action.lines,
12833                    selection.goal,
12834                    false,
12835                    text_layout_details,
12836                );
12837                selection.collapse_to(cursor, goal);
12838            });
12839        })
12840    }
12841
12842    pub fn move_down_by_lines(
12843        &mut self,
12844        action: &MoveDownByLines,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        if self.take_rename(true, window, cx).is_some() {
12849            return;
12850        }
12851
12852        if self.mode.is_single_line() {
12853            cx.propagate();
12854            return;
12855        }
12856
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858
12859        let text_layout_details = &self.text_layout_details(window);
12860
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_with(|map, selection| {
12863                if !selection.is_empty() {
12864                    selection.goal = SelectionGoal::None;
12865                }
12866                let (cursor, goal) = movement::down_by_rows(
12867                    map,
12868                    selection.start,
12869                    action.lines,
12870                    selection.goal,
12871                    false,
12872                    text_layout_details,
12873                );
12874                selection.collapse_to(cursor, goal);
12875            });
12876        })
12877    }
12878
12879    pub fn select_down_by_lines(
12880        &mut self,
12881        action: &SelectDownByLines,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        let text_layout_details = &self.text_layout_details(window);
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_heads_with(|map, head, goal| {
12889                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12890            })
12891        })
12892    }
12893
12894    pub fn select_up_by_lines(
12895        &mut self,
12896        action: &SelectUpByLines,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12901        let text_layout_details = &self.text_layout_details(window);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, goal| {
12904                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12905            })
12906        })
12907    }
12908
12909    pub fn select_page_up(
12910        &mut self,
12911        _: &SelectPageUp,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        let Some(row_count) = self.visible_row_count() else {
12916            return;
12917        };
12918
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920
12921        let text_layout_details = &self.text_layout_details(window);
12922
12923        self.change_selections(Default::default(), window, cx, |s| {
12924            s.move_heads_with(|map, head, goal| {
12925                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12926            })
12927        })
12928    }
12929
12930    pub fn move_page_up(
12931        &mut self,
12932        action: &MovePageUp,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if self.take_rename(true, window, cx).is_some() {
12937            return;
12938        }
12939
12940        if self
12941            .context_menu
12942            .borrow_mut()
12943            .as_mut()
12944            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12945            .unwrap_or(false)
12946        {
12947            return;
12948        }
12949
12950        if matches!(self.mode, EditorMode::SingleLine) {
12951            cx.propagate();
12952            return;
12953        }
12954
12955        let Some(row_count) = self.visible_row_count() else {
12956            return;
12957        };
12958
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12960
12961        let effects = if action.center_cursor {
12962            SelectionEffects::scroll(Autoscroll::center())
12963        } else {
12964            SelectionEffects::default()
12965        };
12966
12967        let text_layout_details = &self.text_layout_details(window);
12968
12969        self.change_selections(effects, window, cx, |s| {
12970            s.move_with(|map, selection| {
12971                if !selection.is_empty() {
12972                    selection.goal = SelectionGoal::None;
12973                }
12974                let (cursor, goal) = movement::up_by_rows(
12975                    map,
12976                    selection.end,
12977                    row_count,
12978                    selection.goal,
12979                    false,
12980                    text_layout_details,
12981                );
12982                selection.collapse_to(cursor, goal);
12983            });
12984        });
12985    }
12986
12987    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989        let text_layout_details = &self.text_layout_details(window);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_heads_with(|map, head, goal| {
12992                movement::up(map, head, goal, false, text_layout_details)
12993            })
12994        })
12995    }
12996
12997    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12998        self.take_rename(true, window, cx);
12999
13000        if self.mode.is_single_line() {
13001            cx.propagate();
13002            return;
13003        }
13004
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006
13007        let text_layout_details = &self.text_layout_details(window);
13008        let selection_count = self.selections.count();
13009        let first_selection = self.selections.first_anchor();
13010
13011        self.change_selections(Default::default(), window, cx, |s| {
13012            s.move_with(|map, selection| {
13013                if !selection.is_empty() {
13014                    selection.goal = SelectionGoal::None;
13015                }
13016                let (cursor, goal) = movement::down(
13017                    map,
13018                    selection.end,
13019                    selection.goal,
13020                    false,
13021                    text_layout_details,
13022                );
13023                selection.collapse_to(cursor, goal);
13024            });
13025        });
13026
13027        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13028        {
13029            cx.propagate();
13030        }
13031    }
13032
13033    pub fn select_page_down(
13034        &mut self,
13035        _: &SelectPageDown,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        let Some(row_count) = self.visible_row_count() else {
13040            return;
13041        };
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_heads_with(|map, head, goal| {
13049                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13050            })
13051        })
13052    }
13053
13054    pub fn move_page_down(
13055        &mut self,
13056        action: &MovePageDown,
13057        window: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if self.take_rename(true, window, cx).is_some() {
13061            return;
13062        }
13063
13064        if self
13065            .context_menu
13066            .borrow_mut()
13067            .as_mut()
13068            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13069            .unwrap_or(false)
13070        {
13071            return;
13072        }
13073
13074        if matches!(self.mode, EditorMode::SingleLine) {
13075            cx.propagate();
13076            return;
13077        }
13078
13079        let Some(row_count) = self.visible_row_count() else {
13080            return;
13081        };
13082
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084
13085        let effects = if action.center_cursor {
13086            SelectionEffects::scroll(Autoscroll::center())
13087        } else {
13088            SelectionEffects::default()
13089        };
13090
13091        let text_layout_details = &self.text_layout_details(window);
13092        self.change_selections(effects, window, cx, |s| {
13093            s.move_with(|map, selection| {
13094                if !selection.is_empty() {
13095                    selection.goal = SelectionGoal::None;
13096                }
13097                let (cursor, goal) = movement::down_by_rows(
13098                    map,
13099                    selection.end,
13100                    row_count,
13101                    selection.goal,
13102                    false,
13103                    text_layout_details,
13104                );
13105                selection.collapse_to(cursor, goal);
13106            });
13107        });
13108    }
13109
13110    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112        let text_layout_details = &self.text_layout_details(window);
13113        self.change_selections(Default::default(), window, cx, |s| {
13114            s.move_heads_with(|map, head, goal| {
13115                movement::down(map, head, goal, false, text_layout_details)
13116            })
13117        });
13118    }
13119
13120    pub fn context_menu_first(
13121        &mut self,
13122        _: &ContextMenuFirst,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13127            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13128        }
13129    }
13130
13131    pub fn context_menu_prev(
13132        &mut self,
13133        _: &ContextMenuPrevious,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13138            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13139        }
13140    }
13141
13142    pub fn context_menu_next(
13143        &mut self,
13144        _: &ContextMenuNext,
13145        window: &mut Window,
13146        cx: &mut Context<Self>,
13147    ) {
13148        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13149            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13150        }
13151    }
13152
13153    pub fn context_menu_last(
13154        &mut self,
13155        _: &ContextMenuLast,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13160            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13161        }
13162    }
13163
13164    pub fn signature_help_prev(
13165        &mut self,
13166        _: &SignatureHelpPrevious,
13167        _: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if let Some(popover) = self.signature_help_state.popover_mut() {
13171            if popover.current_signature == 0 {
13172                popover.current_signature = popover.signatures.len() - 1;
13173            } else {
13174                popover.current_signature -= 1;
13175            }
13176            cx.notify();
13177        }
13178    }
13179
13180    pub fn signature_help_next(
13181        &mut self,
13182        _: &SignatureHelpNext,
13183        _: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        if let Some(popover) = self.signature_help_state.popover_mut() {
13187            if popover.current_signature + 1 == popover.signatures.len() {
13188                popover.current_signature = 0;
13189            } else {
13190                popover.current_signature += 1;
13191            }
13192            cx.notify();
13193        }
13194    }
13195
13196    pub fn move_to_previous_word_start(
13197        &mut self,
13198        _: &MoveToPreviousWordStart,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203        self.change_selections(Default::default(), window, cx, |s| {
13204            s.move_cursors_with(|map, head, _| {
13205                (
13206                    movement::previous_word_start(map, head),
13207                    SelectionGoal::None,
13208                )
13209            });
13210        })
13211    }
13212
13213    pub fn move_to_previous_subword_start(
13214        &mut self,
13215        _: &MoveToPreviousSubwordStart,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        self.change_selections(Default::default(), window, cx, |s| {
13221            s.move_cursors_with(|map, head, _| {
13222                (
13223                    movement::previous_subword_start(map, head),
13224                    SelectionGoal::None,
13225                )
13226            });
13227        })
13228    }
13229
13230    pub fn select_to_previous_word_start(
13231        &mut self,
13232        _: &SelectToPreviousWordStart,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13237        self.change_selections(Default::default(), window, cx, |s| {
13238            s.move_heads_with(|map, head, _| {
13239                (
13240                    movement::previous_word_start(map, head),
13241                    SelectionGoal::None,
13242                )
13243            });
13244        })
13245    }
13246
13247    pub fn select_to_previous_subword_start(
13248        &mut self,
13249        _: &SelectToPreviousSubwordStart,
13250        window: &mut Window,
13251        cx: &mut Context<Self>,
13252    ) {
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_heads_with(|map, head, _| {
13256                (
13257                    movement::previous_subword_start(map, head),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn delete_to_previous_word_start(
13265        &mut self,
13266        action: &DeleteToPreviousWordStart,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13271        self.transact(window, cx, |this, window, cx| {
13272            this.select_autoclose_pair(window, cx);
13273            this.change_selections(Default::default(), window, cx, |s| {
13274                s.move_with(|map, selection| {
13275                    if selection.is_empty() {
13276                        let mut cursor = if action.ignore_newlines {
13277                            movement::previous_word_start(map, selection.head())
13278                        } else {
13279                            movement::previous_word_start_or_newline(map, selection.head())
13280                        };
13281                        cursor = movement::adjust_greedy_deletion(
13282                            map,
13283                            selection.head(),
13284                            cursor,
13285                            action.ignore_brackets,
13286                        );
13287                        selection.set_head(cursor, SelectionGoal::None);
13288                    }
13289                });
13290            });
13291            this.insert("", window, cx);
13292        });
13293    }
13294
13295    pub fn delete_to_previous_subword_start(
13296        &mut self,
13297        _: &DeleteToPreviousSubwordStart,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13302        self.transact(window, cx, |this, window, cx| {
13303            this.select_autoclose_pair(window, cx);
13304            this.change_selections(Default::default(), window, cx, |s| {
13305                s.move_with(|map, selection| {
13306                    if selection.is_empty() {
13307                        let mut cursor = movement::previous_subword_start(map, selection.head());
13308                        cursor =
13309                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13310                        selection.set_head(cursor, SelectionGoal::None);
13311                    }
13312                });
13313            });
13314            this.insert("", window, cx);
13315        });
13316    }
13317
13318    pub fn move_to_next_word_end(
13319        &mut self,
13320        _: &MoveToNextWordEnd,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        self.change_selections(Default::default(), window, cx, |s| {
13326            s.move_cursors_with(|map, head, _| {
13327                (movement::next_word_end(map, head), SelectionGoal::None)
13328            });
13329        })
13330    }
13331
13332    pub fn move_to_next_subword_end(
13333        &mut self,
13334        _: &MoveToNextSubwordEnd,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (movement::next_subword_end(map, head), SelectionGoal::None)
13342            });
13343        })
13344    }
13345
13346    pub fn select_to_next_word_end(
13347        &mut self,
13348        _: &SelectToNextWordEnd,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.move_heads_with(|map, head, _| {
13355                (movement::next_word_end(map, head), SelectionGoal::None)
13356            });
13357        })
13358    }
13359
13360    pub fn select_to_next_subword_end(
13361        &mut self,
13362        _: &SelectToNextSubwordEnd,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (movement::next_subword_end(map, head), SelectionGoal::None)
13370            });
13371        })
13372    }
13373
13374    pub fn delete_to_next_word_end(
13375        &mut self,
13376        action: &DeleteToNextWordEnd,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13381        self.transact(window, cx, |this, window, cx| {
13382            this.change_selections(Default::default(), window, cx, |s| {
13383                s.move_with(|map, selection| {
13384                    if selection.is_empty() {
13385                        let mut cursor = if action.ignore_newlines {
13386                            movement::next_word_end(map, selection.head())
13387                        } else {
13388                            movement::next_word_end_or_newline(map, selection.head())
13389                        };
13390                        cursor = movement::adjust_greedy_deletion(
13391                            map,
13392                            selection.head(),
13393                            cursor,
13394                            action.ignore_brackets,
13395                        );
13396                        selection.set_head(cursor, SelectionGoal::None);
13397                    }
13398                });
13399            });
13400            this.insert("", window, cx);
13401        });
13402    }
13403
13404    pub fn delete_to_next_subword_end(
13405        &mut self,
13406        _: &DeleteToNextSubwordEnd,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13411        self.transact(window, cx, |this, window, cx| {
13412            this.change_selections(Default::default(), window, cx, |s| {
13413                s.move_with(|map, selection| {
13414                    if selection.is_empty() {
13415                        let mut cursor = movement::next_subword_end(map, selection.head());
13416                        cursor =
13417                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13418                        selection.set_head(cursor, SelectionGoal::None);
13419                    }
13420                });
13421            });
13422            this.insert("", window, cx);
13423        });
13424    }
13425
13426    pub fn move_to_beginning_of_line(
13427        &mut self,
13428        action: &MoveToBeginningOfLine,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13433        self.change_selections(Default::default(), window, cx, |s| {
13434            s.move_cursors_with(|map, head, _| {
13435                (
13436                    movement::indented_line_beginning(
13437                        map,
13438                        head,
13439                        action.stop_at_soft_wraps,
13440                        action.stop_at_indent,
13441                    ),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_beginning_of_line(
13449        &mut self,
13450        action: &SelectToBeginningOfLine,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        self.change_selections(Default::default(), window, cx, |s| {
13456            s.move_heads_with(|map, head, _| {
13457                (
13458                    movement::indented_line_beginning(
13459                        map,
13460                        head,
13461                        action.stop_at_soft_wraps,
13462                        action.stop_at_indent,
13463                    ),
13464                    SelectionGoal::None,
13465                )
13466            });
13467        });
13468    }
13469
13470    pub fn delete_to_beginning_of_line(
13471        &mut self,
13472        action: &DeleteToBeginningOfLine,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13477        self.transact(window, cx, |this, window, cx| {
13478            this.change_selections(Default::default(), window, cx, |s| {
13479                s.move_with(|_, selection| {
13480                    selection.reversed = true;
13481                });
13482            });
13483
13484            this.select_to_beginning_of_line(
13485                &SelectToBeginningOfLine {
13486                    stop_at_soft_wraps: false,
13487                    stop_at_indent: action.stop_at_indent,
13488                },
13489                window,
13490                cx,
13491            );
13492            this.backspace(&Backspace, window, cx);
13493        });
13494    }
13495
13496    pub fn move_to_end_of_line(
13497        &mut self,
13498        action: &MoveToEndOfLine,
13499        window: &mut Window,
13500        cx: &mut Context<Self>,
13501    ) {
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503        self.change_selections(Default::default(), window, cx, |s| {
13504            s.move_cursors_with(|map, head, _| {
13505                (
13506                    movement::line_end(map, head, action.stop_at_soft_wraps),
13507                    SelectionGoal::None,
13508                )
13509            });
13510        })
13511    }
13512
13513    pub fn select_to_end_of_line(
13514        &mut self,
13515        action: &SelectToEndOfLine,
13516        window: &mut Window,
13517        cx: &mut Context<Self>,
13518    ) {
13519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13520        self.change_selections(Default::default(), window, cx, |s| {
13521            s.move_heads_with(|map, head, _| {
13522                (
13523                    movement::line_end(map, head, action.stop_at_soft_wraps),
13524                    SelectionGoal::None,
13525                )
13526            });
13527        })
13528    }
13529
13530    pub fn delete_to_end_of_line(
13531        &mut self,
13532        _: &DeleteToEndOfLine,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13537        self.transact(window, cx, |this, window, cx| {
13538            this.select_to_end_of_line(
13539                &SelectToEndOfLine {
13540                    stop_at_soft_wraps: false,
13541                },
13542                window,
13543                cx,
13544            );
13545            this.delete(&Delete, window, cx);
13546        });
13547    }
13548
13549    pub fn cut_to_end_of_line(
13550        &mut self,
13551        action: &CutToEndOfLine,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        self.transact(window, cx, |this, window, cx| {
13557            this.select_to_end_of_line(
13558                &SelectToEndOfLine {
13559                    stop_at_soft_wraps: false,
13560                },
13561                window,
13562                cx,
13563            );
13564            if !action.stop_at_newlines {
13565                this.change_selections(Default::default(), window, cx, |s| {
13566                    s.move_with(|_, sel| {
13567                        if sel.is_empty() {
13568                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13569                        }
13570                    });
13571                });
13572            }
13573            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13574            let item = this.cut_common(false, window, cx);
13575            cx.write_to_clipboard(item);
13576        });
13577    }
13578
13579    pub fn move_to_start_of_paragraph(
13580        &mut self,
13581        _: &MoveToStartOfParagraph,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if matches!(self.mode, EditorMode::SingleLine) {
13586            cx.propagate();
13587            return;
13588        }
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_with(|map, selection| {
13592                selection.collapse_to(
13593                    movement::start_of_paragraph(map, selection.head(), 1),
13594                    SelectionGoal::None,
13595                )
13596            });
13597        })
13598    }
13599
13600    pub fn move_to_end_of_paragraph(
13601        &mut self,
13602        _: &MoveToEndOfParagraph,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        if matches!(self.mode, EditorMode::SingleLine) {
13607            cx.propagate();
13608            return;
13609        }
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                selection.collapse_to(
13614                    movement::end_of_paragraph(map, selection.head(), 1),
13615                    SelectionGoal::None,
13616                )
13617            });
13618        })
13619    }
13620
13621    pub fn select_to_start_of_paragraph(
13622        &mut self,
13623        _: &SelectToStartOfParagraph,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        if matches!(self.mode, EditorMode::SingleLine) {
13628            cx.propagate();
13629            return;
13630        }
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_heads_with(|map, head, _| {
13634                (
13635                    movement::start_of_paragraph(map, head, 1),
13636                    SelectionGoal::None,
13637                )
13638            });
13639        })
13640    }
13641
13642    pub fn select_to_end_of_paragraph(
13643        &mut self,
13644        _: &SelectToEndOfParagraph,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        if matches!(self.mode, EditorMode::SingleLine) {
13649            cx.propagate();
13650            return;
13651        }
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, _| {
13655                (
13656                    movement::end_of_paragraph(map, head, 1),
13657                    SelectionGoal::None,
13658                )
13659            });
13660        })
13661    }
13662
13663    pub fn move_to_start_of_excerpt(
13664        &mut self,
13665        _: &MoveToStartOfExcerpt,
13666        window: &mut Window,
13667        cx: &mut Context<Self>,
13668    ) {
13669        if matches!(self.mode, EditorMode::SingleLine) {
13670            cx.propagate();
13671            return;
13672        }
13673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13674        self.change_selections(Default::default(), window, cx, |s| {
13675            s.move_with(|map, selection| {
13676                selection.collapse_to(
13677                    movement::start_of_excerpt(
13678                        map,
13679                        selection.head(),
13680                        workspace::searchable::Direction::Prev,
13681                    ),
13682                    SelectionGoal::None,
13683                )
13684            });
13685        })
13686    }
13687
13688    pub fn move_to_start_of_next_excerpt(
13689        &mut self,
13690        _: &MoveToStartOfNextExcerpt,
13691        window: &mut Window,
13692        cx: &mut Context<Self>,
13693    ) {
13694        if matches!(self.mode, EditorMode::SingleLine) {
13695            cx.propagate();
13696            return;
13697        }
13698
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.move_with(|map, selection| {
13701                selection.collapse_to(
13702                    movement::start_of_excerpt(
13703                        map,
13704                        selection.head(),
13705                        workspace::searchable::Direction::Next,
13706                    ),
13707                    SelectionGoal::None,
13708                )
13709            });
13710        })
13711    }
13712
13713    pub fn move_to_end_of_excerpt(
13714        &mut self,
13715        _: &MoveToEndOfExcerpt,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if matches!(self.mode, EditorMode::SingleLine) {
13720            cx.propagate();
13721            return;
13722        }
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                selection.collapse_to(
13727                    movement::end_of_excerpt(
13728                        map,
13729                        selection.head(),
13730                        workspace::searchable::Direction::Next,
13731                    ),
13732                    SelectionGoal::None,
13733                )
13734            });
13735        })
13736    }
13737
13738    pub fn move_to_end_of_previous_excerpt(
13739        &mut self,
13740        _: &MoveToEndOfPreviousExcerpt,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if matches!(self.mode, EditorMode::SingleLine) {
13745            cx.propagate();
13746            return;
13747        }
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        self.change_selections(Default::default(), window, cx, |s| {
13750            s.move_with(|map, selection| {
13751                selection.collapse_to(
13752                    movement::end_of_excerpt(
13753                        map,
13754                        selection.head(),
13755                        workspace::searchable::Direction::Prev,
13756                    ),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_start_of_excerpt(
13764        &mut self,
13765        _: &SelectToStartOfExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn select_to_start_of_next_excerpt(
13785        &mut self,
13786        _: &SelectToStartOfNextExcerpt,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_heads_with(|map, head, _| {
13797                (
13798                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13799                    SelectionGoal::None,
13800                )
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_end_of_excerpt(
13806        &mut self,
13807        _: &SelectToEndOfExcerpt,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        if matches!(self.mode, EditorMode::SingleLine) {
13812            cx.propagate();
13813            return;
13814        }
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (
13819                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn select_to_end_of_previous_excerpt(
13827        &mut self,
13828        _: &SelectToEndOfPreviousExcerpt,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_heads_with(|map, head, _| {
13839                (
13840                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_beginning(
13848        &mut self,
13849        _: &MoveToBeginning,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.select_ranges(vec![0..0]);
13860        });
13861    }
13862
13863    pub fn select_to_beginning(
13864        &mut self,
13865        _: &SelectToBeginning,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        let mut selection = self.selections.last::<Point>(cx);
13870        selection.set_head(Point::zero(), SelectionGoal::None);
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.select(vec![selection]);
13874        });
13875    }
13876
13877    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        let cursor = self.buffer.read(cx).read(cx).len();
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.select_ranges(vec![cursor..cursor])
13886        });
13887    }
13888
13889    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13890        self.nav_history = nav_history;
13891    }
13892
13893    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13894        self.nav_history.as_ref()
13895    }
13896
13897    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13898        self.push_to_nav_history(
13899            self.selections.newest_anchor().head(),
13900            None,
13901            false,
13902            true,
13903            cx,
13904        );
13905    }
13906
13907    fn push_to_nav_history(
13908        &mut self,
13909        cursor_anchor: Anchor,
13910        new_position: Option<Point>,
13911        is_deactivate: bool,
13912        always: bool,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if let Some(nav_history) = self.nav_history.as_mut() {
13916            let buffer = self.buffer.read(cx).read(cx);
13917            let cursor_position = cursor_anchor.to_point(&buffer);
13918            let scroll_state = self.scroll_manager.anchor();
13919            let scroll_top_row = scroll_state.top_row(&buffer);
13920            drop(buffer);
13921
13922            if let Some(new_position) = new_position {
13923                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13924                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13925                    return;
13926                }
13927            }
13928
13929            nav_history.push(
13930                Some(NavigationData {
13931                    cursor_anchor,
13932                    cursor_position,
13933                    scroll_anchor: scroll_state,
13934                    scroll_top_row,
13935                }),
13936                cx,
13937            );
13938            cx.emit(EditorEvent::PushedToNavHistory {
13939                anchor: cursor_anchor,
13940                is_deactivate,
13941            })
13942        }
13943    }
13944
13945    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        let buffer = self.buffer.read(cx).snapshot(cx);
13948        let mut selection = self.selections.first::<usize>(cx);
13949        selection.set_head(buffer.len(), SelectionGoal::None);
13950        self.change_selections(Default::default(), window, cx, |s| {
13951            s.select(vec![selection]);
13952        });
13953    }
13954
13955    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13957        let end = self.buffer.read(cx).read(cx).len();
13958        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13959            s.select_ranges(vec![0..end]);
13960        });
13961    }
13962
13963    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13965        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13966        let mut selections = self.selections.all::<Point>(cx);
13967        let max_point = display_map.buffer_snapshot.max_point();
13968        for selection in &mut selections {
13969            let rows = selection.spanned_rows(true, &display_map);
13970            selection.start = Point::new(rows.start.0, 0);
13971            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13972            selection.reversed = false;
13973        }
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.select(selections);
13976        });
13977    }
13978
13979    pub fn split_selection_into_lines(
13980        &mut self,
13981        action: &SplitSelectionIntoLines,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        let selections = self
13986            .selections
13987            .all::<Point>(cx)
13988            .into_iter()
13989            .map(|selection| selection.start..selection.end)
13990            .collect::<Vec<_>>();
13991        self.unfold_ranges(&selections, true, true, cx);
13992
13993        let mut new_selection_ranges = Vec::new();
13994        {
13995            let buffer = self.buffer.read(cx).read(cx);
13996            for selection in selections {
13997                for row in selection.start.row..selection.end.row {
13998                    let line_start = Point::new(row, 0);
13999                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14000
14001                    if action.keep_selections {
14002                        // Keep the selection range for each line
14003                        let selection_start = if row == selection.start.row {
14004                            selection.start
14005                        } else {
14006                            line_start
14007                        };
14008                        new_selection_ranges.push(selection_start..line_end);
14009                    } else {
14010                        // Collapse to cursor at end of line
14011                        new_selection_ranges.push(line_end..line_end);
14012                    }
14013                }
14014
14015                let is_multiline_selection = selection.start.row != selection.end.row;
14016                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14017                // so this action feels more ergonomic when paired with other selection operations
14018                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14019                if !should_skip_last {
14020                    if action.keep_selections {
14021                        if is_multiline_selection {
14022                            let line_start = Point::new(selection.end.row, 0);
14023                            new_selection_ranges.push(line_start..selection.end);
14024                        } else {
14025                            new_selection_ranges.push(selection.start..selection.end);
14026                        }
14027                    } else {
14028                        new_selection_ranges.push(selection.end..selection.end);
14029                    }
14030                }
14031            }
14032        }
14033        self.change_selections(Default::default(), window, cx, |s| {
14034            s.select_ranges(new_selection_ranges);
14035        });
14036    }
14037
14038    pub fn add_selection_above(
14039        &mut self,
14040        _: &AddSelectionAbove,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        self.add_selection(true, window, cx);
14045    }
14046
14047    pub fn add_selection_below(
14048        &mut self,
14049        _: &AddSelectionBelow,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        self.add_selection(false, window, cx);
14054    }
14055
14056    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14058
14059        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14060        let all_selections = self.selections.all::<Point>(cx);
14061        let text_layout_details = self.text_layout_details(window);
14062
14063        let (mut columnar_selections, new_selections_to_columnarize) = {
14064            if let Some(state) = self.add_selections_state.as_ref() {
14065                let columnar_selection_ids: HashSet<_> = state
14066                    .groups
14067                    .iter()
14068                    .flat_map(|group| group.stack.iter())
14069                    .copied()
14070                    .collect();
14071
14072                all_selections
14073                    .into_iter()
14074                    .partition(|s| columnar_selection_ids.contains(&s.id))
14075            } else {
14076                (Vec::new(), all_selections)
14077            }
14078        };
14079
14080        let mut state = self
14081            .add_selections_state
14082            .take()
14083            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14084
14085        for selection in new_selections_to_columnarize {
14086            let range = selection.display_range(&display_map).sorted();
14087            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14088            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14089            let positions = start_x.min(end_x)..start_x.max(end_x);
14090            let mut stack = Vec::new();
14091            for row in range.start.row().0..=range.end.row().0 {
14092                if let Some(selection) = self.selections.build_columnar_selection(
14093                    &display_map,
14094                    DisplayRow(row),
14095                    &positions,
14096                    selection.reversed,
14097                    &text_layout_details,
14098                ) {
14099                    stack.push(selection.id);
14100                    columnar_selections.push(selection);
14101                }
14102            }
14103            if !stack.is_empty() {
14104                if above {
14105                    stack.reverse();
14106                }
14107                state.groups.push(AddSelectionsGroup { above, stack });
14108            }
14109        }
14110
14111        let mut final_selections = Vec::new();
14112        let end_row = if above {
14113            DisplayRow(0)
14114        } else {
14115            display_map.max_point().row()
14116        };
14117
14118        let mut last_added_item_per_group = HashMap::default();
14119        for group in state.groups.iter_mut() {
14120            if let Some(last_id) = group.stack.last() {
14121                last_added_item_per_group.insert(*last_id, group);
14122            }
14123        }
14124
14125        for selection in columnar_selections {
14126            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14127                if above == group.above {
14128                    let range = selection.display_range(&display_map).sorted();
14129                    debug_assert_eq!(range.start.row(), range.end.row());
14130                    let mut row = range.start.row();
14131                    let positions =
14132                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14133                            px(start)..px(end)
14134                        } else {
14135                            let start_x =
14136                                display_map.x_for_display_point(range.start, &text_layout_details);
14137                            let end_x =
14138                                display_map.x_for_display_point(range.end, &text_layout_details);
14139                            start_x.min(end_x)..start_x.max(end_x)
14140                        };
14141
14142                    let mut maybe_new_selection = None;
14143                    while row != end_row {
14144                        if above {
14145                            row.0 -= 1;
14146                        } else {
14147                            row.0 += 1;
14148                        }
14149                        if let Some(new_selection) = self.selections.build_columnar_selection(
14150                            &display_map,
14151                            row,
14152                            &positions,
14153                            selection.reversed,
14154                            &text_layout_details,
14155                        ) {
14156                            maybe_new_selection = Some(new_selection);
14157                            break;
14158                        }
14159                    }
14160
14161                    if let Some(new_selection) = maybe_new_selection {
14162                        group.stack.push(new_selection.id);
14163                        if above {
14164                            final_selections.push(new_selection);
14165                            final_selections.push(selection);
14166                        } else {
14167                            final_selections.push(selection);
14168                            final_selections.push(new_selection);
14169                        }
14170                    } else {
14171                        final_selections.push(selection);
14172                    }
14173                } else {
14174                    group.stack.pop();
14175                }
14176            } else {
14177                final_selections.push(selection);
14178            }
14179        }
14180
14181        self.change_selections(Default::default(), window, cx, |s| {
14182            s.select(final_selections);
14183        });
14184
14185        let final_selection_ids: HashSet<_> = self
14186            .selections
14187            .all::<Point>(cx)
14188            .iter()
14189            .map(|s| s.id)
14190            .collect();
14191        state.groups.retain_mut(|group| {
14192            // selections might get merged above so we remove invalid items from stacks
14193            group.stack.retain(|id| final_selection_ids.contains(id));
14194
14195            // single selection in stack can be treated as initial state
14196            group.stack.len() > 1
14197        });
14198
14199        if !state.groups.is_empty() {
14200            self.add_selections_state = Some(state);
14201        }
14202    }
14203
14204    fn select_match_ranges(
14205        &mut self,
14206        range: Range<usize>,
14207        reversed: bool,
14208        replace_newest: bool,
14209        auto_scroll: Option<Autoscroll>,
14210        window: &mut Window,
14211        cx: &mut Context<Editor>,
14212    ) {
14213        self.unfold_ranges(
14214            std::slice::from_ref(&range),
14215            false,
14216            auto_scroll.is_some(),
14217            cx,
14218        );
14219        let effects = if let Some(scroll) = auto_scroll {
14220            SelectionEffects::scroll(scroll)
14221        } else {
14222            SelectionEffects::no_scroll()
14223        };
14224        self.change_selections(effects, window, cx, |s| {
14225            if replace_newest {
14226                s.delete(s.newest_anchor().id);
14227            }
14228            if reversed {
14229                s.insert_range(range.end..range.start);
14230            } else {
14231                s.insert_range(range);
14232            }
14233        });
14234    }
14235
14236    pub fn select_next_match_internal(
14237        &mut self,
14238        display_map: &DisplaySnapshot,
14239        replace_newest: bool,
14240        autoscroll: Option<Autoscroll>,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Result<()> {
14244        let buffer = &display_map.buffer_snapshot;
14245        let mut selections = self.selections.all::<usize>(cx);
14246        if let Some(mut select_next_state) = self.select_next_state.take() {
14247            let query = &select_next_state.query;
14248            if !select_next_state.done {
14249                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14250                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14251                let mut next_selected_range = None;
14252
14253                let bytes_after_last_selection =
14254                    buffer.bytes_in_range(last_selection.end..buffer.len());
14255                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14256                let query_matches = query
14257                    .stream_find_iter(bytes_after_last_selection)
14258                    .map(|result| (last_selection.end, result))
14259                    .chain(
14260                        query
14261                            .stream_find_iter(bytes_before_first_selection)
14262                            .map(|result| (0, result)),
14263                    );
14264
14265                for (start_offset, query_match) in query_matches {
14266                    let query_match = query_match.unwrap(); // can only fail due to I/O
14267                    let offset_range =
14268                        start_offset + query_match.start()..start_offset + query_match.end();
14269
14270                    if !select_next_state.wordwise
14271                        || (!buffer.is_inside_word(offset_range.start, None)
14272                            && !buffer.is_inside_word(offset_range.end, None))
14273                    {
14274                        // TODO: This is n^2, because we might check all the selections
14275                        if !selections
14276                            .iter()
14277                            .any(|selection| selection.range().overlaps(&offset_range))
14278                        {
14279                            next_selected_range = Some(offset_range);
14280                            break;
14281                        }
14282                    }
14283                }
14284
14285                if let Some(next_selected_range) = next_selected_range {
14286                    self.select_match_ranges(
14287                        next_selected_range,
14288                        last_selection.reversed,
14289                        replace_newest,
14290                        autoscroll,
14291                        window,
14292                        cx,
14293                    );
14294                } else {
14295                    select_next_state.done = true;
14296                }
14297            }
14298
14299            self.select_next_state = Some(select_next_state);
14300        } else {
14301            let mut only_carets = true;
14302            let mut same_text_selected = true;
14303            let mut selected_text = None;
14304
14305            let mut selections_iter = selections.iter().peekable();
14306            while let Some(selection) = selections_iter.next() {
14307                if selection.start != selection.end {
14308                    only_carets = false;
14309                }
14310
14311                if same_text_selected {
14312                    if selected_text.is_none() {
14313                        selected_text =
14314                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14315                    }
14316
14317                    if let Some(next_selection) = selections_iter.peek() {
14318                        if next_selection.range().len() == selection.range().len() {
14319                            let next_selected_text = buffer
14320                                .text_for_range(next_selection.range())
14321                                .collect::<String>();
14322                            if Some(next_selected_text) != selected_text {
14323                                same_text_selected = false;
14324                                selected_text = None;
14325                            }
14326                        } else {
14327                            same_text_selected = false;
14328                            selected_text = None;
14329                        }
14330                    }
14331                }
14332            }
14333
14334            if only_carets {
14335                for selection in &mut selections {
14336                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14337                    selection.start = word_range.start;
14338                    selection.end = word_range.end;
14339                    selection.goal = SelectionGoal::None;
14340                    selection.reversed = false;
14341                    self.select_match_ranges(
14342                        selection.start..selection.end,
14343                        selection.reversed,
14344                        replace_newest,
14345                        autoscroll,
14346                        window,
14347                        cx,
14348                    );
14349                }
14350
14351                if selections.len() == 1 {
14352                    let selection = selections
14353                        .last()
14354                        .expect("ensured that there's only one selection");
14355                    let query = buffer
14356                        .text_for_range(selection.start..selection.end)
14357                        .collect::<String>();
14358                    let is_empty = query.is_empty();
14359                    let select_state = SelectNextState {
14360                        query: AhoCorasick::new(&[query])?,
14361                        wordwise: true,
14362                        done: is_empty,
14363                    };
14364                    self.select_next_state = Some(select_state);
14365                } else {
14366                    self.select_next_state = None;
14367                }
14368            } else if let Some(selected_text) = selected_text {
14369                self.select_next_state = Some(SelectNextState {
14370                    query: AhoCorasick::new(&[selected_text])?,
14371                    wordwise: false,
14372                    done: false,
14373                });
14374                self.select_next_match_internal(
14375                    display_map,
14376                    replace_newest,
14377                    autoscroll,
14378                    window,
14379                    cx,
14380                )?;
14381            }
14382        }
14383        Ok(())
14384    }
14385
14386    pub fn select_all_matches(
14387        &mut self,
14388        _action: &SelectAllMatches,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) -> Result<()> {
14392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14393
14394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14395
14396        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14397        let Some(select_next_state) = self.select_next_state.as_mut() else {
14398            return Ok(());
14399        };
14400        if select_next_state.done {
14401            return Ok(());
14402        }
14403
14404        let mut new_selections = Vec::new();
14405
14406        let reversed = self.selections.oldest::<usize>(cx).reversed;
14407        let buffer = &display_map.buffer_snapshot;
14408        let query_matches = select_next_state
14409            .query
14410            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14411
14412        for query_match in query_matches.into_iter() {
14413            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14414            let offset_range = if reversed {
14415                query_match.end()..query_match.start()
14416            } else {
14417                query_match.start()..query_match.end()
14418            };
14419
14420            if !select_next_state.wordwise
14421                || (!buffer.is_inside_word(offset_range.start, None)
14422                    && !buffer.is_inside_word(offset_range.end, None))
14423            {
14424                new_selections.push(offset_range.start..offset_range.end);
14425            }
14426        }
14427
14428        select_next_state.done = true;
14429
14430        if new_selections.is_empty() {
14431            log::error!("bug: new_selections is empty in select_all_matches");
14432            return Ok(());
14433        }
14434
14435        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14436        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14437            selections.select_ranges(new_selections)
14438        });
14439
14440        Ok(())
14441    }
14442
14443    pub fn select_next(
14444        &mut self,
14445        action: &SelectNext,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) -> Result<()> {
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14451        self.select_next_match_internal(
14452            &display_map,
14453            action.replace_newest,
14454            Some(Autoscroll::newest()),
14455            window,
14456            cx,
14457        )?;
14458        Ok(())
14459    }
14460
14461    pub fn select_previous(
14462        &mut self,
14463        action: &SelectPrevious,
14464        window: &mut Window,
14465        cx: &mut Context<Self>,
14466    ) -> Result<()> {
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14469        let buffer = &display_map.buffer_snapshot;
14470        let mut selections = self.selections.all::<usize>(cx);
14471        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14472            let query = &select_prev_state.query;
14473            if !select_prev_state.done {
14474                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14475                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14476                let mut next_selected_range = None;
14477                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14478                let bytes_before_last_selection =
14479                    buffer.reversed_bytes_in_range(0..last_selection.start);
14480                let bytes_after_first_selection =
14481                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14482                let query_matches = query
14483                    .stream_find_iter(bytes_before_last_selection)
14484                    .map(|result| (last_selection.start, result))
14485                    .chain(
14486                        query
14487                            .stream_find_iter(bytes_after_first_selection)
14488                            .map(|result| (buffer.len(), result)),
14489                    );
14490                for (end_offset, query_match) in query_matches {
14491                    let query_match = query_match.unwrap(); // can only fail due to I/O
14492                    let offset_range =
14493                        end_offset - query_match.end()..end_offset - query_match.start();
14494
14495                    if !select_prev_state.wordwise
14496                        || (!buffer.is_inside_word(offset_range.start, None)
14497                            && !buffer.is_inside_word(offset_range.end, None))
14498                    {
14499                        next_selected_range = Some(offset_range);
14500                        break;
14501                    }
14502                }
14503
14504                if let Some(next_selected_range) = next_selected_range {
14505                    self.select_match_ranges(
14506                        next_selected_range,
14507                        last_selection.reversed,
14508                        action.replace_newest,
14509                        Some(Autoscroll::newest()),
14510                        window,
14511                        cx,
14512                    );
14513                } else {
14514                    select_prev_state.done = true;
14515                }
14516            }
14517
14518            self.select_prev_state = Some(select_prev_state);
14519        } else {
14520            let mut only_carets = true;
14521            let mut same_text_selected = true;
14522            let mut selected_text = None;
14523
14524            let mut selections_iter = selections.iter().peekable();
14525            while let Some(selection) = selections_iter.next() {
14526                if selection.start != selection.end {
14527                    only_carets = false;
14528                }
14529
14530                if same_text_selected {
14531                    if selected_text.is_none() {
14532                        selected_text =
14533                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14534                    }
14535
14536                    if let Some(next_selection) = selections_iter.peek() {
14537                        if next_selection.range().len() == selection.range().len() {
14538                            let next_selected_text = buffer
14539                                .text_for_range(next_selection.range())
14540                                .collect::<String>();
14541                            if Some(next_selected_text) != selected_text {
14542                                same_text_selected = false;
14543                                selected_text = None;
14544                            }
14545                        } else {
14546                            same_text_selected = false;
14547                            selected_text = None;
14548                        }
14549                    }
14550                }
14551            }
14552
14553            if only_carets {
14554                for selection in &mut selections {
14555                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14556                    selection.start = word_range.start;
14557                    selection.end = word_range.end;
14558                    selection.goal = SelectionGoal::None;
14559                    selection.reversed = false;
14560                    self.select_match_ranges(
14561                        selection.start..selection.end,
14562                        selection.reversed,
14563                        action.replace_newest,
14564                        Some(Autoscroll::newest()),
14565                        window,
14566                        cx,
14567                    );
14568                }
14569                if selections.len() == 1 {
14570                    let selection = selections
14571                        .last()
14572                        .expect("ensured that there's only one selection");
14573                    let query = buffer
14574                        .text_for_range(selection.start..selection.end)
14575                        .collect::<String>();
14576                    let is_empty = query.is_empty();
14577                    let select_state = SelectNextState {
14578                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14579                        wordwise: true,
14580                        done: is_empty,
14581                    };
14582                    self.select_prev_state = Some(select_state);
14583                } else {
14584                    self.select_prev_state = None;
14585                }
14586            } else if let Some(selected_text) = selected_text {
14587                self.select_prev_state = Some(SelectNextState {
14588                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14589                    wordwise: false,
14590                    done: false,
14591                });
14592                self.select_previous(action, window, cx)?;
14593            }
14594        }
14595        Ok(())
14596    }
14597
14598    pub fn find_next_match(
14599        &mut self,
14600        _: &FindNextMatch,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) -> Result<()> {
14604        let selections = self.selections.disjoint_anchors_arc();
14605        match selections.first() {
14606            Some(first) if selections.len() >= 2 => {
14607                self.change_selections(Default::default(), window, cx, |s| {
14608                    s.select_ranges([first.range()]);
14609                });
14610            }
14611            _ => self.select_next(
14612                &SelectNext {
14613                    replace_newest: true,
14614                },
14615                window,
14616                cx,
14617            )?,
14618        }
14619        Ok(())
14620    }
14621
14622    pub fn find_previous_match(
14623        &mut self,
14624        _: &FindPreviousMatch,
14625        window: &mut Window,
14626        cx: &mut Context<Self>,
14627    ) -> Result<()> {
14628        let selections = self.selections.disjoint_anchors_arc();
14629        match selections.last() {
14630            Some(last) if selections.len() >= 2 => {
14631                self.change_selections(Default::default(), window, cx, |s| {
14632                    s.select_ranges([last.range()]);
14633                });
14634            }
14635            _ => self.select_previous(
14636                &SelectPrevious {
14637                    replace_newest: true,
14638                },
14639                window,
14640                cx,
14641            )?,
14642        }
14643        Ok(())
14644    }
14645
14646    pub fn toggle_comments(
14647        &mut self,
14648        action: &ToggleComments,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) {
14652        if self.read_only(cx) {
14653            return;
14654        }
14655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14656        let text_layout_details = &self.text_layout_details(window);
14657        self.transact(window, cx, |this, window, cx| {
14658            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14659            let mut edits = Vec::new();
14660            let mut selection_edit_ranges = Vec::new();
14661            let mut last_toggled_row = None;
14662            let snapshot = this.buffer.read(cx).read(cx);
14663            let empty_str: Arc<str> = Arc::default();
14664            let mut suffixes_inserted = Vec::new();
14665            let ignore_indent = action.ignore_indent;
14666
14667            fn comment_prefix_range(
14668                snapshot: &MultiBufferSnapshot,
14669                row: MultiBufferRow,
14670                comment_prefix: &str,
14671                comment_prefix_whitespace: &str,
14672                ignore_indent: bool,
14673            ) -> Range<Point> {
14674                let indent_size = if ignore_indent {
14675                    0
14676                } else {
14677                    snapshot.indent_size_for_line(row).len
14678                };
14679
14680                let start = Point::new(row.0, indent_size);
14681
14682                let mut line_bytes = snapshot
14683                    .bytes_in_range(start..snapshot.max_point())
14684                    .flatten()
14685                    .copied();
14686
14687                // If this line currently begins with the line comment prefix, then record
14688                // the range containing the prefix.
14689                if line_bytes
14690                    .by_ref()
14691                    .take(comment_prefix.len())
14692                    .eq(comment_prefix.bytes())
14693                {
14694                    // Include any whitespace that matches the comment prefix.
14695                    let matching_whitespace_len = line_bytes
14696                        .zip(comment_prefix_whitespace.bytes())
14697                        .take_while(|(a, b)| a == b)
14698                        .count() as u32;
14699                    let end = Point::new(
14700                        start.row,
14701                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14702                    );
14703                    start..end
14704                } else {
14705                    start..start
14706                }
14707            }
14708
14709            fn comment_suffix_range(
14710                snapshot: &MultiBufferSnapshot,
14711                row: MultiBufferRow,
14712                comment_suffix: &str,
14713                comment_suffix_has_leading_space: bool,
14714            ) -> Range<Point> {
14715                let end = Point::new(row.0, snapshot.line_len(row));
14716                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14717
14718                let mut line_end_bytes = snapshot
14719                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14720                    .flatten()
14721                    .copied();
14722
14723                let leading_space_len = if suffix_start_column > 0
14724                    && line_end_bytes.next() == Some(b' ')
14725                    && comment_suffix_has_leading_space
14726                {
14727                    1
14728                } else {
14729                    0
14730                };
14731
14732                // If this line currently begins with the line comment prefix, then record
14733                // the range containing the prefix.
14734                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14735                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14736                    start..end
14737                } else {
14738                    end..end
14739                }
14740            }
14741
14742            // TODO: Handle selections that cross excerpts
14743            for selection in &mut selections {
14744                let start_column = snapshot
14745                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14746                    .len;
14747                let language = if let Some(language) =
14748                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14749                {
14750                    language
14751                } else {
14752                    continue;
14753                };
14754
14755                selection_edit_ranges.clear();
14756
14757                // If multiple selections contain a given row, avoid processing that
14758                // row more than once.
14759                let mut start_row = MultiBufferRow(selection.start.row);
14760                if last_toggled_row == Some(start_row) {
14761                    start_row = start_row.next_row();
14762                }
14763                let end_row =
14764                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14765                        MultiBufferRow(selection.end.row - 1)
14766                    } else {
14767                        MultiBufferRow(selection.end.row)
14768                    };
14769                last_toggled_row = Some(end_row);
14770
14771                if start_row > end_row {
14772                    continue;
14773                }
14774
14775                // If the language has line comments, toggle those.
14776                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14777
14778                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14779                if ignore_indent {
14780                    full_comment_prefixes = full_comment_prefixes
14781                        .into_iter()
14782                        .map(|s| Arc::from(s.trim_end()))
14783                        .collect();
14784                }
14785
14786                if !full_comment_prefixes.is_empty() {
14787                    let first_prefix = full_comment_prefixes
14788                        .first()
14789                        .expect("prefixes is non-empty");
14790                    let prefix_trimmed_lengths = full_comment_prefixes
14791                        .iter()
14792                        .map(|p| p.trim_end_matches(' ').len())
14793                        .collect::<SmallVec<[usize; 4]>>();
14794
14795                    let mut all_selection_lines_are_comments = true;
14796
14797                    for row in start_row.0..=end_row.0 {
14798                        let row = MultiBufferRow(row);
14799                        if start_row < end_row && snapshot.is_line_blank(row) {
14800                            continue;
14801                        }
14802
14803                        let prefix_range = full_comment_prefixes
14804                            .iter()
14805                            .zip(prefix_trimmed_lengths.iter().copied())
14806                            .map(|(prefix, trimmed_prefix_len)| {
14807                                comment_prefix_range(
14808                                    snapshot.deref(),
14809                                    row,
14810                                    &prefix[..trimmed_prefix_len],
14811                                    &prefix[trimmed_prefix_len..],
14812                                    ignore_indent,
14813                                )
14814                            })
14815                            .max_by_key(|range| range.end.column - range.start.column)
14816                            .expect("prefixes is non-empty");
14817
14818                        if prefix_range.is_empty() {
14819                            all_selection_lines_are_comments = false;
14820                        }
14821
14822                        selection_edit_ranges.push(prefix_range);
14823                    }
14824
14825                    if all_selection_lines_are_comments {
14826                        edits.extend(
14827                            selection_edit_ranges
14828                                .iter()
14829                                .cloned()
14830                                .map(|range| (range, empty_str.clone())),
14831                        );
14832                    } else {
14833                        let min_column = selection_edit_ranges
14834                            .iter()
14835                            .map(|range| range.start.column)
14836                            .min()
14837                            .unwrap_or(0);
14838                        edits.extend(selection_edit_ranges.iter().map(|range| {
14839                            let position = Point::new(range.start.row, min_column);
14840                            (position..position, first_prefix.clone())
14841                        }));
14842                    }
14843                } else if let Some(BlockCommentConfig {
14844                    start: full_comment_prefix,
14845                    end: comment_suffix,
14846                    ..
14847                }) = language.block_comment()
14848                {
14849                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14850                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14851                    let prefix_range = comment_prefix_range(
14852                        snapshot.deref(),
14853                        start_row,
14854                        comment_prefix,
14855                        comment_prefix_whitespace,
14856                        ignore_indent,
14857                    );
14858                    let suffix_range = comment_suffix_range(
14859                        snapshot.deref(),
14860                        end_row,
14861                        comment_suffix.trim_start_matches(' '),
14862                        comment_suffix.starts_with(' '),
14863                    );
14864
14865                    if prefix_range.is_empty() || suffix_range.is_empty() {
14866                        edits.push((
14867                            prefix_range.start..prefix_range.start,
14868                            full_comment_prefix.clone(),
14869                        ));
14870                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14871                        suffixes_inserted.push((end_row, comment_suffix.len()));
14872                    } else {
14873                        edits.push((prefix_range, empty_str.clone()));
14874                        edits.push((suffix_range, empty_str.clone()));
14875                    }
14876                } else {
14877                    continue;
14878                }
14879            }
14880
14881            drop(snapshot);
14882            this.buffer.update(cx, |buffer, cx| {
14883                buffer.edit(edits, None, cx);
14884            });
14885
14886            // Adjust selections so that they end before any comment suffixes that
14887            // were inserted.
14888            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14889            let mut selections = this.selections.all::<Point>(cx);
14890            let snapshot = this.buffer.read(cx).read(cx);
14891            for selection in &mut selections {
14892                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14893                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14894                        Ordering::Less => {
14895                            suffixes_inserted.next();
14896                            continue;
14897                        }
14898                        Ordering::Greater => break,
14899                        Ordering::Equal => {
14900                            if selection.end.column == snapshot.line_len(row) {
14901                                if selection.is_empty() {
14902                                    selection.start.column -= suffix_len as u32;
14903                                }
14904                                selection.end.column -= suffix_len as u32;
14905                            }
14906                            break;
14907                        }
14908                    }
14909                }
14910            }
14911
14912            drop(snapshot);
14913            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14914
14915            let selections = this.selections.all::<Point>(cx);
14916            let selections_on_single_row = selections.windows(2).all(|selections| {
14917                selections[0].start.row == selections[1].start.row
14918                    && selections[0].end.row == selections[1].end.row
14919                    && selections[0].start.row == selections[0].end.row
14920            });
14921            let selections_selecting = selections
14922                .iter()
14923                .any(|selection| selection.start != selection.end);
14924            let advance_downwards = action.advance_downwards
14925                && selections_on_single_row
14926                && !selections_selecting
14927                && !matches!(this.mode, EditorMode::SingleLine);
14928
14929            if advance_downwards {
14930                let snapshot = this.buffer.read(cx).snapshot(cx);
14931
14932                this.change_selections(Default::default(), window, cx, |s| {
14933                    s.move_cursors_with(|display_snapshot, display_point, _| {
14934                        let mut point = display_point.to_point(display_snapshot);
14935                        point.row += 1;
14936                        point = snapshot.clip_point(point, Bias::Left);
14937                        let display_point = point.to_display_point(display_snapshot);
14938                        let goal = SelectionGoal::HorizontalPosition(
14939                            display_snapshot
14940                                .x_for_display_point(display_point, text_layout_details)
14941                                .into(),
14942                        );
14943                        (display_point, goal)
14944                    })
14945                });
14946            }
14947        });
14948    }
14949
14950    pub fn select_enclosing_symbol(
14951        &mut self,
14952        _: &SelectEnclosingSymbol,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957
14958        let buffer = self.buffer.read(cx).snapshot(cx);
14959        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14960
14961        fn update_selection(
14962            selection: &Selection<usize>,
14963            buffer_snap: &MultiBufferSnapshot,
14964        ) -> Option<Selection<usize>> {
14965            let cursor = selection.head();
14966            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14967            for symbol in symbols.iter().rev() {
14968                let start = symbol.range.start.to_offset(buffer_snap);
14969                let end = symbol.range.end.to_offset(buffer_snap);
14970                let new_range = start..end;
14971                if start < selection.start || end > selection.end {
14972                    return Some(Selection {
14973                        id: selection.id,
14974                        start: new_range.start,
14975                        end: new_range.end,
14976                        goal: SelectionGoal::None,
14977                        reversed: selection.reversed,
14978                    });
14979                }
14980            }
14981            None
14982        }
14983
14984        let mut selected_larger_symbol = false;
14985        let new_selections = old_selections
14986            .iter()
14987            .map(|selection| match update_selection(selection, &buffer) {
14988                Some(new_selection) => {
14989                    if new_selection.range() != selection.range() {
14990                        selected_larger_symbol = true;
14991                    }
14992                    new_selection
14993                }
14994                None => selection.clone(),
14995            })
14996            .collect::<Vec<_>>();
14997
14998        if selected_larger_symbol {
14999            self.change_selections(Default::default(), window, cx, |s| {
15000                s.select(new_selections);
15001            });
15002        }
15003    }
15004
15005    pub fn select_larger_syntax_node(
15006        &mut self,
15007        _: &SelectLargerSyntaxNode,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) {
15011        let Some(visible_row_count) = self.visible_row_count() else {
15012            return;
15013        };
15014        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15015        if old_selections.is_empty() {
15016            return;
15017        }
15018
15019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15020
15021        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15022        let buffer = self.buffer.read(cx).snapshot(cx);
15023
15024        let mut selected_larger_node = false;
15025        let mut new_selections = old_selections
15026            .iter()
15027            .map(|selection| {
15028                let old_range = selection.start..selection.end;
15029
15030                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15031                    // manually select word at selection
15032                    if ["string_content", "inline"].contains(&node.kind()) {
15033                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15034                        // ignore if word is already selected
15035                        if !word_range.is_empty() && old_range != word_range {
15036                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15037                            // only select word if start and end point belongs to same word
15038                            if word_range == last_word_range {
15039                                selected_larger_node = true;
15040                                return Selection {
15041                                    id: selection.id,
15042                                    start: word_range.start,
15043                                    end: word_range.end,
15044                                    goal: SelectionGoal::None,
15045                                    reversed: selection.reversed,
15046                                };
15047                            }
15048                        }
15049                    }
15050                }
15051
15052                let mut new_range = old_range.clone();
15053                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15054                {
15055                    new_range = match containing_range {
15056                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15057                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15058                    };
15059                    if !node.is_named() {
15060                        continue;
15061                    }
15062                    if !display_map.intersects_fold(new_range.start)
15063                        && !display_map.intersects_fold(new_range.end)
15064                    {
15065                        break;
15066                    }
15067                }
15068
15069                selected_larger_node |= new_range != old_range;
15070                Selection {
15071                    id: selection.id,
15072                    start: new_range.start,
15073                    end: new_range.end,
15074                    goal: SelectionGoal::None,
15075                    reversed: selection.reversed,
15076                }
15077            })
15078            .collect::<Vec<_>>();
15079
15080        if !selected_larger_node {
15081            return; // don't put this call in the history
15082        }
15083
15084        // scroll based on transformation done to the last selection created by the user
15085        let (last_old, last_new) = old_selections
15086            .last()
15087            .zip(new_selections.last().cloned())
15088            .expect("old_selections isn't empty");
15089
15090        // revert selection
15091        let is_selection_reversed = {
15092            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15093            new_selections.last_mut().expect("checked above").reversed =
15094                should_newest_selection_be_reversed;
15095            should_newest_selection_be_reversed
15096        };
15097
15098        if selected_larger_node {
15099            self.select_syntax_node_history.disable_clearing = true;
15100            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15101                s.select(new_selections.clone());
15102            });
15103            self.select_syntax_node_history.disable_clearing = false;
15104        }
15105
15106        let start_row = last_new.start.to_display_point(&display_map).row().0;
15107        let end_row = last_new.end.to_display_point(&display_map).row().0;
15108        let selection_height = end_row - start_row + 1;
15109        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15110
15111        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15112        let scroll_behavior = if fits_on_the_screen {
15113            self.request_autoscroll(Autoscroll::fit(), cx);
15114            SelectSyntaxNodeScrollBehavior::FitSelection
15115        } else if is_selection_reversed {
15116            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15117            SelectSyntaxNodeScrollBehavior::CursorTop
15118        } else {
15119            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15120            SelectSyntaxNodeScrollBehavior::CursorBottom
15121        };
15122
15123        self.select_syntax_node_history.push((
15124            old_selections,
15125            scroll_behavior,
15126            is_selection_reversed,
15127        ));
15128    }
15129
15130    pub fn select_smaller_syntax_node(
15131        &mut self,
15132        _: &SelectSmallerSyntaxNode,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15137
15138        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15139            self.select_syntax_node_history.pop()
15140        {
15141            if let Some(selection) = selections.last_mut() {
15142                selection.reversed = is_selection_reversed;
15143            }
15144
15145            self.select_syntax_node_history.disable_clearing = true;
15146            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15147                s.select(selections.to_vec());
15148            });
15149            self.select_syntax_node_history.disable_clearing = false;
15150
15151            match scroll_behavior {
15152                SelectSyntaxNodeScrollBehavior::CursorTop => {
15153                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15154                }
15155                SelectSyntaxNodeScrollBehavior::FitSelection => {
15156                    self.request_autoscroll(Autoscroll::fit(), cx);
15157                }
15158                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15159                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15160                }
15161            }
15162        }
15163    }
15164
15165    pub fn unwrap_syntax_node(
15166        &mut self,
15167        _: &UnwrapSyntaxNode,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) {
15171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15172
15173        let buffer = self.buffer.read(cx).snapshot(cx);
15174        let selections = self
15175            .selections
15176            .all::<usize>(cx)
15177            .into_iter()
15178            // subtracting the offset requires sorting
15179            .sorted_by_key(|i| i.start);
15180
15181        let full_edits = selections
15182            .into_iter()
15183            .filter_map(|selection| {
15184                let child = if selection.is_empty()
15185                    && let Some((_, ancestor_range)) =
15186                        buffer.syntax_ancestor(selection.start..selection.end)
15187                {
15188                    match ancestor_range {
15189                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15190                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15191                    }
15192                } else {
15193                    selection.range()
15194                };
15195
15196                let mut parent = child.clone();
15197                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15198                    parent = match ancestor_range {
15199                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15200                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15201                    };
15202                    if parent.start < child.start || parent.end > child.end {
15203                        break;
15204                    }
15205                }
15206
15207                if parent == child {
15208                    return None;
15209                }
15210                let text = buffer.text_for_range(child).collect::<String>();
15211                Some((selection.id, parent, text))
15212            })
15213            .collect::<Vec<_>>();
15214        if full_edits.is_empty() {
15215            return;
15216        }
15217
15218        self.transact(window, cx, |this, window, cx| {
15219            this.buffer.update(cx, |buffer, cx| {
15220                buffer.edit(
15221                    full_edits
15222                        .iter()
15223                        .map(|(_, p, t)| (p.clone(), t.clone()))
15224                        .collect::<Vec<_>>(),
15225                    None,
15226                    cx,
15227                );
15228            });
15229            this.change_selections(Default::default(), window, cx, |s| {
15230                let mut offset = 0;
15231                let mut selections = vec![];
15232                for (id, parent, text) in full_edits {
15233                    let start = parent.start - offset;
15234                    offset += parent.len() - text.len();
15235                    selections.push(Selection {
15236                        id,
15237                        start,
15238                        end: start + text.len(),
15239                        reversed: false,
15240                        goal: Default::default(),
15241                    });
15242                }
15243                s.select(selections);
15244            });
15245        });
15246    }
15247
15248    pub fn select_next_syntax_node(
15249        &mut self,
15250        _: &SelectNextSyntaxNode,
15251        window: &mut Window,
15252        cx: &mut Context<Self>,
15253    ) {
15254        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15255        if old_selections.is_empty() {
15256            return;
15257        }
15258
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262        let mut selected_sibling = false;
15263
15264        let new_selections = old_selections
15265            .iter()
15266            .map(|selection| {
15267                let old_range = selection.start..selection.end;
15268
15269                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15270                    let new_range = node.byte_range();
15271                    selected_sibling = true;
15272                    Selection {
15273                        id: selection.id,
15274                        start: new_range.start,
15275                        end: new_range.end,
15276                        goal: SelectionGoal::None,
15277                        reversed: selection.reversed,
15278                    }
15279                } else {
15280                    selection.clone()
15281                }
15282            })
15283            .collect::<Vec<_>>();
15284
15285        if selected_sibling {
15286            self.change_selections(
15287                SelectionEffects::scroll(Autoscroll::fit()),
15288                window,
15289                cx,
15290                |s| {
15291                    s.select(new_selections);
15292                },
15293            );
15294        }
15295    }
15296
15297    pub fn select_prev_syntax_node(
15298        &mut self,
15299        _: &SelectPreviousSyntaxNode,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15304        if old_selections.is_empty() {
15305            return;
15306        }
15307
15308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15309
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311        let mut selected_sibling = false;
15312
15313        let new_selections = old_selections
15314            .iter()
15315            .map(|selection| {
15316                let old_range = selection.start..selection.end;
15317
15318                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15319                    let new_range = node.byte_range();
15320                    selected_sibling = true;
15321                    Selection {
15322                        id: selection.id,
15323                        start: new_range.start,
15324                        end: new_range.end,
15325                        goal: SelectionGoal::None,
15326                        reversed: selection.reversed,
15327                    }
15328                } else {
15329                    selection.clone()
15330                }
15331            })
15332            .collect::<Vec<_>>();
15333
15334        if selected_sibling {
15335            self.change_selections(
15336                SelectionEffects::scroll(Autoscroll::fit()),
15337                window,
15338                cx,
15339                |s| {
15340                    s.select(new_selections);
15341                },
15342            );
15343        }
15344    }
15345
15346    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15347        if !EditorSettings::get_global(cx).gutter.runnables {
15348            self.clear_tasks();
15349            return Task::ready(());
15350        }
15351        let project = self.project().map(Entity::downgrade);
15352        let task_sources = self.lsp_task_sources(cx);
15353        let multi_buffer = self.buffer.downgrade();
15354        cx.spawn_in(window, async move |editor, cx| {
15355            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15356            let Some(project) = project.and_then(|p| p.upgrade()) else {
15357                return;
15358            };
15359            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15360                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15361            }) else {
15362                return;
15363            };
15364
15365            let hide_runnables = project
15366                .update(cx, |project, _| project.is_via_collab())
15367                .unwrap_or(true);
15368            if hide_runnables {
15369                return;
15370            }
15371            let new_rows =
15372                cx.background_spawn({
15373                    let snapshot = display_snapshot.clone();
15374                    async move {
15375                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15376                    }
15377                })
15378                    .await;
15379            let Ok(lsp_tasks) =
15380                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15381            else {
15382                return;
15383            };
15384            let lsp_tasks = lsp_tasks.await;
15385
15386            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15387                lsp_tasks
15388                    .into_iter()
15389                    .flat_map(|(kind, tasks)| {
15390                        tasks.into_iter().filter_map(move |(location, task)| {
15391                            Some((kind.clone(), location?, task))
15392                        })
15393                    })
15394                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15395                        let buffer = location.target.buffer;
15396                        let buffer_snapshot = buffer.read(cx).snapshot();
15397                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15398                            |(excerpt_id, snapshot, _)| {
15399                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15400                                    display_snapshot
15401                                        .buffer_snapshot
15402                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15403                                } else {
15404                                    None
15405                                }
15406                            },
15407                        );
15408                        if let Some(offset) = offset {
15409                            let task_buffer_range =
15410                                location.target.range.to_point(&buffer_snapshot);
15411                            let context_buffer_range =
15412                                task_buffer_range.to_offset(&buffer_snapshot);
15413                            let context_range = BufferOffset(context_buffer_range.start)
15414                                ..BufferOffset(context_buffer_range.end);
15415
15416                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15417                                .or_insert_with(|| RunnableTasks {
15418                                    templates: Vec::new(),
15419                                    offset,
15420                                    column: task_buffer_range.start.column,
15421                                    extra_variables: HashMap::default(),
15422                                    context_range,
15423                                })
15424                                .templates
15425                                .push((kind, task.original_task().clone()));
15426                        }
15427
15428                        acc
15429                    })
15430            }) else {
15431                return;
15432            };
15433
15434            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15435                buffer.language_settings(cx).tasks.prefer_lsp
15436            }) else {
15437                return;
15438            };
15439
15440            let rows = Self::runnable_rows(
15441                project,
15442                display_snapshot,
15443                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15444                new_rows,
15445                cx.clone(),
15446            )
15447            .await;
15448            editor
15449                .update(cx, |editor, _| {
15450                    editor.clear_tasks();
15451                    for (key, mut value) in rows {
15452                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15453                            value.templates.extend(lsp_tasks.templates);
15454                        }
15455
15456                        editor.insert_tasks(key, value);
15457                    }
15458                    for (key, value) in lsp_tasks_by_rows {
15459                        editor.insert_tasks(key, value);
15460                    }
15461                })
15462                .ok();
15463        })
15464    }
15465    fn fetch_runnable_ranges(
15466        snapshot: &DisplaySnapshot,
15467        range: Range<Anchor>,
15468    ) -> Vec<language::RunnableRange> {
15469        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15470    }
15471
15472    fn runnable_rows(
15473        project: Entity<Project>,
15474        snapshot: DisplaySnapshot,
15475        prefer_lsp: bool,
15476        runnable_ranges: Vec<RunnableRange>,
15477        cx: AsyncWindowContext,
15478    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15479        cx.spawn(async move |cx| {
15480            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15481            for mut runnable in runnable_ranges {
15482                let Some(tasks) = cx
15483                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15484                    .ok()
15485                else {
15486                    continue;
15487                };
15488                let mut tasks = tasks.await;
15489
15490                if prefer_lsp {
15491                    tasks.retain(|(task_kind, _)| {
15492                        !matches!(task_kind, TaskSourceKind::Language { .. })
15493                    });
15494                }
15495                if tasks.is_empty() {
15496                    continue;
15497                }
15498
15499                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15500                let Some(row) = snapshot
15501                    .buffer_snapshot
15502                    .buffer_line_for_row(MultiBufferRow(point.row))
15503                    .map(|(_, range)| range.start.row)
15504                else {
15505                    continue;
15506                };
15507
15508                let context_range =
15509                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15510                runnable_rows.push((
15511                    (runnable.buffer_id, row),
15512                    RunnableTasks {
15513                        templates: tasks,
15514                        offset: snapshot
15515                            .buffer_snapshot
15516                            .anchor_before(runnable.run_range.start),
15517                        context_range,
15518                        column: point.column,
15519                        extra_variables: runnable.extra_captures,
15520                    },
15521                ));
15522            }
15523            runnable_rows
15524        })
15525    }
15526
15527    fn templates_with_tags(
15528        project: &Entity<Project>,
15529        runnable: &mut Runnable,
15530        cx: &mut App,
15531    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15532        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15533            let (worktree_id, file) = project
15534                .buffer_for_id(runnable.buffer, cx)
15535                .and_then(|buffer| buffer.read(cx).file())
15536                .map(|file| (file.worktree_id(cx), file.clone()))
15537                .unzip();
15538
15539            (
15540                project.task_store().read(cx).task_inventory().cloned(),
15541                worktree_id,
15542                file,
15543            )
15544        });
15545
15546        let tags = mem::take(&mut runnable.tags);
15547        let language = runnable.language.clone();
15548        cx.spawn(async move |cx| {
15549            let mut templates_with_tags = Vec::new();
15550            if let Some(inventory) = inventory {
15551                for RunnableTag(tag) in tags {
15552                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15553                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15554                    }) else {
15555                        return templates_with_tags;
15556                    };
15557                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15558                        move |(_, template)| {
15559                            template.tags.iter().any(|source_tag| source_tag == &tag)
15560                        },
15561                    ));
15562                }
15563            }
15564            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15565
15566            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15567                // Strongest source wins; if we have worktree tag binding, prefer that to
15568                // global and language bindings;
15569                // if we have a global binding, prefer that to language binding.
15570                let first_mismatch = templates_with_tags
15571                    .iter()
15572                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15573                if let Some(index) = first_mismatch {
15574                    templates_with_tags.truncate(index);
15575                }
15576            }
15577
15578            templates_with_tags
15579        })
15580    }
15581
15582    pub fn move_to_enclosing_bracket(
15583        &mut self,
15584        _: &MoveToEnclosingBracket,
15585        window: &mut Window,
15586        cx: &mut Context<Self>,
15587    ) {
15588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15589        self.change_selections(Default::default(), window, cx, |s| {
15590            s.move_offsets_with(|snapshot, selection| {
15591                let Some(enclosing_bracket_ranges) =
15592                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15593                else {
15594                    return;
15595                };
15596
15597                let mut best_length = usize::MAX;
15598                let mut best_inside = false;
15599                let mut best_in_bracket_range = false;
15600                let mut best_destination = None;
15601                for (open, close) in enclosing_bracket_ranges {
15602                    let close = close.to_inclusive();
15603                    let length = close.end() - open.start;
15604                    let inside = selection.start >= open.end && selection.end <= *close.start();
15605                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15606                        || close.contains(&selection.head());
15607
15608                    // If best is next to a bracket and current isn't, skip
15609                    if !in_bracket_range && best_in_bracket_range {
15610                        continue;
15611                    }
15612
15613                    // Prefer smaller lengths unless best is inside and current isn't
15614                    if length > best_length && (best_inside || !inside) {
15615                        continue;
15616                    }
15617
15618                    best_length = length;
15619                    best_inside = inside;
15620                    best_in_bracket_range = in_bracket_range;
15621                    best_destination = Some(
15622                        if close.contains(&selection.start) && close.contains(&selection.end) {
15623                            if inside { open.end } else { open.start }
15624                        } else if inside {
15625                            *close.start()
15626                        } else {
15627                            *close.end()
15628                        },
15629                    );
15630                }
15631
15632                if let Some(destination) = best_destination {
15633                    selection.collapse_to(destination, SelectionGoal::None);
15634                }
15635            })
15636        });
15637    }
15638
15639    pub fn undo_selection(
15640        &mut self,
15641        _: &UndoSelection,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15646        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15647            self.selection_history.mode = SelectionHistoryMode::Undoing;
15648            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15649                this.end_selection(window, cx);
15650                this.change_selections(
15651                    SelectionEffects::scroll(Autoscroll::newest()),
15652                    window,
15653                    cx,
15654                    |s| s.select_anchors(entry.selections.to_vec()),
15655                );
15656            });
15657            self.selection_history.mode = SelectionHistoryMode::Normal;
15658
15659            self.select_next_state = entry.select_next_state;
15660            self.select_prev_state = entry.select_prev_state;
15661            self.add_selections_state = entry.add_selections_state;
15662        }
15663    }
15664
15665    pub fn redo_selection(
15666        &mut self,
15667        _: &RedoSelection,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) {
15671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15672        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15673            self.selection_history.mode = SelectionHistoryMode::Redoing;
15674            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15675                this.end_selection(window, cx);
15676                this.change_selections(
15677                    SelectionEffects::scroll(Autoscroll::newest()),
15678                    window,
15679                    cx,
15680                    |s| s.select_anchors(entry.selections.to_vec()),
15681                );
15682            });
15683            self.selection_history.mode = SelectionHistoryMode::Normal;
15684
15685            self.select_next_state = entry.select_next_state;
15686            self.select_prev_state = entry.select_prev_state;
15687            self.add_selections_state = entry.add_selections_state;
15688        }
15689    }
15690
15691    pub fn expand_excerpts(
15692        &mut self,
15693        action: &ExpandExcerpts,
15694        _: &mut Window,
15695        cx: &mut Context<Self>,
15696    ) {
15697        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15698    }
15699
15700    pub fn expand_excerpts_down(
15701        &mut self,
15702        action: &ExpandExcerptsDown,
15703        _: &mut Window,
15704        cx: &mut Context<Self>,
15705    ) {
15706        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15707    }
15708
15709    pub fn expand_excerpts_up(
15710        &mut self,
15711        action: &ExpandExcerptsUp,
15712        _: &mut Window,
15713        cx: &mut Context<Self>,
15714    ) {
15715        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15716    }
15717
15718    pub fn expand_excerpts_for_direction(
15719        &mut self,
15720        lines: u32,
15721        direction: ExpandExcerptDirection,
15722
15723        cx: &mut Context<Self>,
15724    ) {
15725        let selections = self.selections.disjoint_anchors_arc();
15726
15727        let lines = if lines == 0 {
15728            EditorSettings::get_global(cx).expand_excerpt_lines
15729        } else {
15730            lines
15731        };
15732
15733        self.buffer.update(cx, |buffer, cx| {
15734            let snapshot = buffer.snapshot(cx);
15735            let mut excerpt_ids = selections
15736                .iter()
15737                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15738                .collect::<Vec<_>>();
15739            excerpt_ids.sort();
15740            excerpt_ids.dedup();
15741            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15742        })
15743    }
15744
15745    pub fn expand_excerpt(
15746        &mut self,
15747        excerpt: ExcerptId,
15748        direction: ExpandExcerptDirection,
15749        window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        let current_scroll_position = self.scroll_position(cx);
15753        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15754        let mut should_scroll_up = false;
15755
15756        if direction == ExpandExcerptDirection::Down {
15757            let multi_buffer = self.buffer.read(cx);
15758            let snapshot = multi_buffer.snapshot(cx);
15759            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15760                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15761                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15762            {
15763                let buffer_snapshot = buffer.read(cx).snapshot();
15764                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15765                let last_row = buffer_snapshot.max_point().row;
15766                let lines_below = last_row.saturating_sub(excerpt_end_row);
15767                should_scroll_up = lines_below >= lines_to_expand;
15768            }
15769        }
15770
15771        self.buffer.update(cx, |buffer, cx| {
15772            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15773        });
15774
15775        if should_scroll_up {
15776            let new_scroll_position =
15777                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15778            self.set_scroll_position(new_scroll_position, window, cx);
15779        }
15780    }
15781
15782    pub fn go_to_singleton_buffer_point(
15783        &mut self,
15784        point: Point,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        self.go_to_singleton_buffer_range(point..point, window, cx);
15789    }
15790
15791    pub fn go_to_singleton_buffer_range(
15792        &mut self,
15793        range: Range<Point>,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        let multibuffer = self.buffer().read(cx);
15798        let Some(buffer) = multibuffer.as_singleton() else {
15799            return;
15800        };
15801        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15802            return;
15803        };
15804        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15805            return;
15806        };
15807        self.change_selections(
15808            SelectionEffects::default().nav_history(true),
15809            window,
15810            cx,
15811            |s| s.select_anchor_ranges([start..end]),
15812        );
15813    }
15814
15815    pub fn go_to_diagnostic(
15816        &mut self,
15817        action: &GoToDiagnostic,
15818        window: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        if !self.diagnostics_enabled() {
15822            return;
15823        }
15824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15825        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15826    }
15827
15828    pub fn go_to_prev_diagnostic(
15829        &mut self,
15830        action: &GoToPreviousDiagnostic,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        if !self.diagnostics_enabled() {
15835            return;
15836        }
15837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15838        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15839    }
15840
15841    pub fn go_to_diagnostic_impl(
15842        &mut self,
15843        direction: Direction,
15844        severity: GoToDiagnosticSeverityFilter,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        let buffer = self.buffer.read(cx).snapshot(cx);
15849        let selection = self.selections.newest::<usize>(cx);
15850
15851        let mut active_group_id = None;
15852        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15853            && active_group.active_range.start.to_offset(&buffer) == selection.start
15854        {
15855            active_group_id = Some(active_group.group_id);
15856        }
15857
15858        fn filtered(
15859            snapshot: EditorSnapshot,
15860            severity: GoToDiagnosticSeverityFilter,
15861            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15862        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15863            diagnostics
15864                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15865                .filter(|entry| entry.range.start != entry.range.end)
15866                .filter(|entry| !entry.diagnostic.is_unnecessary)
15867                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15868        }
15869
15870        let snapshot = self.snapshot(window, cx);
15871        let before = filtered(
15872            snapshot.clone(),
15873            severity,
15874            buffer
15875                .diagnostics_in_range(0..selection.start)
15876                .filter(|entry| entry.range.start <= selection.start),
15877        );
15878        let after = filtered(
15879            snapshot,
15880            severity,
15881            buffer
15882                .diagnostics_in_range(selection.start..buffer.len())
15883                .filter(|entry| entry.range.start >= selection.start),
15884        );
15885
15886        let mut found: Option<DiagnosticEntry<usize>> = None;
15887        if direction == Direction::Prev {
15888            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15889            {
15890                for diagnostic in prev_diagnostics.into_iter().rev() {
15891                    if diagnostic.range.start != selection.start
15892                        || active_group_id
15893                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15894                    {
15895                        found = Some(diagnostic);
15896                        break 'outer;
15897                    }
15898                }
15899            }
15900        } else {
15901            for diagnostic in after.chain(before) {
15902                if diagnostic.range.start != selection.start
15903                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15904                {
15905                    found = Some(diagnostic);
15906                    break;
15907                }
15908            }
15909        }
15910        let Some(next_diagnostic) = found else {
15911            return;
15912        };
15913
15914        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15915        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15916            return;
15917        };
15918        self.change_selections(Default::default(), window, cx, |s| {
15919            s.select_ranges(vec![
15920                next_diagnostic.range.start..next_diagnostic.range.start,
15921            ])
15922        });
15923        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15924        self.refresh_edit_prediction(false, true, window, cx);
15925    }
15926
15927    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        let snapshot = self.snapshot(window, cx);
15930        let selection = self.selections.newest::<Point>(cx);
15931        self.go_to_hunk_before_or_after_position(
15932            &snapshot,
15933            selection.head(),
15934            Direction::Next,
15935            window,
15936            cx,
15937        );
15938    }
15939
15940    pub fn go_to_hunk_before_or_after_position(
15941        &mut self,
15942        snapshot: &EditorSnapshot,
15943        position: Point,
15944        direction: Direction,
15945        window: &mut Window,
15946        cx: &mut Context<Editor>,
15947    ) {
15948        let row = if direction == Direction::Next {
15949            self.hunk_after_position(snapshot, position)
15950                .map(|hunk| hunk.row_range.start)
15951        } else {
15952            self.hunk_before_position(snapshot, position)
15953        };
15954
15955        if let Some(row) = row {
15956            let destination = Point::new(row.0, 0);
15957            let autoscroll = Autoscroll::center();
15958
15959            self.unfold_ranges(&[destination..destination], false, false, cx);
15960            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15961                s.select_ranges([destination..destination]);
15962            });
15963        }
15964    }
15965
15966    fn hunk_after_position(
15967        &mut self,
15968        snapshot: &EditorSnapshot,
15969        position: Point,
15970    ) -> Option<MultiBufferDiffHunk> {
15971        snapshot
15972            .buffer_snapshot
15973            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15974            .find(|hunk| hunk.row_range.start.0 > position.row)
15975            .or_else(|| {
15976                snapshot
15977                    .buffer_snapshot
15978                    .diff_hunks_in_range(Point::zero()..position)
15979                    .find(|hunk| hunk.row_range.end.0 < position.row)
15980            })
15981    }
15982
15983    fn go_to_prev_hunk(
15984        &mut self,
15985        _: &GoToPreviousHunk,
15986        window: &mut Window,
15987        cx: &mut Context<Self>,
15988    ) {
15989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15990        let snapshot = self.snapshot(window, cx);
15991        let selection = self.selections.newest::<Point>(cx);
15992        self.go_to_hunk_before_or_after_position(
15993            &snapshot,
15994            selection.head(),
15995            Direction::Prev,
15996            window,
15997            cx,
15998        );
15999    }
16000
16001    fn hunk_before_position(
16002        &mut self,
16003        snapshot: &EditorSnapshot,
16004        position: Point,
16005    ) -> Option<MultiBufferRow> {
16006        snapshot
16007            .buffer_snapshot
16008            .diff_hunk_before(position)
16009            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16010    }
16011
16012    fn go_to_next_change(
16013        &mut self,
16014        _: &GoToNextChange,
16015        window: &mut Window,
16016        cx: &mut Context<Self>,
16017    ) {
16018        if let Some(selections) = self
16019            .change_list
16020            .next_change(1, Direction::Next)
16021            .map(|s| s.to_vec())
16022        {
16023            self.change_selections(Default::default(), window, cx, |s| {
16024                let map = s.display_map();
16025                s.select_display_ranges(selections.iter().map(|a| {
16026                    let point = a.to_display_point(&map);
16027                    point..point
16028                }))
16029            })
16030        }
16031    }
16032
16033    fn go_to_previous_change(
16034        &mut self,
16035        _: &GoToPreviousChange,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        if let Some(selections) = self
16040            .change_list
16041            .next_change(1, Direction::Prev)
16042            .map(|s| s.to_vec())
16043        {
16044            self.change_selections(Default::default(), window, cx, |s| {
16045                let map = s.display_map();
16046                s.select_display_ranges(selections.iter().map(|a| {
16047                    let point = a.to_display_point(&map);
16048                    point..point
16049                }))
16050            })
16051        }
16052    }
16053
16054    pub fn go_to_next_document_highlight(
16055        &mut self,
16056        _: &GoToNextDocumentHighlight,
16057        window: &mut Window,
16058        cx: &mut Context<Self>,
16059    ) {
16060        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16061    }
16062
16063    pub fn go_to_prev_document_highlight(
16064        &mut self,
16065        _: &GoToPreviousDocumentHighlight,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) {
16069        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16070    }
16071
16072    pub fn go_to_document_highlight_before_or_after_position(
16073        &mut self,
16074        direction: Direction,
16075        window: &mut Window,
16076        cx: &mut Context<Editor>,
16077    ) {
16078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16079        let snapshot = self.snapshot(window, cx);
16080        let buffer = &snapshot.buffer_snapshot;
16081        let position = self.selections.newest::<Point>(cx).head();
16082        let anchor_position = buffer.anchor_after(position);
16083
16084        // Get all document highlights (both read and write)
16085        let mut all_highlights = Vec::new();
16086
16087        if let Some((_, read_highlights)) = self
16088            .background_highlights
16089            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16090        {
16091            all_highlights.extend(read_highlights.iter());
16092        }
16093
16094        if let Some((_, write_highlights)) = self
16095            .background_highlights
16096            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16097        {
16098            all_highlights.extend(write_highlights.iter());
16099        }
16100
16101        if all_highlights.is_empty() {
16102            return;
16103        }
16104
16105        // Sort highlights by position
16106        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16107
16108        let target_highlight = match direction {
16109            Direction::Next => {
16110                // Find the first highlight after the current position
16111                all_highlights
16112                    .iter()
16113                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16114            }
16115            Direction::Prev => {
16116                // Find the last highlight before the current position
16117                all_highlights
16118                    .iter()
16119                    .rev()
16120                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16121            }
16122        };
16123
16124        if let Some(highlight) = target_highlight {
16125            let destination = highlight.start.to_point(buffer);
16126            let autoscroll = Autoscroll::center();
16127
16128            self.unfold_ranges(&[destination..destination], false, false, cx);
16129            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16130                s.select_ranges([destination..destination]);
16131            });
16132        }
16133    }
16134
16135    fn go_to_line<T: 'static>(
16136        &mut self,
16137        position: Anchor,
16138        highlight_color: Option<Hsla>,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        let snapshot = self.snapshot(window, cx).display_snapshot;
16143        let position = position.to_point(&snapshot.buffer_snapshot);
16144        let start = snapshot
16145            .buffer_snapshot
16146            .clip_point(Point::new(position.row, 0), Bias::Left);
16147        let end = start + Point::new(1, 0);
16148        let start = snapshot.buffer_snapshot.anchor_before(start);
16149        let end = snapshot.buffer_snapshot.anchor_before(end);
16150
16151        self.highlight_rows::<T>(
16152            start..end,
16153            highlight_color
16154                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16155            Default::default(),
16156            cx,
16157        );
16158
16159        if self.buffer.read(cx).is_singleton() {
16160            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16161        }
16162    }
16163
16164    pub fn go_to_definition(
16165        &mut self,
16166        _: &GoToDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        let definition =
16171            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16172        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16173        cx.spawn_in(window, async move |editor, cx| {
16174            if definition.await? == Navigated::Yes {
16175                return Ok(Navigated::Yes);
16176            }
16177            match fallback_strategy {
16178                GoToDefinitionFallback::None => Ok(Navigated::No),
16179                GoToDefinitionFallback::FindAllReferences => {
16180                    match editor.update_in(cx, |editor, window, cx| {
16181                        editor.find_all_references(&FindAllReferences, window, cx)
16182                    })? {
16183                        Some(references) => references.await,
16184                        None => Ok(Navigated::No),
16185                    }
16186                }
16187            }
16188        })
16189    }
16190
16191    pub fn go_to_declaration(
16192        &mut self,
16193        _: &GoToDeclaration,
16194        window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) -> Task<Result<Navigated>> {
16197        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16198    }
16199
16200    pub fn go_to_declaration_split(
16201        &mut self,
16202        _: &GoToDeclaration,
16203        window: &mut Window,
16204        cx: &mut Context<Self>,
16205    ) -> Task<Result<Navigated>> {
16206        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16207    }
16208
16209    pub fn go_to_implementation(
16210        &mut self,
16211        _: &GoToImplementation,
16212        window: &mut Window,
16213        cx: &mut Context<Self>,
16214    ) -> Task<Result<Navigated>> {
16215        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16216    }
16217
16218    pub fn go_to_implementation_split(
16219        &mut self,
16220        _: &GoToImplementationSplit,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) -> Task<Result<Navigated>> {
16224        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16225    }
16226
16227    pub fn go_to_type_definition(
16228        &mut self,
16229        _: &GoToTypeDefinition,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) -> Task<Result<Navigated>> {
16233        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16234    }
16235
16236    pub fn go_to_definition_split(
16237        &mut self,
16238        _: &GoToDefinitionSplit,
16239        window: &mut Window,
16240        cx: &mut Context<Self>,
16241    ) -> Task<Result<Navigated>> {
16242        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16243    }
16244
16245    pub fn go_to_type_definition_split(
16246        &mut self,
16247        _: &GoToTypeDefinitionSplit,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) -> Task<Result<Navigated>> {
16251        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16252    }
16253
16254    fn go_to_definition_of_kind(
16255        &mut self,
16256        kind: GotoDefinitionKind,
16257        split: bool,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Task<Result<Navigated>> {
16261        let Some(provider) = self.semantics_provider.clone() else {
16262            return Task::ready(Ok(Navigated::No));
16263        };
16264        let head = self.selections.newest::<usize>(cx).head();
16265        let buffer = self.buffer.read(cx);
16266        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16267            return Task::ready(Ok(Navigated::No));
16268        };
16269        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16270            return Task::ready(Ok(Navigated::No));
16271        };
16272
16273        cx.spawn_in(window, async move |editor, cx| {
16274            let Some(definitions) = definitions.await? else {
16275                return Ok(Navigated::No);
16276            };
16277            let navigated = editor
16278                .update_in(cx, |editor, window, cx| {
16279                    editor.navigate_to_hover_links(
16280                        Some(kind),
16281                        definitions
16282                            .into_iter()
16283                            .filter(|location| {
16284                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16285                            })
16286                            .map(HoverLink::Text)
16287                            .collect::<Vec<_>>(),
16288                        split,
16289                        window,
16290                        cx,
16291                    )
16292                })?
16293                .await?;
16294            anyhow::Ok(navigated)
16295        })
16296    }
16297
16298    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16299        let selection = self.selections.newest_anchor();
16300        let head = selection.head();
16301        let tail = selection.tail();
16302
16303        let Some((buffer, start_position)) =
16304            self.buffer.read(cx).text_anchor_for_position(head, cx)
16305        else {
16306            return;
16307        };
16308
16309        let end_position = if head != tail {
16310            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16311                return;
16312            };
16313            Some(pos)
16314        } else {
16315            None
16316        };
16317
16318        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16319            let url = if let Some(end_pos) = end_position {
16320                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16321            } else {
16322                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16323            };
16324
16325            if let Some(url) = url {
16326                editor.update(cx, |_, cx| {
16327                    cx.open_url(&url);
16328                })
16329            } else {
16330                Ok(())
16331            }
16332        });
16333
16334        url_finder.detach();
16335    }
16336
16337    pub fn open_selected_filename(
16338        &mut self,
16339        _: &OpenSelectedFilename,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) {
16343        let Some(workspace) = self.workspace() else {
16344            return;
16345        };
16346
16347        let position = self.selections.newest_anchor().head();
16348
16349        let Some((buffer, buffer_position)) =
16350            self.buffer.read(cx).text_anchor_for_position(position, cx)
16351        else {
16352            return;
16353        };
16354
16355        let project = self.project.clone();
16356
16357        cx.spawn_in(window, async move |_, cx| {
16358            let result = find_file(&buffer, project, buffer_position, cx).await;
16359
16360            if let Some((_, path)) = result {
16361                workspace
16362                    .update_in(cx, |workspace, window, cx| {
16363                        workspace.open_resolved_path(path, window, cx)
16364                    })?
16365                    .await?;
16366            }
16367            anyhow::Ok(())
16368        })
16369        .detach();
16370    }
16371
16372    pub(crate) fn navigate_to_hover_links(
16373        &mut self,
16374        kind: Option<GotoDefinitionKind>,
16375        definitions: Vec<HoverLink>,
16376        split: bool,
16377        window: &mut Window,
16378        cx: &mut Context<Editor>,
16379    ) -> Task<Result<Navigated>> {
16380        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16381        let mut first_url_or_file = None;
16382        let definitions: Vec<_> = definitions
16383            .into_iter()
16384            .filter_map(|def| match def {
16385                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16386                HoverLink::InlayHint(lsp_location, server_id) => {
16387                    let computation =
16388                        self.compute_target_location(lsp_location, server_id, window, cx);
16389                    Some(cx.background_spawn(computation))
16390                }
16391                HoverLink::Url(url) => {
16392                    first_url_or_file = Some(Either::Left(url));
16393                    None
16394                }
16395                HoverLink::File(path) => {
16396                    first_url_or_file = Some(Either::Right(path));
16397                    None
16398                }
16399            })
16400            .collect();
16401
16402        let workspace = self.workspace();
16403
16404        cx.spawn_in(window, async move |editor, cx| {
16405            let locations: Vec<Location> = future::join_all(definitions)
16406                .await
16407                .into_iter()
16408                .filter_map(|location| location.transpose())
16409                .collect::<Result<_>>()
16410                .context("location tasks")?;
16411            let mut locations = cx.update(|_, cx| {
16412                locations
16413                    .into_iter()
16414                    .map(|location| {
16415                        let buffer = location.buffer.read(cx);
16416                        (location.buffer, location.range.to_point(buffer))
16417                    })
16418                    .into_group_map()
16419            })?;
16420            let mut num_locations = 0;
16421            for ranges in locations.values_mut() {
16422                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16423                ranges.dedup();
16424                num_locations += ranges.len();
16425            }
16426
16427            if num_locations > 1 {
16428                let Some(workspace) = workspace else {
16429                    return Ok(Navigated::No);
16430                };
16431
16432                let tab_kind = match kind {
16433                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16434                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16435                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16436                    Some(GotoDefinitionKind::Type) => "Types",
16437                };
16438                let title = editor
16439                    .update_in(cx, |_, _, cx| {
16440                        let target = locations
16441                            .iter()
16442                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16443                            .map(|(buffer, location)| {
16444                                buffer
16445                                    .read(cx)
16446                                    .text_for_range(location.clone())
16447                                    .collect::<String>()
16448                            })
16449                            .filter(|text| !text.contains('\n'))
16450                            .unique()
16451                            .take(3)
16452                            .join(", ");
16453                        if target.is_empty() {
16454                            tab_kind.to_owned()
16455                        } else {
16456                            format!("{tab_kind} for {target}")
16457                        }
16458                    })
16459                    .context("buffer title")?;
16460
16461                let opened = workspace
16462                    .update_in(cx, |workspace, window, cx| {
16463                        Self::open_locations_in_multibuffer(
16464                            workspace,
16465                            locations,
16466                            title,
16467                            split,
16468                            MultibufferSelectionMode::First,
16469                            window,
16470                            cx,
16471                        )
16472                    })
16473                    .is_ok();
16474
16475                anyhow::Ok(Navigated::from_bool(opened))
16476            } else if num_locations == 0 {
16477                // If there is one url or file, open it directly
16478                match first_url_or_file {
16479                    Some(Either::Left(url)) => {
16480                        cx.update(|_, cx| cx.open_url(&url))?;
16481                        Ok(Navigated::Yes)
16482                    }
16483                    Some(Either::Right(path)) => {
16484                        let Some(workspace) = workspace else {
16485                            return Ok(Navigated::No);
16486                        };
16487
16488                        workspace
16489                            .update_in(cx, |workspace, window, cx| {
16490                                workspace.open_resolved_path(path, window, cx)
16491                            })?
16492                            .await?;
16493                        Ok(Navigated::Yes)
16494                    }
16495                    None => Ok(Navigated::No),
16496                }
16497            } else {
16498                let Some(workspace) = workspace else {
16499                    return Ok(Navigated::No);
16500                };
16501
16502                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16503                let target_range = target_ranges.first().unwrap().clone();
16504
16505                editor.update_in(cx, |editor, window, cx| {
16506                    let range = target_range.to_point(target_buffer.read(cx));
16507                    let range = editor.range_for_match(&range);
16508                    let range = collapse_multiline_range(range);
16509
16510                    if !split
16511                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16512                    {
16513                        editor.go_to_singleton_buffer_range(range, window, cx);
16514                    } else {
16515                        let pane = workspace.read(cx).active_pane().clone();
16516                        window.defer(cx, move |window, cx| {
16517                            let target_editor: Entity<Self> =
16518                                workspace.update(cx, |workspace, cx| {
16519                                    let pane = if split {
16520                                        workspace.adjacent_pane(window, cx)
16521                                    } else {
16522                                        workspace.active_pane().clone()
16523                                    };
16524
16525                                    workspace.open_project_item(
16526                                        pane,
16527                                        target_buffer.clone(),
16528                                        true,
16529                                        true,
16530                                        window,
16531                                        cx,
16532                                    )
16533                                });
16534                            target_editor.update(cx, |target_editor, cx| {
16535                                // When selecting a definition in a different buffer, disable the nav history
16536                                // to avoid creating a history entry at the previous cursor location.
16537                                pane.update(cx, |pane, _| pane.disable_history());
16538                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16539                                pane.update(cx, |pane, _| pane.enable_history());
16540                            });
16541                        });
16542                    }
16543                    Navigated::Yes
16544                })
16545            }
16546        })
16547    }
16548
16549    fn compute_target_location(
16550        &self,
16551        lsp_location: lsp::Location,
16552        server_id: LanguageServerId,
16553        window: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) -> Task<anyhow::Result<Option<Location>>> {
16556        let Some(project) = self.project.clone() else {
16557            return Task::ready(Ok(None));
16558        };
16559
16560        cx.spawn_in(window, async move |editor, cx| {
16561            let location_task = editor.update(cx, |_, cx| {
16562                project.update(cx, |project, cx| {
16563                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16564                })
16565            })?;
16566            let location = Some({
16567                let target_buffer_handle = location_task.await.context("open local buffer")?;
16568                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16569                    let target_start = target_buffer
16570                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16571                    let target_end = target_buffer
16572                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16573                    target_buffer.anchor_after(target_start)
16574                        ..target_buffer.anchor_before(target_end)
16575                })?;
16576                Location {
16577                    buffer: target_buffer_handle,
16578                    range,
16579                }
16580            });
16581            Ok(location)
16582        })
16583    }
16584
16585    pub fn find_all_references(
16586        &mut self,
16587        _: &FindAllReferences,
16588        window: &mut Window,
16589        cx: &mut Context<Self>,
16590    ) -> Option<Task<Result<Navigated>>> {
16591        let selection = self.selections.newest::<usize>(cx);
16592        let multi_buffer = self.buffer.read(cx);
16593        let head = selection.head();
16594
16595        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16596        let head_anchor = multi_buffer_snapshot.anchor_at(
16597            head,
16598            if head < selection.tail() {
16599                Bias::Right
16600            } else {
16601                Bias::Left
16602            },
16603        );
16604
16605        match self
16606            .find_all_references_task_sources
16607            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16608        {
16609            Ok(_) => {
16610                log::info!(
16611                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16612                );
16613                return None;
16614            }
16615            Err(i) => {
16616                self.find_all_references_task_sources.insert(i, head_anchor);
16617            }
16618        }
16619
16620        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16621        let workspace = self.workspace()?;
16622        let project = workspace.read(cx).project().clone();
16623        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16624        Some(cx.spawn_in(window, async move |editor, cx| {
16625            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16626                if let Ok(i) = editor
16627                    .find_all_references_task_sources
16628                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16629                {
16630                    editor.find_all_references_task_sources.remove(i);
16631                }
16632            });
16633
16634            let Some(locations) = references.await? else {
16635                return anyhow::Ok(Navigated::No);
16636            };
16637            let mut locations = cx.update(|_, cx| {
16638                locations
16639                    .into_iter()
16640                    .map(|location| {
16641                        let buffer = location.buffer.read(cx);
16642                        (location.buffer, location.range.to_point(buffer))
16643                    })
16644                    .into_group_map()
16645            })?;
16646            if locations.is_empty() {
16647                return anyhow::Ok(Navigated::No);
16648            }
16649            for ranges in locations.values_mut() {
16650                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16651                ranges.dedup();
16652            }
16653
16654            workspace.update_in(cx, |workspace, window, cx| {
16655                let target = locations
16656                    .iter()
16657                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16658                    .map(|(buffer, location)| {
16659                        buffer
16660                            .read(cx)
16661                            .text_for_range(location.clone())
16662                            .collect::<String>()
16663                    })
16664                    .filter(|text| !text.contains('\n'))
16665                    .unique()
16666                    .take(3)
16667                    .join(", ");
16668                let title = if target.is_empty() {
16669                    "References".to_owned()
16670                } else {
16671                    format!("References to {target}")
16672                };
16673                Self::open_locations_in_multibuffer(
16674                    workspace,
16675                    locations,
16676                    title,
16677                    false,
16678                    MultibufferSelectionMode::First,
16679                    window,
16680                    cx,
16681                );
16682                Navigated::Yes
16683            })
16684        }))
16685    }
16686
16687    /// Opens a multibuffer with the given project locations in it
16688    pub fn open_locations_in_multibuffer(
16689        workspace: &mut Workspace,
16690        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16691        title: String,
16692        split: bool,
16693        multibuffer_selection_mode: MultibufferSelectionMode,
16694        window: &mut Window,
16695        cx: &mut Context<Workspace>,
16696    ) {
16697        if locations.is_empty() {
16698            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16699            return;
16700        }
16701
16702        let capability = workspace.project().read(cx).capability();
16703        let mut ranges = <Vec<Range<Anchor>>>::new();
16704
16705        // a key to find existing multibuffer editors with the same set of locations
16706        // to prevent us from opening more and more multibuffer tabs for searches and the like
16707        let mut key = (title.clone(), vec![]);
16708        let excerpt_buffer = cx.new(|cx| {
16709            let key = &mut key.1;
16710            let mut multibuffer = MultiBuffer::new(capability);
16711            for (buffer, mut ranges_for_buffer) in locations {
16712                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16713                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16714                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16715                    PathKey::for_buffer(&buffer, cx),
16716                    buffer.clone(),
16717                    ranges_for_buffer,
16718                    multibuffer_context_lines(cx),
16719                    cx,
16720                );
16721                ranges.extend(new_ranges)
16722            }
16723
16724            multibuffer.with_title(title)
16725        });
16726        let existing = workspace.active_pane().update(cx, |pane, cx| {
16727            pane.items()
16728                .filter_map(|item| item.downcast::<Editor>())
16729                .find(|editor| {
16730                    editor
16731                        .read(cx)
16732                        .lookup_key
16733                        .as_ref()
16734                        .and_then(|it| {
16735                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16736                        })
16737                        .is_some_and(|it| *it == key)
16738                })
16739        });
16740        let editor = existing.unwrap_or_else(|| {
16741            cx.new(|cx| {
16742                let mut editor = Editor::for_multibuffer(
16743                    excerpt_buffer,
16744                    Some(workspace.project().clone()),
16745                    window,
16746                    cx,
16747                );
16748                editor.lookup_key = Some(Box::new(key));
16749                editor
16750            })
16751        });
16752        editor.update(cx, |editor, cx| {
16753            match multibuffer_selection_mode {
16754                MultibufferSelectionMode::First => {
16755                    if let Some(first_range) = ranges.first() {
16756                        editor.change_selections(
16757                            SelectionEffects::no_scroll(),
16758                            window,
16759                            cx,
16760                            |selections| {
16761                                selections.clear_disjoint();
16762                                selections
16763                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16764                            },
16765                        );
16766                    }
16767                    editor.highlight_background::<Self>(
16768                        &ranges,
16769                        |theme| theme.colors().editor_highlighted_line_background,
16770                        cx,
16771                    );
16772                }
16773                MultibufferSelectionMode::All => {
16774                    editor.change_selections(
16775                        SelectionEffects::no_scroll(),
16776                        window,
16777                        cx,
16778                        |selections| {
16779                            selections.clear_disjoint();
16780                            selections.select_anchor_ranges(ranges);
16781                        },
16782                    );
16783                }
16784            }
16785            editor.register_buffers_with_language_servers(cx);
16786        });
16787
16788        let item = Box::new(editor);
16789        let item_id = item.item_id();
16790
16791        if split {
16792            workspace.split_item(SplitDirection::Right, item, window, cx);
16793        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16794            let (preview_item_id, preview_item_idx) =
16795                workspace.active_pane().read_with(cx, |pane, _| {
16796                    (pane.preview_item_id(), pane.preview_item_idx())
16797                });
16798
16799            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16800
16801            if let Some(preview_item_id) = preview_item_id {
16802                workspace.active_pane().update(cx, |pane, cx| {
16803                    pane.remove_item(preview_item_id, false, false, window, cx);
16804                });
16805            }
16806        } else {
16807            workspace.add_item_to_active_pane(item, None, true, window, cx);
16808        }
16809        workspace.active_pane().update(cx, |pane, cx| {
16810            pane.set_preview_item_id(Some(item_id), cx);
16811        });
16812    }
16813
16814    pub fn rename(
16815        &mut self,
16816        _: &Rename,
16817        window: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) -> Option<Task<Result<()>>> {
16820        use language::ToOffset as _;
16821
16822        let provider = self.semantics_provider.clone()?;
16823        let selection = self.selections.newest_anchor().clone();
16824        let (cursor_buffer, cursor_buffer_position) = self
16825            .buffer
16826            .read(cx)
16827            .text_anchor_for_position(selection.head(), cx)?;
16828        let (tail_buffer, cursor_buffer_position_end) = self
16829            .buffer
16830            .read(cx)
16831            .text_anchor_for_position(selection.tail(), cx)?;
16832        if tail_buffer != cursor_buffer {
16833            return None;
16834        }
16835
16836        let snapshot = cursor_buffer.read(cx).snapshot();
16837        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16838        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16839        let prepare_rename = provider
16840            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16841            .unwrap_or_else(|| Task::ready(Ok(None)));
16842        drop(snapshot);
16843
16844        Some(cx.spawn_in(window, async move |this, cx| {
16845            let rename_range = if let Some(range) = prepare_rename.await? {
16846                Some(range)
16847            } else {
16848                this.update(cx, |this, cx| {
16849                    let buffer = this.buffer.read(cx).snapshot(cx);
16850                    let mut buffer_highlights = this
16851                        .document_highlights_for_position(selection.head(), &buffer)
16852                        .filter(|highlight| {
16853                            highlight.start.excerpt_id == selection.head().excerpt_id
16854                                && highlight.end.excerpt_id == selection.head().excerpt_id
16855                        });
16856                    buffer_highlights
16857                        .next()
16858                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16859                })?
16860            };
16861            if let Some(rename_range) = rename_range {
16862                this.update_in(cx, |this, window, cx| {
16863                    let snapshot = cursor_buffer.read(cx).snapshot();
16864                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16865                    let cursor_offset_in_rename_range =
16866                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16867                    let cursor_offset_in_rename_range_end =
16868                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16869
16870                    this.take_rename(false, window, cx);
16871                    let buffer = this.buffer.read(cx).read(cx);
16872                    let cursor_offset = selection.head().to_offset(&buffer);
16873                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16874                    let rename_end = rename_start + rename_buffer_range.len();
16875                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16876                    let mut old_highlight_id = None;
16877                    let old_name: Arc<str> = buffer
16878                        .chunks(rename_start..rename_end, true)
16879                        .map(|chunk| {
16880                            if old_highlight_id.is_none() {
16881                                old_highlight_id = chunk.syntax_highlight_id;
16882                            }
16883                            chunk.text
16884                        })
16885                        .collect::<String>()
16886                        .into();
16887
16888                    drop(buffer);
16889
16890                    // Position the selection in the rename editor so that it matches the current selection.
16891                    this.show_local_selections = false;
16892                    let rename_editor = cx.new(|cx| {
16893                        let mut editor = Editor::single_line(window, cx);
16894                        editor.buffer.update(cx, |buffer, cx| {
16895                            buffer.edit([(0..0, old_name.clone())], None, cx)
16896                        });
16897                        let rename_selection_range = match cursor_offset_in_rename_range
16898                            .cmp(&cursor_offset_in_rename_range_end)
16899                        {
16900                            Ordering::Equal => {
16901                                editor.select_all(&SelectAll, window, cx);
16902                                return editor;
16903                            }
16904                            Ordering::Less => {
16905                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16906                            }
16907                            Ordering::Greater => {
16908                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16909                            }
16910                        };
16911                        if rename_selection_range.end > old_name.len() {
16912                            editor.select_all(&SelectAll, window, cx);
16913                        } else {
16914                            editor.change_selections(Default::default(), window, cx, |s| {
16915                                s.select_ranges([rename_selection_range]);
16916                            });
16917                        }
16918                        editor
16919                    });
16920                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16921                        if e == &EditorEvent::Focused {
16922                            cx.emit(EditorEvent::FocusedIn)
16923                        }
16924                    })
16925                    .detach();
16926
16927                    let write_highlights =
16928                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16929                    let read_highlights =
16930                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16931                    let ranges = write_highlights
16932                        .iter()
16933                        .flat_map(|(_, ranges)| ranges.iter())
16934                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16935                        .cloned()
16936                        .collect();
16937
16938                    this.highlight_text::<Rename>(
16939                        ranges,
16940                        HighlightStyle {
16941                            fade_out: Some(0.6),
16942                            ..Default::default()
16943                        },
16944                        cx,
16945                    );
16946                    let rename_focus_handle = rename_editor.focus_handle(cx);
16947                    window.focus(&rename_focus_handle);
16948                    let block_id = this.insert_blocks(
16949                        [BlockProperties {
16950                            style: BlockStyle::Flex,
16951                            placement: BlockPlacement::Below(range.start),
16952                            height: Some(1),
16953                            render: Arc::new({
16954                                let rename_editor = rename_editor.clone();
16955                                move |cx: &mut BlockContext| {
16956                                    let mut text_style = cx.editor_style.text.clone();
16957                                    if let Some(highlight_style) = old_highlight_id
16958                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16959                                    {
16960                                        text_style = text_style.highlight(highlight_style);
16961                                    }
16962                                    div()
16963                                        .block_mouse_except_scroll()
16964                                        .pl(cx.anchor_x)
16965                                        .child(EditorElement::new(
16966                                            &rename_editor,
16967                                            EditorStyle {
16968                                                background: cx.theme().system().transparent,
16969                                                local_player: cx.editor_style.local_player,
16970                                                text: text_style,
16971                                                scrollbar_width: cx.editor_style.scrollbar_width,
16972                                                syntax: cx.editor_style.syntax.clone(),
16973                                                status: cx.editor_style.status.clone(),
16974                                                inlay_hints_style: HighlightStyle {
16975                                                    font_weight: Some(FontWeight::BOLD),
16976                                                    ..make_inlay_hints_style(cx.app)
16977                                                },
16978                                                edit_prediction_styles: make_suggestion_styles(
16979                                                    cx.app,
16980                                                ),
16981                                                ..EditorStyle::default()
16982                                            },
16983                                        ))
16984                                        .into_any_element()
16985                                }
16986                            }),
16987                            priority: 0,
16988                        }],
16989                        Some(Autoscroll::fit()),
16990                        cx,
16991                    )[0];
16992                    this.pending_rename = Some(RenameState {
16993                        range,
16994                        old_name,
16995                        editor: rename_editor,
16996                        block_id,
16997                    });
16998                })?;
16999            }
17000
17001            Ok(())
17002        }))
17003    }
17004
17005    pub fn confirm_rename(
17006        &mut self,
17007        _: &ConfirmRename,
17008        window: &mut Window,
17009        cx: &mut Context<Self>,
17010    ) -> Option<Task<Result<()>>> {
17011        let rename = self.take_rename(false, window, cx)?;
17012        let workspace = self.workspace()?.downgrade();
17013        let (buffer, start) = self
17014            .buffer
17015            .read(cx)
17016            .text_anchor_for_position(rename.range.start, cx)?;
17017        let (end_buffer, _) = self
17018            .buffer
17019            .read(cx)
17020            .text_anchor_for_position(rename.range.end, cx)?;
17021        if buffer != end_buffer {
17022            return None;
17023        }
17024
17025        let old_name = rename.old_name;
17026        let new_name = rename.editor.read(cx).text(cx);
17027
17028        let rename = self.semantics_provider.as_ref()?.perform_rename(
17029            &buffer,
17030            start,
17031            new_name.clone(),
17032            cx,
17033        )?;
17034
17035        Some(cx.spawn_in(window, async move |editor, cx| {
17036            let project_transaction = rename.await?;
17037            Self::open_project_transaction(
17038                &editor,
17039                workspace,
17040                project_transaction,
17041                format!("Rename: {}{}", old_name, new_name),
17042                cx,
17043            )
17044            .await?;
17045
17046            editor.update(cx, |editor, cx| {
17047                editor.refresh_document_highlights(cx);
17048            })?;
17049            Ok(())
17050        }))
17051    }
17052
17053    fn take_rename(
17054        &mut self,
17055        moving_cursor: bool,
17056        window: &mut Window,
17057        cx: &mut Context<Self>,
17058    ) -> Option<RenameState> {
17059        let rename = self.pending_rename.take()?;
17060        if rename.editor.focus_handle(cx).is_focused(window) {
17061            window.focus(&self.focus_handle);
17062        }
17063
17064        self.remove_blocks(
17065            [rename.block_id].into_iter().collect(),
17066            Some(Autoscroll::fit()),
17067            cx,
17068        );
17069        self.clear_highlights::<Rename>(cx);
17070        self.show_local_selections = true;
17071
17072        if moving_cursor {
17073            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17074                editor.selections.newest::<usize>(cx).head()
17075            });
17076
17077            // Update the selection to match the position of the selection inside
17078            // the rename editor.
17079            let snapshot = self.buffer.read(cx).read(cx);
17080            let rename_range = rename.range.to_offset(&snapshot);
17081            let cursor_in_editor = snapshot
17082                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17083                .min(rename_range.end);
17084            drop(snapshot);
17085
17086            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17087                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17088            });
17089        } else {
17090            self.refresh_document_highlights(cx);
17091        }
17092
17093        Some(rename)
17094    }
17095
17096    pub fn pending_rename(&self) -> Option<&RenameState> {
17097        self.pending_rename.as_ref()
17098    }
17099
17100    fn format(
17101        &mut self,
17102        _: &Format,
17103        window: &mut Window,
17104        cx: &mut Context<Self>,
17105    ) -> Option<Task<Result<()>>> {
17106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17107
17108        let project = match &self.project {
17109            Some(project) => project.clone(),
17110            None => return None,
17111        };
17112
17113        Some(self.perform_format(
17114            project,
17115            FormatTrigger::Manual,
17116            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17117            window,
17118            cx,
17119        ))
17120    }
17121
17122    fn format_selections(
17123        &mut self,
17124        _: &FormatSelections,
17125        window: &mut Window,
17126        cx: &mut Context<Self>,
17127    ) -> Option<Task<Result<()>>> {
17128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17129
17130        let project = match &self.project {
17131            Some(project) => project.clone(),
17132            None => return None,
17133        };
17134
17135        let ranges = self
17136            .selections
17137            .all_adjusted(cx)
17138            .into_iter()
17139            .map(|selection| selection.range())
17140            .collect_vec();
17141
17142        Some(self.perform_format(
17143            project,
17144            FormatTrigger::Manual,
17145            FormatTarget::Ranges(ranges),
17146            window,
17147            cx,
17148        ))
17149    }
17150
17151    fn perform_format(
17152        &mut self,
17153        project: Entity<Project>,
17154        trigger: FormatTrigger,
17155        target: FormatTarget,
17156        window: &mut Window,
17157        cx: &mut Context<Self>,
17158    ) -> Task<Result<()>> {
17159        let buffer = self.buffer.clone();
17160        let (buffers, target) = match target {
17161            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17162            FormatTarget::Ranges(selection_ranges) => {
17163                let multi_buffer = buffer.read(cx);
17164                let snapshot = multi_buffer.read(cx);
17165                let mut buffers = HashSet::default();
17166                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17167                    BTreeMap::new();
17168                for selection_range in selection_ranges {
17169                    for (buffer, buffer_range, _) in
17170                        snapshot.range_to_buffer_ranges(selection_range)
17171                    {
17172                        let buffer_id = buffer.remote_id();
17173                        let start = buffer.anchor_before(buffer_range.start);
17174                        let end = buffer.anchor_after(buffer_range.end);
17175                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17176                        buffer_id_to_ranges
17177                            .entry(buffer_id)
17178                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17179                            .or_insert_with(|| vec![start..end]);
17180                    }
17181                }
17182                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17183            }
17184        };
17185
17186        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17187        let selections_prev = transaction_id_prev
17188            .and_then(|transaction_id_prev| {
17189                // default to selections as they were after the last edit, if we have them,
17190                // instead of how they are now.
17191                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17192                // will take you back to where you made the last edit, instead of staying where you scrolled
17193                self.selection_history
17194                    .transaction(transaction_id_prev)
17195                    .map(|t| t.0.clone())
17196            })
17197            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17198
17199        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17200        let format = project.update(cx, |project, cx| {
17201            project.format(buffers, target, true, trigger, cx)
17202        });
17203
17204        cx.spawn_in(window, async move |editor, cx| {
17205            let transaction = futures::select_biased! {
17206                transaction = format.log_err().fuse() => transaction,
17207                () = timeout => {
17208                    log::warn!("timed out waiting for formatting");
17209                    None
17210                }
17211            };
17212
17213            buffer
17214                .update(cx, |buffer, cx| {
17215                    if let Some(transaction) = transaction
17216                        && !buffer.is_singleton()
17217                    {
17218                        buffer.push_transaction(&transaction.0, cx);
17219                    }
17220                    cx.notify();
17221                })
17222                .ok();
17223
17224            if let Some(transaction_id_now) =
17225                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17226            {
17227                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17228                if has_new_transaction {
17229                    _ = editor.update(cx, |editor, _| {
17230                        editor
17231                            .selection_history
17232                            .insert_transaction(transaction_id_now, selections_prev);
17233                    });
17234                }
17235            }
17236
17237            Ok(())
17238        })
17239    }
17240
17241    fn organize_imports(
17242        &mut self,
17243        _: &OrganizeImports,
17244        window: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) -> Option<Task<Result<()>>> {
17247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17248        let project = match &self.project {
17249            Some(project) => project.clone(),
17250            None => return None,
17251        };
17252        Some(self.perform_code_action_kind(
17253            project,
17254            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17255            window,
17256            cx,
17257        ))
17258    }
17259
17260    fn perform_code_action_kind(
17261        &mut self,
17262        project: Entity<Project>,
17263        kind: CodeActionKind,
17264        window: &mut Window,
17265        cx: &mut Context<Self>,
17266    ) -> Task<Result<()>> {
17267        let buffer = self.buffer.clone();
17268        let buffers = buffer.read(cx).all_buffers();
17269        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17270        let apply_action = project.update(cx, |project, cx| {
17271            project.apply_code_action_kind(buffers, kind, true, cx)
17272        });
17273        cx.spawn_in(window, async move |_, cx| {
17274            let transaction = futures::select_biased! {
17275                () = timeout => {
17276                    log::warn!("timed out waiting for executing code action");
17277                    None
17278                }
17279                transaction = apply_action.log_err().fuse() => transaction,
17280            };
17281            buffer
17282                .update(cx, |buffer, cx| {
17283                    // check if we need this
17284                    if let Some(transaction) = transaction
17285                        && !buffer.is_singleton()
17286                    {
17287                        buffer.push_transaction(&transaction.0, cx);
17288                    }
17289                    cx.notify();
17290                })
17291                .ok();
17292            Ok(())
17293        })
17294    }
17295
17296    pub fn restart_language_server(
17297        &mut self,
17298        _: &RestartLanguageServer,
17299        _: &mut Window,
17300        cx: &mut Context<Self>,
17301    ) {
17302        if let Some(project) = self.project.clone() {
17303            self.buffer.update(cx, |multi_buffer, cx| {
17304                project.update(cx, |project, cx| {
17305                    project.restart_language_servers_for_buffers(
17306                        multi_buffer.all_buffers().into_iter().collect(),
17307                        HashSet::default(),
17308                        cx,
17309                    );
17310                });
17311            })
17312        }
17313    }
17314
17315    pub fn stop_language_server(
17316        &mut self,
17317        _: &StopLanguageServer,
17318        _: &mut Window,
17319        cx: &mut Context<Self>,
17320    ) {
17321        if let Some(project) = self.project.clone() {
17322            self.buffer.update(cx, |multi_buffer, cx| {
17323                project.update(cx, |project, cx| {
17324                    project.stop_language_servers_for_buffers(
17325                        multi_buffer.all_buffers().into_iter().collect(),
17326                        HashSet::default(),
17327                        cx,
17328                    );
17329                    cx.emit(project::Event::RefreshInlayHints);
17330                });
17331            });
17332        }
17333    }
17334
17335    fn cancel_language_server_work(
17336        workspace: &mut Workspace,
17337        _: &actions::CancelLanguageServerWork,
17338        _: &mut Window,
17339        cx: &mut Context<Workspace>,
17340    ) {
17341        let project = workspace.project();
17342        let buffers = workspace
17343            .active_item(cx)
17344            .and_then(|item| item.act_as::<Editor>(cx))
17345            .map_or(HashSet::default(), |editor| {
17346                editor.read(cx).buffer.read(cx).all_buffers()
17347            });
17348        project.update(cx, |project, cx| {
17349            project.cancel_language_server_work_for_buffers(buffers, cx);
17350        });
17351    }
17352
17353    fn show_character_palette(
17354        &mut self,
17355        _: &ShowCharacterPalette,
17356        window: &mut Window,
17357        _: &mut Context<Self>,
17358    ) {
17359        window.show_character_palette();
17360    }
17361
17362    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17363        if !self.diagnostics_enabled() {
17364            return;
17365        }
17366
17367        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17368            let buffer = self.buffer.read(cx).snapshot(cx);
17369            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17370            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17371            let is_valid = buffer
17372                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17373                .any(|entry| {
17374                    entry.diagnostic.is_primary
17375                        && !entry.range.is_empty()
17376                        && entry.range.start == primary_range_start
17377                        && entry.diagnostic.message == active_diagnostics.active_message
17378                });
17379
17380            if !is_valid {
17381                self.dismiss_diagnostics(cx);
17382            }
17383        }
17384    }
17385
17386    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17387        match &self.active_diagnostics {
17388            ActiveDiagnostic::Group(group) => Some(group),
17389            _ => None,
17390        }
17391    }
17392
17393    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17394        if !self.diagnostics_enabled() {
17395            return;
17396        }
17397        self.dismiss_diagnostics(cx);
17398        self.active_diagnostics = ActiveDiagnostic::All;
17399    }
17400
17401    fn activate_diagnostics(
17402        &mut self,
17403        buffer_id: BufferId,
17404        diagnostic: DiagnosticEntry<usize>,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17409            return;
17410        }
17411        self.dismiss_diagnostics(cx);
17412        let snapshot = self.snapshot(window, cx);
17413        let buffer = self.buffer.read(cx).snapshot(cx);
17414        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17415            return;
17416        };
17417
17418        let diagnostic_group = buffer
17419            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17420            .collect::<Vec<_>>();
17421
17422        let blocks =
17423            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17424
17425        let blocks = self.display_map.update(cx, |display_map, cx| {
17426            display_map.insert_blocks(blocks, cx).into_iter().collect()
17427        });
17428        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17429            active_range: buffer.anchor_before(diagnostic.range.start)
17430                ..buffer.anchor_after(diagnostic.range.end),
17431            active_message: diagnostic.diagnostic.message.clone(),
17432            group_id: diagnostic.diagnostic.group_id,
17433            blocks,
17434        });
17435        cx.notify();
17436    }
17437
17438    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17439        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17440            return;
17441        };
17442
17443        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17444        if let ActiveDiagnostic::Group(group) = prev {
17445            self.display_map.update(cx, |display_map, cx| {
17446                display_map.remove_blocks(group.blocks, cx);
17447            });
17448            cx.notify();
17449        }
17450    }
17451
17452    /// Disable inline diagnostics rendering for this editor.
17453    pub fn disable_inline_diagnostics(&mut self) {
17454        self.inline_diagnostics_enabled = false;
17455        self.inline_diagnostics_update = Task::ready(());
17456        self.inline_diagnostics.clear();
17457    }
17458
17459    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17460        self.diagnostics_enabled = false;
17461        self.dismiss_diagnostics(cx);
17462        self.inline_diagnostics_update = Task::ready(());
17463        self.inline_diagnostics.clear();
17464    }
17465
17466    pub fn disable_word_completions(&mut self) {
17467        self.word_completions_enabled = false;
17468    }
17469
17470    pub fn diagnostics_enabled(&self) -> bool {
17471        self.diagnostics_enabled && self.mode.is_full()
17472    }
17473
17474    pub fn inline_diagnostics_enabled(&self) -> bool {
17475        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17476    }
17477
17478    pub fn show_inline_diagnostics(&self) -> bool {
17479        self.show_inline_diagnostics
17480    }
17481
17482    pub fn toggle_inline_diagnostics(
17483        &mut self,
17484        _: &ToggleInlineDiagnostics,
17485        window: &mut Window,
17486        cx: &mut Context<Editor>,
17487    ) {
17488        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17489        self.refresh_inline_diagnostics(false, window, cx);
17490    }
17491
17492    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17493        self.diagnostics_max_severity = severity;
17494        self.display_map.update(cx, |display_map, _| {
17495            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17496        });
17497    }
17498
17499    pub fn toggle_diagnostics(
17500        &mut self,
17501        _: &ToggleDiagnostics,
17502        window: &mut Window,
17503        cx: &mut Context<Editor>,
17504    ) {
17505        if !self.diagnostics_enabled() {
17506            return;
17507        }
17508
17509        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17510            EditorSettings::get_global(cx)
17511                .diagnostics_max_severity
17512                .filter(|severity| severity != &DiagnosticSeverity::Off)
17513                .unwrap_or(DiagnosticSeverity::Hint)
17514        } else {
17515            DiagnosticSeverity::Off
17516        };
17517        self.set_max_diagnostics_severity(new_severity, cx);
17518        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17519            self.active_diagnostics = ActiveDiagnostic::None;
17520            self.inline_diagnostics_update = Task::ready(());
17521            self.inline_diagnostics.clear();
17522        } else {
17523            self.refresh_inline_diagnostics(false, window, cx);
17524        }
17525
17526        cx.notify();
17527    }
17528
17529    pub fn toggle_minimap(
17530        &mut self,
17531        _: &ToggleMinimap,
17532        window: &mut Window,
17533        cx: &mut Context<Editor>,
17534    ) {
17535        if self.supports_minimap(cx) {
17536            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17537        }
17538    }
17539
17540    fn refresh_inline_diagnostics(
17541        &mut self,
17542        debounce: bool,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        let max_severity = ProjectSettings::get_global(cx)
17547            .diagnostics
17548            .inline
17549            .max_severity
17550            .unwrap_or(self.diagnostics_max_severity);
17551
17552        if !self.inline_diagnostics_enabled()
17553            || !self.show_inline_diagnostics
17554            || max_severity == DiagnosticSeverity::Off
17555        {
17556            self.inline_diagnostics_update = Task::ready(());
17557            self.inline_diagnostics.clear();
17558            return;
17559        }
17560
17561        let debounce_ms = ProjectSettings::get_global(cx)
17562            .diagnostics
17563            .inline
17564            .update_debounce_ms;
17565        let debounce = if debounce && debounce_ms > 0 {
17566            Some(Duration::from_millis(debounce_ms))
17567        } else {
17568            None
17569        };
17570        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17571            if let Some(debounce) = debounce {
17572                cx.background_executor().timer(debounce).await;
17573            }
17574            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17575                editor
17576                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17577                    .ok()
17578            }) else {
17579                return;
17580            };
17581
17582            let new_inline_diagnostics = cx
17583                .background_spawn(async move {
17584                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17585                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17586                        let message = diagnostic_entry
17587                            .diagnostic
17588                            .message
17589                            .split_once('\n')
17590                            .map(|(line, _)| line)
17591                            .map(SharedString::new)
17592                            .unwrap_or_else(|| {
17593                                SharedString::from(diagnostic_entry.diagnostic.message)
17594                            });
17595                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17596                        let (Ok(i) | Err(i)) = inline_diagnostics
17597                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17598                        inline_diagnostics.insert(
17599                            i,
17600                            (
17601                                start_anchor,
17602                                InlineDiagnostic {
17603                                    message,
17604                                    group_id: diagnostic_entry.diagnostic.group_id,
17605                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17606                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17607                                    severity: diagnostic_entry.diagnostic.severity,
17608                                },
17609                            ),
17610                        );
17611                    }
17612                    inline_diagnostics
17613                })
17614                .await;
17615
17616            editor
17617                .update(cx, |editor, cx| {
17618                    editor.inline_diagnostics = new_inline_diagnostics;
17619                    cx.notify();
17620                })
17621                .ok();
17622        });
17623    }
17624
17625    fn pull_diagnostics(
17626        &mut self,
17627        buffer_id: Option<BufferId>,
17628        window: &Window,
17629        cx: &mut Context<Self>,
17630    ) -> Option<()> {
17631        if !self.mode().is_full() {
17632            return None;
17633        }
17634        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17635            .diagnostics
17636            .lsp_pull_diagnostics;
17637        if !pull_diagnostics_settings.enabled {
17638            return None;
17639        }
17640        let project = self.project()?.downgrade();
17641        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17642        let mut buffers = self.buffer.read(cx).all_buffers();
17643        if let Some(buffer_id) = buffer_id {
17644            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17645        }
17646
17647        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17648            cx.background_executor().timer(debounce).await;
17649
17650            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17651                buffers
17652                    .into_iter()
17653                    .filter_map(|buffer| {
17654                        project
17655                            .update(cx, |project, cx| {
17656                                project.lsp_store().update(cx, |lsp_store, cx| {
17657                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17658                                })
17659                            })
17660                            .ok()
17661                    })
17662                    .collect::<FuturesUnordered<_>>()
17663            }) else {
17664                return;
17665            };
17666
17667            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17668                match pull_task {
17669                    Ok(()) => {
17670                        if editor
17671                            .update_in(cx, |editor, window, cx| {
17672                                editor.update_diagnostics_state(window, cx);
17673                            })
17674                            .is_err()
17675                        {
17676                            return;
17677                        }
17678                    }
17679                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17680                }
17681            }
17682        });
17683
17684        Some(())
17685    }
17686
17687    pub fn set_selections_from_remote(
17688        &mut self,
17689        selections: Vec<Selection<Anchor>>,
17690        pending_selection: Option<Selection<Anchor>>,
17691        window: &mut Window,
17692        cx: &mut Context<Self>,
17693    ) {
17694        let old_cursor_position = self.selections.newest_anchor().head();
17695        self.selections.change_with(cx, |s| {
17696            s.select_anchors(selections);
17697            if let Some(pending_selection) = pending_selection {
17698                s.set_pending(pending_selection, SelectMode::Character);
17699            } else {
17700                s.clear_pending();
17701            }
17702        });
17703        self.selections_did_change(
17704            false,
17705            &old_cursor_position,
17706            SelectionEffects::default(),
17707            window,
17708            cx,
17709        );
17710    }
17711
17712    pub fn transact(
17713        &mut self,
17714        window: &mut Window,
17715        cx: &mut Context<Self>,
17716        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17717    ) -> Option<TransactionId> {
17718        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17719            this.start_transaction_at(Instant::now(), window, cx);
17720            update(this, window, cx);
17721            this.end_transaction_at(Instant::now(), cx)
17722        })
17723    }
17724
17725    pub fn start_transaction_at(
17726        &mut self,
17727        now: Instant,
17728        window: &mut Window,
17729        cx: &mut Context<Self>,
17730    ) -> Option<TransactionId> {
17731        self.end_selection(window, cx);
17732        if let Some(tx_id) = self
17733            .buffer
17734            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17735        {
17736            self.selection_history
17737                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17738            cx.emit(EditorEvent::TransactionBegun {
17739                transaction_id: tx_id,
17740            });
17741            Some(tx_id)
17742        } else {
17743            None
17744        }
17745    }
17746
17747    pub fn end_transaction_at(
17748        &mut self,
17749        now: Instant,
17750        cx: &mut Context<Self>,
17751    ) -> Option<TransactionId> {
17752        if let Some(transaction_id) = self
17753            .buffer
17754            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17755        {
17756            if let Some((_, end_selections)) =
17757                self.selection_history.transaction_mut(transaction_id)
17758            {
17759                *end_selections = Some(self.selections.disjoint_anchors_arc());
17760            } else {
17761                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17762            }
17763
17764            cx.emit(EditorEvent::Edited { transaction_id });
17765            Some(transaction_id)
17766        } else {
17767            None
17768        }
17769    }
17770
17771    pub fn modify_transaction_selection_history(
17772        &mut self,
17773        transaction_id: TransactionId,
17774        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17775    ) -> bool {
17776        self.selection_history
17777            .transaction_mut(transaction_id)
17778            .map(modify)
17779            .is_some()
17780    }
17781
17782    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17783        if self.selection_mark_mode {
17784            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17785                s.move_with(|_, sel| {
17786                    sel.collapse_to(sel.head(), SelectionGoal::None);
17787                });
17788            })
17789        }
17790        self.selection_mark_mode = true;
17791        cx.notify();
17792    }
17793
17794    pub fn swap_selection_ends(
17795        &mut self,
17796        _: &actions::SwapSelectionEnds,
17797        window: &mut Window,
17798        cx: &mut Context<Self>,
17799    ) {
17800        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17801            s.move_with(|_, sel| {
17802                if sel.start != sel.end {
17803                    sel.reversed = !sel.reversed
17804                }
17805            });
17806        });
17807        self.request_autoscroll(Autoscroll::newest(), cx);
17808        cx.notify();
17809    }
17810
17811    pub fn toggle_focus(
17812        workspace: &mut Workspace,
17813        _: &actions::ToggleFocus,
17814        window: &mut Window,
17815        cx: &mut Context<Workspace>,
17816    ) {
17817        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17818            return;
17819        };
17820        workspace.activate_item(&item, true, true, window, cx);
17821    }
17822
17823    pub fn toggle_fold(
17824        &mut self,
17825        _: &actions::ToggleFold,
17826        window: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        if self.is_singleton(cx) {
17830            let selection = self.selections.newest::<Point>(cx);
17831
17832            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17833            let range = if selection.is_empty() {
17834                let point = selection.head().to_display_point(&display_map);
17835                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17836                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17837                    .to_point(&display_map);
17838                start..end
17839            } else {
17840                selection.range()
17841            };
17842            if display_map.folds_in_range(range).next().is_some() {
17843                self.unfold_lines(&Default::default(), window, cx)
17844            } else {
17845                self.fold(&Default::default(), window, cx)
17846            }
17847        } else {
17848            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17849            let buffer_ids: HashSet<_> = self
17850                .selections
17851                .disjoint_anchor_ranges()
17852                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17853                .collect();
17854
17855            let should_unfold = buffer_ids
17856                .iter()
17857                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17858
17859            for buffer_id in buffer_ids {
17860                if should_unfold {
17861                    self.unfold_buffer(buffer_id, cx);
17862                } else {
17863                    self.fold_buffer(buffer_id, cx);
17864                }
17865            }
17866        }
17867    }
17868
17869    pub fn toggle_fold_recursive(
17870        &mut self,
17871        _: &actions::ToggleFoldRecursive,
17872        window: &mut Window,
17873        cx: &mut Context<Self>,
17874    ) {
17875        let selection = self.selections.newest::<Point>(cx);
17876
17877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17878        let range = if selection.is_empty() {
17879            let point = selection.head().to_display_point(&display_map);
17880            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17881            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17882                .to_point(&display_map);
17883            start..end
17884        } else {
17885            selection.range()
17886        };
17887        if display_map.folds_in_range(range).next().is_some() {
17888            self.unfold_recursive(&Default::default(), window, cx)
17889        } else {
17890            self.fold_recursive(&Default::default(), window, cx)
17891        }
17892    }
17893
17894    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17895        if self.is_singleton(cx) {
17896            let mut to_fold = Vec::new();
17897            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17898            let selections = self.selections.all_adjusted(cx);
17899
17900            for selection in selections {
17901                let range = selection.range().sorted();
17902                let buffer_start_row = range.start.row;
17903
17904                if range.start.row != range.end.row {
17905                    let mut found = false;
17906                    let mut row = range.start.row;
17907                    while row <= range.end.row {
17908                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17909                        {
17910                            found = true;
17911                            row = crease.range().end.row + 1;
17912                            to_fold.push(crease);
17913                        } else {
17914                            row += 1
17915                        }
17916                    }
17917                    if found {
17918                        continue;
17919                    }
17920                }
17921
17922                for row in (0..=range.start.row).rev() {
17923                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17924                        && crease.range().end.row >= buffer_start_row
17925                    {
17926                        to_fold.push(crease);
17927                        if row <= range.start.row {
17928                            break;
17929                        }
17930                    }
17931                }
17932            }
17933
17934            self.fold_creases(to_fold, true, window, cx);
17935        } else {
17936            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17937            let buffer_ids = self
17938                .selections
17939                .disjoint_anchor_ranges()
17940                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17941                .collect::<HashSet<_>>();
17942            for buffer_id in buffer_ids {
17943                self.fold_buffer(buffer_id, cx);
17944            }
17945        }
17946    }
17947
17948    pub fn toggle_fold_all(
17949        &mut self,
17950        _: &actions::ToggleFoldAll,
17951        window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        if self.buffer.read(cx).is_singleton() {
17955            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17956            let has_folds = display_map
17957                .folds_in_range(0..display_map.buffer_snapshot.len())
17958                .next()
17959                .is_some();
17960
17961            if has_folds {
17962                self.unfold_all(&actions::UnfoldAll, window, cx);
17963            } else {
17964                self.fold_all(&actions::FoldAll, window, cx);
17965            }
17966        } else {
17967            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17968            let should_unfold = buffer_ids
17969                .iter()
17970                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17971
17972            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17973                editor
17974                    .update_in(cx, |editor, _, cx| {
17975                        for buffer_id in buffer_ids {
17976                            if should_unfold {
17977                                editor.unfold_buffer(buffer_id, cx);
17978                            } else {
17979                                editor.fold_buffer(buffer_id, cx);
17980                            }
17981                        }
17982                    })
17983                    .ok();
17984            });
17985        }
17986    }
17987
17988    fn fold_at_level(
17989        &mut self,
17990        fold_at: &FoldAtLevel,
17991        window: &mut Window,
17992        cx: &mut Context<Self>,
17993    ) {
17994        if !self.buffer.read(cx).is_singleton() {
17995            return;
17996        }
17997
17998        let fold_at_level = fold_at.0;
17999        let snapshot = self.buffer.read(cx).snapshot(cx);
18000        let mut to_fold = Vec::new();
18001        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18002
18003        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18004            while start_row < end_row {
18005                match self
18006                    .snapshot(window, cx)
18007                    .crease_for_buffer_row(MultiBufferRow(start_row))
18008                {
18009                    Some(crease) => {
18010                        let nested_start_row = crease.range().start.row + 1;
18011                        let nested_end_row = crease.range().end.row;
18012
18013                        if current_level < fold_at_level {
18014                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18015                        } else if current_level == fold_at_level {
18016                            to_fold.push(crease);
18017                        }
18018
18019                        start_row = nested_end_row + 1;
18020                    }
18021                    None => start_row += 1,
18022                }
18023            }
18024        }
18025
18026        self.fold_creases(to_fold, true, window, cx);
18027    }
18028
18029    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18030        if self.buffer.read(cx).is_singleton() {
18031            let mut fold_ranges = Vec::new();
18032            let snapshot = self.buffer.read(cx).snapshot(cx);
18033
18034            for row in 0..snapshot.max_row().0 {
18035                if let Some(foldable_range) = self
18036                    .snapshot(window, cx)
18037                    .crease_for_buffer_row(MultiBufferRow(row))
18038                {
18039                    fold_ranges.push(foldable_range);
18040                }
18041            }
18042
18043            self.fold_creases(fold_ranges, true, window, cx);
18044        } else {
18045            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18046                editor
18047                    .update_in(cx, |editor, _, cx| {
18048                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18049                            editor.fold_buffer(buffer_id, cx);
18050                        }
18051                    })
18052                    .ok();
18053            });
18054        }
18055    }
18056
18057    pub fn fold_function_bodies(
18058        &mut self,
18059        _: &actions::FoldFunctionBodies,
18060        window: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) {
18063        let snapshot = self.buffer.read(cx).snapshot(cx);
18064
18065        let ranges = snapshot
18066            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18067            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18068            .collect::<Vec<_>>();
18069
18070        let creases = ranges
18071            .into_iter()
18072            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18073            .collect();
18074
18075        self.fold_creases(creases, true, window, cx);
18076    }
18077
18078    pub fn fold_recursive(
18079        &mut self,
18080        _: &actions::FoldRecursive,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        let mut to_fold = Vec::new();
18085        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18086        let selections = self.selections.all_adjusted(cx);
18087
18088        for selection in selections {
18089            let range = selection.range().sorted();
18090            let buffer_start_row = range.start.row;
18091
18092            if range.start.row != range.end.row {
18093                let mut found = false;
18094                for row in range.start.row..=range.end.row {
18095                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18096                        found = true;
18097                        to_fold.push(crease);
18098                    }
18099                }
18100                if found {
18101                    continue;
18102                }
18103            }
18104
18105            for row in (0..=range.start.row).rev() {
18106                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18107                    if crease.range().end.row >= buffer_start_row {
18108                        to_fold.push(crease);
18109                    } else {
18110                        break;
18111                    }
18112                }
18113            }
18114        }
18115
18116        self.fold_creases(to_fold, true, window, cx);
18117    }
18118
18119    pub fn fold_at(
18120        &mut self,
18121        buffer_row: MultiBufferRow,
18122        window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126
18127        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18128            let autoscroll = self
18129                .selections
18130                .all::<Point>(cx)
18131                .iter()
18132                .any(|selection| crease.range().overlaps(&selection.range()));
18133
18134            self.fold_creases(vec![crease], autoscroll, window, cx);
18135        }
18136    }
18137
18138    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18139        if self.is_singleton(cx) {
18140            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18141            let buffer = &display_map.buffer_snapshot;
18142            let selections = self.selections.all::<Point>(cx);
18143            let ranges = selections
18144                .iter()
18145                .map(|s| {
18146                    let range = s.display_range(&display_map).sorted();
18147                    let mut start = range.start.to_point(&display_map);
18148                    let mut end = range.end.to_point(&display_map);
18149                    start.column = 0;
18150                    end.column = buffer.line_len(MultiBufferRow(end.row));
18151                    start..end
18152                })
18153                .collect::<Vec<_>>();
18154
18155            self.unfold_ranges(&ranges, true, true, cx);
18156        } else {
18157            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18158            let buffer_ids = self
18159                .selections
18160                .disjoint_anchor_ranges()
18161                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18162                .collect::<HashSet<_>>();
18163            for buffer_id in buffer_ids {
18164                self.unfold_buffer(buffer_id, cx);
18165            }
18166        }
18167    }
18168
18169    pub fn unfold_recursive(
18170        &mut self,
18171        _: &UnfoldRecursive,
18172        _window: &mut Window,
18173        cx: &mut Context<Self>,
18174    ) {
18175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18176        let selections = self.selections.all::<Point>(cx);
18177        let ranges = selections
18178            .iter()
18179            .map(|s| {
18180                let mut range = s.display_range(&display_map).sorted();
18181                *range.start.column_mut() = 0;
18182                *range.end.column_mut() = display_map.line_len(range.end.row());
18183                let start = range.start.to_point(&display_map);
18184                let end = range.end.to_point(&display_map);
18185                start..end
18186            })
18187            .collect::<Vec<_>>();
18188
18189        self.unfold_ranges(&ranges, true, true, cx);
18190    }
18191
18192    pub fn unfold_at(
18193        &mut self,
18194        buffer_row: MultiBufferRow,
18195        _window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18199
18200        let intersection_range = Point::new(buffer_row.0, 0)
18201            ..Point::new(
18202                buffer_row.0,
18203                display_map.buffer_snapshot.line_len(buffer_row),
18204            );
18205
18206        let autoscroll = self
18207            .selections
18208            .all::<Point>(cx)
18209            .iter()
18210            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18211
18212        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18213    }
18214
18215    pub fn unfold_all(
18216        &mut self,
18217        _: &actions::UnfoldAll,
18218        _window: &mut Window,
18219        cx: &mut Context<Self>,
18220    ) {
18221        if self.buffer.read(cx).is_singleton() {
18222            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18223            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18224        } else {
18225            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18226                editor
18227                    .update(cx, |editor, cx| {
18228                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18229                            editor.unfold_buffer(buffer_id, cx);
18230                        }
18231                    })
18232                    .ok();
18233            });
18234        }
18235    }
18236
18237    pub fn fold_selected_ranges(
18238        &mut self,
18239        _: &FoldSelectedRanges,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        let selections = self.selections.all_adjusted(cx);
18244        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18245        let ranges = selections
18246            .into_iter()
18247            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18248            .collect::<Vec<_>>();
18249        self.fold_creases(ranges, true, window, cx);
18250    }
18251
18252    pub fn fold_ranges<T: ToOffset + Clone>(
18253        &mut self,
18254        ranges: Vec<Range<T>>,
18255        auto_scroll: bool,
18256        window: &mut Window,
18257        cx: &mut Context<Self>,
18258    ) {
18259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18260        let ranges = ranges
18261            .into_iter()
18262            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18263            .collect::<Vec<_>>();
18264        self.fold_creases(ranges, auto_scroll, window, cx);
18265    }
18266
18267    pub fn fold_creases<T: ToOffset + Clone>(
18268        &mut self,
18269        creases: Vec<Crease<T>>,
18270        auto_scroll: bool,
18271        _window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) {
18274        if creases.is_empty() {
18275            return;
18276        }
18277
18278        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18279
18280        if auto_scroll {
18281            self.request_autoscroll(Autoscroll::fit(), cx);
18282        }
18283
18284        cx.notify();
18285
18286        self.scrollbar_marker_state.dirty = true;
18287        self.folds_did_change(cx);
18288    }
18289
18290    /// Removes any folds whose ranges intersect any of the given ranges.
18291    pub fn unfold_ranges<T: ToOffset + Clone>(
18292        &mut self,
18293        ranges: &[Range<T>],
18294        inclusive: bool,
18295        auto_scroll: bool,
18296        cx: &mut Context<Self>,
18297    ) {
18298        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18299            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18300        });
18301        self.folds_did_change(cx);
18302    }
18303
18304    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18305        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18306            return;
18307        }
18308        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18309        self.display_map.update(cx, |display_map, cx| {
18310            display_map.fold_buffers([buffer_id], cx)
18311        });
18312        cx.emit(EditorEvent::BufferFoldToggled {
18313            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18314            folded: true,
18315        });
18316        cx.notify();
18317    }
18318
18319    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18320        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18321            return;
18322        }
18323        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18324        self.display_map.update(cx, |display_map, cx| {
18325            display_map.unfold_buffers([buffer_id], cx);
18326        });
18327        cx.emit(EditorEvent::BufferFoldToggled {
18328            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18329            folded: false,
18330        });
18331        cx.notify();
18332    }
18333
18334    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18335        self.display_map.read(cx).is_buffer_folded(buffer)
18336    }
18337
18338    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18339        self.display_map.read(cx).folded_buffers()
18340    }
18341
18342    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18343        self.display_map.update(cx, |display_map, cx| {
18344            display_map.disable_header_for_buffer(buffer_id, cx);
18345        });
18346        cx.notify();
18347    }
18348
18349    /// Removes any folds with the given ranges.
18350    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18351        &mut self,
18352        ranges: &[Range<T>],
18353        type_id: TypeId,
18354        auto_scroll: bool,
18355        cx: &mut Context<Self>,
18356    ) {
18357        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18358            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18359        });
18360        self.folds_did_change(cx);
18361    }
18362
18363    fn remove_folds_with<T: ToOffset + Clone>(
18364        &mut self,
18365        ranges: &[Range<T>],
18366        auto_scroll: bool,
18367        cx: &mut Context<Self>,
18368        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18369    ) {
18370        if ranges.is_empty() {
18371            return;
18372        }
18373
18374        let mut buffers_affected = HashSet::default();
18375        let multi_buffer = self.buffer().read(cx);
18376        for range in ranges {
18377            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18378                buffers_affected.insert(buffer.read(cx).remote_id());
18379            };
18380        }
18381
18382        self.display_map.update(cx, update);
18383
18384        if auto_scroll {
18385            self.request_autoscroll(Autoscroll::fit(), cx);
18386        }
18387
18388        cx.notify();
18389        self.scrollbar_marker_state.dirty = true;
18390        self.active_indent_guides_state.dirty = true;
18391    }
18392
18393    pub fn update_renderer_widths(
18394        &mut self,
18395        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18396        cx: &mut Context<Self>,
18397    ) -> bool {
18398        self.display_map
18399            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18400    }
18401
18402    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18403        self.display_map.read(cx).fold_placeholder.clone()
18404    }
18405
18406    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18407        self.buffer.update(cx, |buffer, cx| {
18408            buffer.set_all_diff_hunks_expanded(cx);
18409        });
18410    }
18411
18412    pub fn expand_all_diff_hunks(
18413        &mut self,
18414        _: &ExpandAllDiffHunks,
18415        _window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        self.buffer.update(cx, |buffer, cx| {
18419            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18420        });
18421    }
18422
18423    pub fn toggle_selected_diff_hunks(
18424        &mut self,
18425        _: &ToggleSelectedDiffHunks,
18426        _window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let ranges: Vec<_> = self
18430            .selections
18431            .disjoint_anchors()
18432            .iter()
18433            .map(|s| s.range())
18434            .collect();
18435        self.toggle_diff_hunks_in_ranges(ranges, cx);
18436    }
18437
18438    pub fn diff_hunks_in_ranges<'a>(
18439        &'a self,
18440        ranges: &'a [Range<Anchor>],
18441        buffer: &'a MultiBufferSnapshot,
18442    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18443        ranges.iter().flat_map(move |range| {
18444            let end_excerpt_id = range.end.excerpt_id;
18445            let range = range.to_point(buffer);
18446            let mut peek_end = range.end;
18447            if range.end.row < buffer.max_row().0 {
18448                peek_end = Point::new(range.end.row + 1, 0);
18449            }
18450            buffer
18451                .diff_hunks_in_range(range.start..peek_end)
18452                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18453        })
18454    }
18455
18456    pub fn has_stageable_diff_hunks_in_ranges(
18457        &self,
18458        ranges: &[Range<Anchor>],
18459        snapshot: &MultiBufferSnapshot,
18460    ) -> bool {
18461        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18462        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18463    }
18464
18465    pub fn toggle_staged_selected_diff_hunks(
18466        &mut self,
18467        _: &::git::ToggleStaged,
18468        _: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        let snapshot = self.buffer.read(cx).snapshot(cx);
18472        let ranges: Vec<_> = self
18473            .selections
18474            .disjoint_anchors()
18475            .iter()
18476            .map(|s| s.range())
18477            .collect();
18478        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18479        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18480    }
18481
18482    pub fn set_render_diff_hunk_controls(
18483        &mut self,
18484        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18485        cx: &mut Context<Self>,
18486    ) {
18487        self.render_diff_hunk_controls = render_diff_hunk_controls;
18488        cx.notify();
18489    }
18490
18491    pub fn stage_and_next(
18492        &mut self,
18493        _: &::git::StageAndNext,
18494        window: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) {
18497        self.do_stage_or_unstage_and_next(true, window, cx);
18498    }
18499
18500    pub fn unstage_and_next(
18501        &mut self,
18502        _: &::git::UnstageAndNext,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) {
18506        self.do_stage_or_unstage_and_next(false, window, cx);
18507    }
18508
18509    pub fn stage_or_unstage_diff_hunks(
18510        &mut self,
18511        stage: bool,
18512        ranges: Vec<Range<Anchor>>,
18513        cx: &mut Context<Self>,
18514    ) {
18515        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18516        cx.spawn(async move |this, cx| {
18517            task.await?;
18518            this.update(cx, |this, cx| {
18519                let snapshot = this.buffer.read(cx).snapshot(cx);
18520                let chunk_by = this
18521                    .diff_hunks_in_ranges(&ranges, &snapshot)
18522                    .chunk_by(|hunk| hunk.buffer_id);
18523                for (buffer_id, hunks) in &chunk_by {
18524                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18525                }
18526            })
18527        })
18528        .detach_and_log_err(cx);
18529    }
18530
18531    fn save_buffers_for_ranges_if_needed(
18532        &mut self,
18533        ranges: &[Range<Anchor>],
18534        cx: &mut Context<Editor>,
18535    ) -> Task<Result<()>> {
18536        let multibuffer = self.buffer.read(cx);
18537        let snapshot = multibuffer.read(cx);
18538        let buffer_ids: HashSet<_> = ranges
18539            .iter()
18540            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18541            .collect();
18542        drop(snapshot);
18543
18544        let mut buffers = HashSet::default();
18545        for buffer_id in buffer_ids {
18546            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18547                let buffer = buffer_entity.read(cx);
18548                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18549                {
18550                    buffers.insert(buffer_entity);
18551                }
18552            }
18553        }
18554
18555        if let Some(project) = &self.project {
18556            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18557        } else {
18558            Task::ready(Ok(()))
18559        }
18560    }
18561
18562    fn do_stage_or_unstage_and_next(
18563        &mut self,
18564        stage: bool,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18569
18570        if ranges.iter().any(|range| range.start != range.end) {
18571            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18572            return;
18573        }
18574
18575        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18576        let snapshot = self.snapshot(window, cx);
18577        let position = self.selections.newest::<Point>(cx).head();
18578        let mut row = snapshot
18579            .buffer_snapshot
18580            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18581            .find(|hunk| hunk.row_range.start.0 > position.row)
18582            .map(|hunk| hunk.row_range.start);
18583
18584        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18585        // Outside of the project diff editor, wrap around to the beginning.
18586        if !all_diff_hunks_expanded {
18587            row = row.or_else(|| {
18588                snapshot
18589                    .buffer_snapshot
18590                    .diff_hunks_in_range(Point::zero()..position)
18591                    .find(|hunk| hunk.row_range.end.0 < position.row)
18592                    .map(|hunk| hunk.row_range.start)
18593            });
18594        }
18595
18596        if let Some(row) = row {
18597            let destination = Point::new(row.0, 0);
18598            let autoscroll = Autoscroll::center();
18599
18600            self.unfold_ranges(&[destination..destination], false, false, cx);
18601            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18602                s.select_ranges([destination..destination]);
18603            });
18604        }
18605    }
18606
18607    fn do_stage_or_unstage(
18608        &self,
18609        stage: bool,
18610        buffer_id: BufferId,
18611        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18612        cx: &mut App,
18613    ) -> Option<()> {
18614        let project = self.project()?;
18615        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18616        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18617        let buffer_snapshot = buffer.read(cx).snapshot();
18618        let file_exists = buffer_snapshot
18619            .file()
18620            .is_some_and(|file| file.disk_state().exists());
18621        diff.update(cx, |diff, cx| {
18622            diff.stage_or_unstage_hunks(
18623                stage,
18624                &hunks
18625                    .map(|hunk| buffer_diff::DiffHunk {
18626                        buffer_range: hunk.buffer_range,
18627                        diff_base_byte_range: hunk.diff_base_byte_range,
18628                        secondary_status: hunk.secondary_status,
18629                        range: Point::zero()..Point::zero(), // unused
18630                    })
18631                    .collect::<Vec<_>>(),
18632                &buffer_snapshot,
18633                file_exists,
18634                cx,
18635            )
18636        });
18637        None
18638    }
18639
18640    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18641        let ranges: Vec<_> = self
18642            .selections
18643            .disjoint_anchors()
18644            .iter()
18645            .map(|s| s.range())
18646            .collect();
18647        self.buffer
18648            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18649    }
18650
18651    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18652        self.buffer.update(cx, |buffer, cx| {
18653            let ranges = vec![Anchor::min()..Anchor::max()];
18654            if !buffer.all_diff_hunks_expanded()
18655                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18656            {
18657                buffer.collapse_diff_hunks(ranges, cx);
18658                true
18659            } else {
18660                false
18661            }
18662        })
18663    }
18664
18665    fn toggle_diff_hunks_in_ranges(
18666        &mut self,
18667        ranges: Vec<Range<Anchor>>,
18668        cx: &mut Context<Editor>,
18669    ) {
18670        self.buffer.update(cx, |buffer, cx| {
18671            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18672            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18673        })
18674    }
18675
18676    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18677        self.buffer.update(cx, |buffer, cx| {
18678            let snapshot = buffer.snapshot(cx);
18679            let excerpt_id = range.end.excerpt_id;
18680            let point_range = range.to_point(&snapshot);
18681            let expand = !buffer.single_hunk_is_expanded(range, cx);
18682            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18683        })
18684    }
18685
18686    pub(crate) fn apply_all_diff_hunks(
18687        &mut self,
18688        _: &ApplyAllDiffHunks,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18693
18694        let buffers = self.buffer.read(cx).all_buffers();
18695        for branch_buffer in buffers {
18696            branch_buffer.update(cx, |branch_buffer, cx| {
18697                branch_buffer.merge_into_base(Vec::new(), cx);
18698            });
18699        }
18700
18701        if let Some(project) = self.project.clone() {
18702            self.save(
18703                SaveOptions {
18704                    format: true,
18705                    autosave: false,
18706                },
18707                project,
18708                window,
18709                cx,
18710            )
18711            .detach_and_log_err(cx);
18712        }
18713    }
18714
18715    pub(crate) fn apply_selected_diff_hunks(
18716        &mut self,
18717        _: &ApplyDiffHunk,
18718        window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) {
18721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18722        let snapshot = self.snapshot(window, cx);
18723        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18724        let mut ranges_by_buffer = HashMap::default();
18725        self.transact(window, cx, |editor, _window, cx| {
18726            for hunk in hunks {
18727                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18728                    ranges_by_buffer
18729                        .entry(buffer.clone())
18730                        .or_insert_with(Vec::new)
18731                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18732                }
18733            }
18734
18735            for (buffer, ranges) in ranges_by_buffer {
18736                buffer.update(cx, |buffer, cx| {
18737                    buffer.merge_into_base(ranges, cx);
18738                });
18739            }
18740        });
18741
18742        if let Some(project) = self.project.clone() {
18743            self.save(
18744                SaveOptions {
18745                    format: true,
18746                    autosave: false,
18747                },
18748                project,
18749                window,
18750                cx,
18751            )
18752            .detach_and_log_err(cx);
18753        }
18754    }
18755
18756    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18757        if hovered != self.gutter_hovered {
18758            self.gutter_hovered = hovered;
18759            cx.notify();
18760        }
18761    }
18762
18763    pub fn insert_blocks(
18764        &mut self,
18765        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18766        autoscroll: Option<Autoscroll>,
18767        cx: &mut Context<Self>,
18768    ) -> Vec<CustomBlockId> {
18769        let blocks = self
18770            .display_map
18771            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18772        if let Some(autoscroll) = autoscroll {
18773            self.request_autoscroll(autoscroll, cx);
18774        }
18775        cx.notify();
18776        blocks
18777    }
18778
18779    pub fn resize_blocks(
18780        &mut self,
18781        heights: HashMap<CustomBlockId, u32>,
18782        autoscroll: Option<Autoscroll>,
18783        cx: &mut Context<Self>,
18784    ) {
18785        self.display_map
18786            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18787        if let Some(autoscroll) = autoscroll {
18788            self.request_autoscroll(autoscroll, cx);
18789        }
18790        cx.notify();
18791    }
18792
18793    pub fn replace_blocks(
18794        &mut self,
18795        renderers: HashMap<CustomBlockId, RenderBlock>,
18796        autoscroll: Option<Autoscroll>,
18797        cx: &mut Context<Self>,
18798    ) {
18799        self.display_map
18800            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18801        if let Some(autoscroll) = autoscroll {
18802            self.request_autoscroll(autoscroll, cx);
18803        }
18804        cx.notify();
18805    }
18806
18807    pub fn remove_blocks(
18808        &mut self,
18809        block_ids: HashSet<CustomBlockId>,
18810        autoscroll: Option<Autoscroll>,
18811        cx: &mut Context<Self>,
18812    ) {
18813        self.display_map.update(cx, |display_map, cx| {
18814            display_map.remove_blocks(block_ids, cx)
18815        });
18816        if let Some(autoscroll) = autoscroll {
18817            self.request_autoscroll(autoscroll, cx);
18818        }
18819        cx.notify();
18820    }
18821
18822    pub fn row_for_block(
18823        &self,
18824        block_id: CustomBlockId,
18825        cx: &mut Context<Self>,
18826    ) -> Option<DisplayRow> {
18827        self.display_map
18828            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18829    }
18830
18831    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18832        self.focused_block = Some(focused_block);
18833    }
18834
18835    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18836        self.focused_block.take()
18837    }
18838
18839    pub fn insert_creases(
18840        &mut self,
18841        creases: impl IntoIterator<Item = Crease<Anchor>>,
18842        cx: &mut Context<Self>,
18843    ) -> Vec<CreaseId> {
18844        self.display_map
18845            .update(cx, |map, cx| map.insert_creases(creases, cx))
18846    }
18847
18848    pub fn remove_creases(
18849        &mut self,
18850        ids: impl IntoIterator<Item = CreaseId>,
18851        cx: &mut Context<Self>,
18852    ) -> Vec<(CreaseId, Range<Anchor>)> {
18853        self.display_map
18854            .update(cx, |map, cx| map.remove_creases(ids, cx))
18855    }
18856
18857    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18858        self.display_map
18859            .update(cx, |map, cx| map.snapshot(cx))
18860            .longest_row()
18861    }
18862
18863    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18864        self.display_map
18865            .update(cx, |map, cx| map.snapshot(cx))
18866            .max_point()
18867    }
18868
18869    pub fn text(&self, cx: &App) -> String {
18870        self.buffer.read(cx).read(cx).text()
18871    }
18872
18873    pub fn is_empty(&self, cx: &App) -> bool {
18874        self.buffer.read(cx).read(cx).is_empty()
18875    }
18876
18877    pub fn text_option(&self, cx: &App) -> Option<String> {
18878        let text = self.text(cx);
18879        let text = text.trim();
18880
18881        if text.is_empty() {
18882            return None;
18883        }
18884
18885        Some(text.to_string())
18886    }
18887
18888    pub fn set_text(
18889        &mut self,
18890        text: impl Into<Arc<str>>,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) {
18894        self.transact(window, cx, |this, _, cx| {
18895            this.buffer
18896                .read(cx)
18897                .as_singleton()
18898                .expect("you can only call set_text on editors for singleton buffers")
18899                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18900        });
18901    }
18902
18903    pub fn display_text(&self, cx: &mut App) -> String {
18904        self.display_map
18905            .update(cx, |map, cx| map.snapshot(cx))
18906            .text()
18907    }
18908
18909    fn create_minimap(
18910        &self,
18911        minimap_settings: MinimapSettings,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) -> Option<Entity<Self>> {
18915        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18916            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18917    }
18918
18919    fn initialize_new_minimap(
18920        &self,
18921        minimap_settings: MinimapSettings,
18922        window: &mut Window,
18923        cx: &mut Context<Self>,
18924    ) -> Entity<Self> {
18925        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18926
18927        let mut minimap = Editor::new_internal(
18928            EditorMode::Minimap {
18929                parent: cx.weak_entity(),
18930            },
18931            self.buffer.clone(),
18932            None,
18933            Some(self.display_map.clone()),
18934            window,
18935            cx,
18936        );
18937        minimap.scroll_manager.clone_state(&self.scroll_manager);
18938        minimap.set_text_style_refinement(TextStyleRefinement {
18939            font_size: Some(MINIMAP_FONT_SIZE),
18940            font_weight: Some(MINIMAP_FONT_WEIGHT),
18941            ..Default::default()
18942        });
18943        minimap.update_minimap_configuration(minimap_settings, cx);
18944        cx.new(|_| minimap)
18945    }
18946
18947    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18948        let current_line_highlight = minimap_settings
18949            .current_line_highlight
18950            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18951        self.set_current_line_highlight(Some(current_line_highlight));
18952    }
18953
18954    pub fn minimap(&self) -> Option<&Entity<Self>> {
18955        self.minimap
18956            .as_ref()
18957            .filter(|_| self.minimap_visibility.visible())
18958    }
18959
18960    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18961        let mut wrap_guides = smallvec![];
18962
18963        if self.show_wrap_guides == Some(false) {
18964            return wrap_guides;
18965        }
18966
18967        let settings = self.buffer.read(cx).language_settings(cx);
18968        if settings.show_wrap_guides {
18969            match self.soft_wrap_mode(cx) {
18970                SoftWrap::Column(soft_wrap) => {
18971                    wrap_guides.push((soft_wrap as usize, true));
18972                }
18973                SoftWrap::Bounded(soft_wrap) => {
18974                    wrap_guides.push((soft_wrap as usize, true));
18975                }
18976                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18977            }
18978            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18979        }
18980
18981        wrap_guides
18982    }
18983
18984    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18985        let settings = self.buffer.read(cx).language_settings(cx);
18986        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18987        match mode {
18988            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18989                SoftWrap::None
18990            }
18991            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18992            language_settings::SoftWrap::PreferredLineLength => {
18993                SoftWrap::Column(settings.preferred_line_length)
18994            }
18995            language_settings::SoftWrap::Bounded => {
18996                SoftWrap::Bounded(settings.preferred_line_length)
18997            }
18998        }
18999    }
19000
19001    pub fn set_soft_wrap_mode(
19002        &mut self,
19003        mode: language_settings::SoftWrap,
19004
19005        cx: &mut Context<Self>,
19006    ) {
19007        self.soft_wrap_mode_override = Some(mode);
19008        cx.notify();
19009    }
19010
19011    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19012        self.hard_wrap = hard_wrap;
19013        cx.notify();
19014    }
19015
19016    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19017        self.text_style_refinement = Some(style);
19018    }
19019
19020    /// called by the Element so we know what style we were most recently rendered with.
19021    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19022        // We intentionally do not inform the display map about the minimap style
19023        // so that wrapping is not recalculated and stays consistent for the editor
19024        // and its linked minimap.
19025        if !self.mode.is_minimap() {
19026            let font = style.text.font();
19027            let font_size = style.text.font_size.to_pixels(window.rem_size());
19028            let display_map = self
19029                .placeholder_display_map
19030                .as_ref()
19031                .filter(|_| self.is_empty(cx))
19032                .unwrap_or(&self.display_map);
19033
19034            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19035        }
19036        self.style = Some(style);
19037    }
19038
19039    pub fn style(&self) -> Option<&EditorStyle> {
19040        self.style.as_ref()
19041    }
19042
19043    // Called by the element. This method is not designed to be called outside of the editor
19044    // element's layout code because it does not notify when rewrapping is computed synchronously.
19045    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19046        if self.is_empty(cx) {
19047            self.placeholder_display_map
19048                .as_ref()
19049                .map_or(false, |display_map| {
19050                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19051                })
19052        } else {
19053            self.display_map
19054                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19055        }
19056    }
19057
19058    pub fn set_soft_wrap(&mut self) {
19059        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19060    }
19061
19062    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19063        if self.soft_wrap_mode_override.is_some() {
19064            self.soft_wrap_mode_override.take();
19065        } else {
19066            let soft_wrap = match self.soft_wrap_mode(cx) {
19067                SoftWrap::GitDiff => return,
19068                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19069                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19070                    language_settings::SoftWrap::None
19071                }
19072            };
19073            self.soft_wrap_mode_override = Some(soft_wrap);
19074        }
19075        cx.notify();
19076    }
19077
19078    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19079        let Some(workspace) = self.workspace() else {
19080            return;
19081        };
19082        let fs = workspace.read(cx).app_state().fs.clone();
19083        let current_show = TabBarSettings::get_global(cx).show;
19084        update_settings_file(fs, cx, move |setting, _| {
19085            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19086        });
19087    }
19088
19089    pub fn toggle_indent_guides(
19090        &mut self,
19091        _: &ToggleIndentGuides,
19092        _: &mut Window,
19093        cx: &mut Context<Self>,
19094    ) {
19095        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19096            self.buffer
19097                .read(cx)
19098                .language_settings(cx)
19099                .indent_guides
19100                .enabled
19101        });
19102        self.show_indent_guides = Some(!currently_enabled);
19103        cx.notify();
19104    }
19105
19106    fn should_show_indent_guides(&self) -> Option<bool> {
19107        self.show_indent_guides
19108    }
19109
19110    pub fn toggle_line_numbers(
19111        &mut self,
19112        _: &ToggleLineNumbers,
19113        _: &mut Window,
19114        cx: &mut Context<Self>,
19115    ) {
19116        let mut editor_settings = EditorSettings::get_global(cx).clone();
19117        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19118        EditorSettings::override_global(editor_settings, cx);
19119    }
19120
19121    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19122        if let Some(show_line_numbers) = self.show_line_numbers {
19123            return show_line_numbers;
19124        }
19125        EditorSettings::get_global(cx).gutter.line_numbers
19126    }
19127
19128    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19129        self.use_relative_line_numbers
19130            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19131    }
19132
19133    pub fn toggle_relative_line_numbers(
19134        &mut self,
19135        _: &ToggleRelativeLineNumbers,
19136        _: &mut Window,
19137        cx: &mut Context<Self>,
19138    ) {
19139        let is_relative = self.should_use_relative_line_numbers(cx);
19140        self.set_relative_line_number(Some(!is_relative), cx)
19141    }
19142
19143    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19144        self.use_relative_line_numbers = is_relative;
19145        cx.notify();
19146    }
19147
19148    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19149        self.show_gutter = show_gutter;
19150        cx.notify();
19151    }
19152
19153    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19154        self.show_scrollbars = ScrollbarAxes {
19155            horizontal: show,
19156            vertical: show,
19157        };
19158        cx.notify();
19159    }
19160
19161    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19162        self.show_scrollbars.vertical = show;
19163        cx.notify();
19164    }
19165
19166    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19167        self.show_scrollbars.horizontal = show;
19168        cx.notify();
19169    }
19170
19171    pub fn set_minimap_visibility(
19172        &mut self,
19173        minimap_visibility: MinimapVisibility,
19174        window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        if self.minimap_visibility != minimap_visibility {
19178            if minimap_visibility.visible() && self.minimap.is_none() {
19179                let minimap_settings = EditorSettings::get_global(cx).minimap;
19180                self.minimap =
19181                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19182            }
19183            self.minimap_visibility = minimap_visibility;
19184            cx.notify();
19185        }
19186    }
19187
19188    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19189        self.set_show_scrollbars(false, cx);
19190        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19191    }
19192
19193    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19194        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19195    }
19196
19197    /// Normally the text in full mode and auto height editors is padded on the
19198    /// left side by roughly half a character width for improved hit testing.
19199    ///
19200    /// Use this method to disable this for cases where this is not wanted (e.g.
19201    /// if you want to align the editor text with some other text above or below)
19202    /// or if you want to add this padding to single-line editors.
19203    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19204        self.offset_content = offset_content;
19205        cx.notify();
19206    }
19207
19208    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19209        self.show_line_numbers = Some(show_line_numbers);
19210        cx.notify();
19211    }
19212
19213    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19214        self.disable_expand_excerpt_buttons = true;
19215        cx.notify();
19216    }
19217
19218    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19219        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19220        cx.notify();
19221    }
19222
19223    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19224        self.show_code_actions = Some(show_code_actions);
19225        cx.notify();
19226    }
19227
19228    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19229        self.show_runnables = Some(show_runnables);
19230        cx.notify();
19231    }
19232
19233    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19234        self.show_breakpoints = Some(show_breakpoints);
19235        cx.notify();
19236    }
19237
19238    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19239        if self.display_map.read(cx).masked != masked {
19240            self.display_map.update(cx, |map, _| map.masked = masked);
19241        }
19242        cx.notify()
19243    }
19244
19245    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19246        self.show_wrap_guides = Some(show_wrap_guides);
19247        cx.notify();
19248    }
19249
19250    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19251        self.show_indent_guides = Some(show_indent_guides);
19252        cx.notify();
19253    }
19254
19255    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19256        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19257            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19258                && let Some(dir) = file.abs_path(cx).parent()
19259            {
19260                return Some(dir.to_owned());
19261            }
19262
19263            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19264                return Some(project_path.path.to_path_buf());
19265            }
19266        }
19267
19268        None
19269    }
19270
19271    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19272        self.active_excerpt(cx)?
19273            .1
19274            .read(cx)
19275            .file()
19276            .and_then(|f| f.as_local())
19277    }
19278
19279    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19280        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19281            let buffer = buffer.read(cx);
19282            if let Some(project_path) = buffer.project_path(cx) {
19283                let project = self.project()?.read(cx);
19284                project.absolute_path(&project_path, cx)
19285            } else {
19286                buffer
19287                    .file()
19288                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19289            }
19290        })
19291    }
19292
19293    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19294        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19295            let project_path = buffer.read(cx).project_path(cx)?;
19296            let project = self.project()?.read(cx);
19297            let entry = project.entry_for_path(&project_path, cx)?;
19298            let path = entry.path.to_path_buf();
19299            Some(path)
19300        })
19301    }
19302
19303    pub fn reveal_in_finder(
19304        &mut self,
19305        _: &RevealInFileManager,
19306        _window: &mut Window,
19307        cx: &mut Context<Self>,
19308    ) {
19309        if let Some(target) = self.target_file(cx) {
19310            cx.reveal_path(&target.abs_path(cx));
19311        }
19312    }
19313
19314    pub fn copy_path(
19315        &mut self,
19316        _: &zed_actions::workspace::CopyPath,
19317        _window: &mut Window,
19318        cx: &mut Context<Self>,
19319    ) {
19320        if let Some(path) = self.target_file_abs_path(cx)
19321            && let Some(path) = path.to_str()
19322        {
19323            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19324        } else {
19325            cx.propagate();
19326        }
19327    }
19328
19329    pub fn copy_relative_path(
19330        &mut self,
19331        _: &zed_actions::workspace::CopyRelativePath,
19332        _window: &mut Window,
19333        cx: &mut Context<Self>,
19334    ) {
19335        if let Some(path) = self.target_file_path(cx)
19336            && let Some(path) = path.to_str()
19337        {
19338            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19339        } else {
19340            cx.propagate();
19341        }
19342    }
19343
19344    /// Returns the project path for the editor's buffer, if any buffer is
19345    /// opened in the editor.
19346    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19347        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19348            buffer.read(cx).project_path(cx)
19349        } else {
19350            None
19351        }
19352    }
19353
19354    // Returns true if the editor handled a go-to-line request
19355    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19356        maybe!({
19357            let breakpoint_store = self.breakpoint_store.as_ref()?;
19358
19359            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19360            else {
19361                self.clear_row_highlights::<ActiveDebugLine>();
19362                return None;
19363            };
19364
19365            let position = active_stack_frame.position;
19366            let buffer_id = position.buffer_id?;
19367            let snapshot = self
19368                .project
19369                .as_ref()?
19370                .read(cx)
19371                .buffer_for_id(buffer_id, cx)?
19372                .read(cx)
19373                .snapshot();
19374
19375            let mut handled = false;
19376            for (id, ExcerptRange { context, .. }) in
19377                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19378            {
19379                if context.start.cmp(&position, &snapshot).is_ge()
19380                    || context.end.cmp(&position, &snapshot).is_lt()
19381                {
19382                    continue;
19383                }
19384                let snapshot = self.buffer.read(cx).snapshot(cx);
19385                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19386
19387                handled = true;
19388                self.clear_row_highlights::<ActiveDebugLine>();
19389
19390                self.go_to_line::<ActiveDebugLine>(
19391                    multibuffer_anchor,
19392                    Some(cx.theme().colors().editor_debugger_active_line_background),
19393                    window,
19394                    cx,
19395                );
19396
19397                cx.notify();
19398            }
19399
19400            handled.then_some(())
19401        })
19402        .is_some()
19403    }
19404
19405    pub fn copy_file_name_without_extension(
19406        &mut self,
19407        _: &CopyFileNameWithoutExtension,
19408        _: &mut Window,
19409        cx: &mut Context<Self>,
19410    ) {
19411        if let Some(file) = self.target_file(cx)
19412            && let Some(file_stem) = file.path().file_stem()
19413            && let Some(name) = file_stem.to_str()
19414        {
19415            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19416        }
19417    }
19418
19419    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19420        if let Some(file) = self.target_file(cx)
19421            && let Some(file_name) = file.path().file_name()
19422            && let Some(name) = file_name.to_str()
19423        {
19424            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19425        }
19426    }
19427
19428    pub fn toggle_git_blame(
19429        &mut self,
19430        _: &::git::Blame,
19431        window: &mut Window,
19432        cx: &mut Context<Self>,
19433    ) {
19434        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19435
19436        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19437            self.start_git_blame(true, window, cx);
19438        }
19439
19440        cx.notify();
19441    }
19442
19443    pub fn toggle_git_blame_inline(
19444        &mut self,
19445        _: &ToggleGitBlameInline,
19446        window: &mut Window,
19447        cx: &mut Context<Self>,
19448    ) {
19449        self.toggle_git_blame_inline_internal(true, window, cx);
19450        cx.notify();
19451    }
19452
19453    pub fn open_git_blame_commit(
19454        &mut self,
19455        _: &OpenGitBlameCommit,
19456        window: &mut Window,
19457        cx: &mut Context<Self>,
19458    ) {
19459        self.open_git_blame_commit_internal(window, cx);
19460    }
19461
19462    fn open_git_blame_commit_internal(
19463        &mut self,
19464        window: &mut Window,
19465        cx: &mut Context<Self>,
19466    ) -> Option<()> {
19467        let blame = self.blame.as_ref()?;
19468        let snapshot = self.snapshot(window, cx);
19469        let cursor = self.selections.newest::<Point>(cx).head();
19470        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19471        let (_, blame_entry) = blame
19472            .update(cx, |blame, cx| {
19473                blame
19474                    .blame_for_rows(
19475                        &[RowInfo {
19476                            buffer_id: Some(buffer.remote_id()),
19477                            buffer_row: Some(point.row),
19478                            ..Default::default()
19479                        }],
19480                        cx,
19481                    )
19482                    .next()
19483            })
19484            .flatten()?;
19485        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19486        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19487        let workspace = self.workspace()?.downgrade();
19488        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19489        None
19490    }
19491
19492    pub fn git_blame_inline_enabled(&self) -> bool {
19493        self.git_blame_inline_enabled
19494    }
19495
19496    pub fn toggle_selection_menu(
19497        &mut self,
19498        _: &ToggleSelectionMenu,
19499        _: &mut Window,
19500        cx: &mut Context<Self>,
19501    ) {
19502        self.show_selection_menu = self
19503            .show_selection_menu
19504            .map(|show_selections_menu| !show_selections_menu)
19505            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19506
19507        cx.notify();
19508    }
19509
19510    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19511        self.show_selection_menu
19512            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19513    }
19514
19515    fn start_git_blame(
19516        &mut self,
19517        user_triggered: bool,
19518        window: &mut Window,
19519        cx: &mut Context<Self>,
19520    ) {
19521        if let Some(project) = self.project() {
19522            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19523                && buffer.read(cx).file().is_none()
19524            {
19525                return;
19526            }
19527
19528            let focused = self.focus_handle(cx).contains_focused(window, cx);
19529
19530            let project = project.clone();
19531            let blame = cx
19532                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19533            self.blame_subscription =
19534                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19535            self.blame = Some(blame);
19536        }
19537    }
19538
19539    fn toggle_git_blame_inline_internal(
19540        &mut self,
19541        user_triggered: bool,
19542        window: &mut Window,
19543        cx: &mut Context<Self>,
19544    ) {
19545        if self.git_blame_inline_enabled {
19546            self.git_blame_inline_enabled = false;
19547            self.show_git_blame_inline = false;
19548            self.show_git_blame_inline_delay_task.take();
19549        } else {
19550            self.git_blame_inline_enabled = true;
19551            self.start_git_blame_inline(user_triggered, window, cx);
19552        }
19553
19554        cx.notify();
19555    }
19556
19557    fn start_git_blame_inline(
19558        &mut self,
19559        user_triggered: bool,
19560        window: &mut Window,
19561        cx: &mut Context<Self>,
19562    ) {
19563        self.start_git_blame(user_triggered, window, cx);
19564
19565        if ProjectSettings::get_global(cx)
19566            .git
19567            .inline_blame_delay()
19568            .is_some()
19569        {
19570            self.start_inline_blame_timer(window, cx);
19571        } else {
19572            self.show_git_blame_inline = true
19573        }
19574    }
19575
19576    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19577        self.blame.as_ref()
19578    }
19579
19580    pub fn show_git_blame_gutter(&self) -> bool {
19581        self.show_git_blame_gutter
19582    }
19583
19584    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19585        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19586    }
19587
19588    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19589        self.show_git_blame_inline
19590            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19591            && !self.newest_selection_head_on_empty_line(cx)
19592            && self.has_blame_entries(cx)
19593    }
19594
19595    fn has_blame_entries(&self, cx: &App) -> bool {
19596        self.blame()
19597            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19598    }
19599
19600    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19601        let cursor_anchor = self.selections.newest_anchor().head();
19602
19603        let snapshot = self.buffer.read(cx).snapshot(cx);
19604        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19605
19606        snapshot.line_len(buffer_row) == 0
19607    }
19608
19609    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19610        let buffer_and_selection = maybe!({
19611            let selection = self.selections.newest::<Point>(cx);
19612            let selection_range = selection.range();
19613
19614            let multi_buffer = self.buffer().read(cx);
19615            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19616            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19617
19618            let (buffer, range, _) = if selection.reversed {
19619                buffer_ranges.first()
19620            } else {
19621                buffer_ranges.last()
19622            }?;
19623
19624            let selection = text::ToPoint::to_point(&range.start, buffer).row
19625                ..text::ToPoint::to_point(&range.end, buffer).row;
19626            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19627        });
19628
19629        let Some((buffer, selection)) = buffer_and_selection else {
19630            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19631        };
19632
19633        let Some(project) = self.project() else {
19634            return Task::ready(Err(anyhow!("editor does not have project")));
19635        };
19636
19637        project.update(cx, |project, cx| {
19638            project.get_permalink_to_line(&buffer, selection, cx)
19639        })
19640    }
19641
19642    pub fn copy_permalink_to_line(
19643        &mut self,
19644        _: &CopyPermalinkToLine,
19645        window: &mut Window,
19646        cx: &mut Context<Self>,
19647    ) {
19648        let permalink_task = self.get_permalink_to_line(cx);
19649        let workspace = self.workspace();
19650
19651        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19652            Ok(permalink) => {
19653                cx.update(|_, cx| {
19654                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19655                })
19656                .ok();
19657            }
19658            Err(err) => {
19659                let message = format!("Failed to copy permalink: {err}");
19660
19661                anyhow::Result::<()>::Err(err).log_err();
19662
19663                if let Some(workspace) = workspace {
19664                    workspace
19665                        .update_in(cx, |workspace, _, cx| {
19666                            struct CopyPermalinkToLine;
19667
19668                            workspace.show_toast(
19669                                Toast::new(
19670                                    NotificationId::unique::<CopyPermalinkToLine>(),
19671                                    message,
19672                                ),
19673                                cx,
19674                            )
19675                        })
19676                        .ok();
19677                }
19678            }
19679        })
19680        .detach();
19681    }
19682
19683    pub fn copy_file_location(
19684        &mut self,
19685        _: &CopyFileLocation,
19686        _: &mut Window,
19687        cx: &mut Context<Self>,
19688    ) {
19689        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19690        if let Some(file) = self.target_file(cx)
19691            && let Some(path) = file.path().to_str()
19692        {
19693            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19694        }
19695    }
19696
19697    pub fn open_permalink_to_line(
19698        &mut self,
19699        _: &OpenPermalinkToLine,
19700        window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        let permalink_task = self.get_permalink_to_line(cx);
19704        let workspace = self.workspace();
19705
19706        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19707            Ok(permalink) => {
19708                cx.update(|_, cx| {
19709                    cx.open_url(permalink.as_ref());
19710                })
19711                .ok();
19712            }
19713            Err(err) => {
19714                let message = format!("Failed to open permalink: {err}");
19715
19716                anyhow::Result::<()>::Err(err).log_err();
19717
19718                if let Some(workspace) = workspace {
19719                    workspace
19720                        .update(cx, |workspace, cx| {
19721                            struct OpenPermalinkToLine;
19722
19723                            workspace.show_toast(
19724                                Toast::new(
19725                                    NotificationId::unique::<OpenPermalinkToLine>(),
19726                                    message,
19727                                ),
19728                                cx,
19729                            )
19730                        })
19731                        .ok();
19732                }
19733            }
19734        })
19735        .detach();
19736    }
19737
19738    pub fn insert_uuid_v4(
19739        &mut self,
19740        _: &InsertUuidV4,
19741        window: &mut Window,
19742        cx: &mut Context<Self>,
19743    ) {
19744        self.insert_uuid(UuidVersion::V4, window, cx);
19745    }
19746
19747    pub fn insert_uuid_v7(
19748        &mut self,
19749        _: &InsertUuidV7,
19750        window: &mut Window,
19751        cx: &mut Context<Self>,
19752    ) {
19753        self.insert_uuid(UuidVersion::V7, window, cx);
19754    }
19755
19756    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19758        self.transact(window, cx, |this, window, cx| {
19759            let edits = this
19760                .selections
19761                .all::<Point>(cx)
19762                .into_iter()
19763                .map(|selection| {
19764                    let uuid = match version {
19765                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19766                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19767                    };
19768
19769                    (selection.range(), uuid.to_string())
19770                });
19771            this.edit(edits, cx);
19772            this.refresh_edit_prediction(true, false, window, cx);
19773        });
19774    }
19775
19776    pub fn open_selections_in_multibuffer(
19777        &mut self,
19778        _: &OpenSelectionsInMultibuffer,
19779        window: &mut Window,
19780        cx: &mut Context<Self>,
19781    ) {
19782        let multibuffer = self.buffer.read(cx);
19783
19784        let Some(buffer) = multibuffer.as_singleton() else {
19785            return;
19786        };
19787
19788        let Some(workspace) = self.workspace() else {
19789            return;
19790        };
19791
19792        let title = multibuffer.title(cx).to_string();
19793
19794        let locations = self
19795            .selections
19796            .all_anchors(cx)
19797            .iter()
19798            .map(|selection| {
19799                (
19800                    buffer.clone(),
19801                    (selection.start.text_anchor..selection.end.text_anchor)
19802                        .to_point(buffer.read(cx)),
19803                )
19804            })
19805            .into_group_map();
19806
19807        cx.spawn_in(window, async move |_, cx| {
19808            workspace.update_in(cx, |workspace, window, cx| {
19809                Self::open_locations_in_multibuffer(
19810                    workspace,
19811                    locations,
19812                    format!("Selections for '{title}'"),
19813                    false,
19814                    MultibufferSelectionMode::All,
19815                    window,
19816                    cx,
19817                );
19818            })
19819        })
19820        .detach();
19821    }
19822
19823    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19824    /// last highlight added will be used.
19825    ///
19826    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19827    pub fn highlight_rows<T: 'static>(
19828        &mut self,
19829        range: Range<Anchor>,
19830        color: Hsla,
19831        options: RowHighlightOptions,
19832        cx: &mut Context<Self>,
19833    ) {
19834        let snapshot = self.buffer().read(cx).snapshot(cx);
19835        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19836        let ix = row_highlights.binary_search_by(|highlight| {
19837            Ordering::Equal
19838                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19839                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19840        });
19841
19842        if let Err(mut ix) = ix {
19843            let index = post_inc(&mut self.highlight_order);
19844
19845            // If this range intersects with the preceding highlight, then merge it with
19846            // the preceding highlight. Otherwise insert a new highlight.
19847            let mut merged = false;
19848            if ix > 0 {
19849                let prev_highlight = &mut row_highlights[ix - 1];
19850                if prev_highlight
19851                    .range
19852                    .end
19853                    .cmp(&range.start, &snapshot)
19854                    .is_ge()
19855                {
19856                    ix -= 1;
19857                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19858                        prev_highlight.range.end = range.end;
19859                    }
19860                    merged = true;
19861                    prev_highlight.index = index;
19862                    prev_highlight.color = color;
19863                    prev_highlight.options = options;
19864                }
19865            }
19866
19867            if !merged {
19868                row_highlights.insert(
19869                    ix,
19870                    RowHighlight {
19871                        range,
19872                        index,
19873                        color,
19874                        options,
19875                        type_id: TypeId::of::<T>(),
19876                    },
19877                );
19878            }
19879
19880            // If any of the following highlights intersect with this one, merge them.
19881            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19882                let highlight = &row_highlights[ix];
19883                if next_highlight
19884                    .range
19885                    .start
19886                    .cmp(&highlight.range.end, &snapshot)
19887                    .is_le()
19888                {
19889                    if next_highlight
19890                        .range
19891                        .end
19892                        .cmp(&highlight.range.end, &snapshot)
19893                        .is_gt()
19894                    {
19895                        row_highlights[ix].range.end = next_highlight.range.end;
19896                    }
19897                    row_highlights.remove(ix + 1);
19898                } else {
19899                    break;
19900                }
19901            }
19902        }
19903    }
19904
19905    /// Remove any highlighted row ranges of the given type that intersect the
19906    /// given ranges.
19907    pub fn remove_highlighted_rows<T: 'static>(
19908        &mut self,
19909        ranges_to_remove: Vec<Range<Anchor>>,
19910        cx: &mut Context<Self>,
19911    ) {
19912        let snapshot = self.buffer().read(cx).snapshot(cx);
19913        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19914        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19915        row_highlights.retain(|highlight| {
19916            while let Some(range_to_remove) = ranges_to_remove.peek() {
19917                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19918                    Ordering::Less | Ordering::Equal => {
19919                        ranges_to_remove.next();
19920                    }
19921                    Ordering::Greater => {
19922                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19923                            Ordering::Less | Ordering::Equal => {
19924                                return false;
19925                            }
19926                            Ordering::Greater => break,
19927                        }
19928                    }
19929                }
19930            }
19931
19932            true
19933        })
19934    }
19935
19936    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19937    pub fn clear_row_highlights<T: 'static>(&mut self) {
19938        self.highlighted_rows.remove(&TypeId::of::<T>());
19939    }
19940
19941    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19942    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19943        self.highlighted_rows
19944            .get(&TypeId::of::<T>())
19945            .map_or(&[] as &[_], |vec| vec.as_slice())
19946            .iter()
19947            .map(|highlight| (highlight.range.clone(), highlight.color))
19948    }
19949
19950    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19951    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19952    /// Allows to ignore certain kinds of highlights.
19953    pub fn highlighted_display_rows(
19954        &self,
19955        window: &mut Window,
19956        cx: &mut App,
19957    ) -> BTreeMap<DisplayRow, LineHighlight> {
19958        let snapshot = self.snapshot(window, cx);
19959        let mut used_highlight_orders = HashMap::default();
19960        self.highlighted_rows
19961            .iter()
19962            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19963            .fold(
19964                BTreeMap::<DisplayRow, LineHighlight>::new(),
19965                |mut unique_rows, highlight| {
19966                    let start = highlight.range.start.to_display_point(&snapshot);
19967                    let end = highlight.range.end.to_display_point(&snapshot);
19968                    let start_row = start.row().0;
19969                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19970                        && end.column() == 0
19971                    {
19972                        end.row().0.saturating_sub(1)
19973                    } else {
19974                        end.row().0
19975                    };
19976                    for row in start_row..=end_row {
19977                        let used_index =
19978                            used_highlight_orders.entry(row).or_insert(highlight.index);
19979                        if highlight.index >= *used_index {
19980                            *used_index = highlight.index;
19981                            unique_rows.insert(
19982                                DisplayRow(row),
19983                                LineHighlight {
19984                                    include_gutter: highlight.options.include_gutter,
19985                                    border: None,
19986                                    background: highlight.color.into(),
19987                                    type_id: Some(highlight.type_id),
19988                                },
19989                            );
19990                        }
19991                    }
19992                    unique_rows
19993                },
19994            )
19995    }
19996
19997    pub fn highlighted_display_row_for_autoscroll(
19998        &self,
19999        snapshot: &DisplaySnapshot,
20000    ) -> Option<DisplayRow> {
20001        self.highlighted_rows
20002            .values()
20003            .flat_map(|highlighted_rows| highlighted_rows.iter())
20004            .filter_map(|highlight| {
20005                if highlight.options.autoscroll {
20006                    Some(highlight.range.start.to_display_point(snapshot).row())
20007                } else {
20008                    None
20009                }
20010            })
20011            .min()
20012    }
20013
20014    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20015        self.highlight_background::<SearchWithinRange>(
20016            ranges,
20017            |colors| colors.colors().editor_document_highlight_read_background,
20018            cx,
20019        )
20020    }
20021
20022    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20023        self.breadcrumb_header = Some(new_header);
20024    }
20025
20026    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20027        self.clear_background_highlights::<SearchWithinRange>(cx);
20028    }
20029
20030    pub fn highlight_background<T: 'static>(
20031        &mut self,
20032        ranges: &[Range<Anchor>],
20033        color_fetcher: fn(&Theme) -> Hsla,
20034        cx: &mut Context<Self>,
20035    ) {
20036        self.background_highlights.insert(
20037            HighlightKey::Type(TypeId::of::<T>()),
20038            (color_fetcher, Arc::from(ranges)),
20039        );
20040        self.scrollbar_marker_state.dirty = true;
20041        cx.notify();
20042    }
20043
20044    pub fn highlight_background_key<T: 'static>(
20045        &mut self,
20046        key: usize,
20047        ranges: &[Range<Anchor>],
20048        color_fetcher: fn(&Theme) -> Hsla,
20049        cx: &mut Context<Self>,
20050    ) {
20051        self.background_highlights.insert(
20052            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20053            (color_fetcher, Arc::from(ranges)),
20054        );
20055        self.scrollbar_marker_state.dirty = true;
20056        cx.notify();
20057    }
20058
20059    pub fn clear_background_highlights<T: 'static>(
20060        &mut self,
20061        cx: &mut Context<Self>,
20062    ) -> Option<BackgroundHighlight> {
20063        let text_highlights = self
20064            .background_highlights
20065            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20066        if !text_highlights.1.is_empty() {
20067            self.scrollbar_marker_state.dirty = true;
20068            cx.notify();
20069        }
20070        Some(text_highlights)
20071    }
20072
20073    pub fn highlight_gutter<T: 'static>(
20074        &mut self,
20075        ranges: impl Into<Vec<Range<Anchor>>>,
20076        color_fetcher: fn(&App) -> Hsla,
20077        cx: &mut Context<Self>,
20078    ) {
20079        self.gutter_highlights
20080            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20081        cx.notify();
20082    }
20083
20084    pub fn clear_gutter_highlights<T: 'static>(
20085        &mut self,
20086        cx: &mut Context<Self>,
20087    ) -> Option<GutterHighlight> {
20088        cx.notify();
20089        self.gutter_highlights.remove(&TypeId::of::<T>())
20090    }
20091
20092    pub fn insert_gutter_highlight<T: 'static>(
20093        &mut self,
20094        range: Range<Anchor>,
20095        color_fetcher: fn(&App) -> Hsla,
20096        cx: &mut Context<Self>,
20097    ) {
20098        let snapshot = self.buffer().read(cx).snapshot(cx);
20099        let mut highlights = self
20100            .gutter_highlights
20101            .remove(&TypeId::of::<T>())
20102            .map(|(_, highlights)| highlights)
20103            .unwrap_or_default();
20104        let ix = highlights.binary_search_by(|highlight| {
20105            Ordering::Equal
20106                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20107                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20108        });
20109        if let Err(ix) = ix {
20110            highlights.insert(ix, range);
20111        }
20112        self.gutter_highlights
20113            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20114    }
20115
20116    pub fn remove_gutter_highlights<T: 'static>(
20117        &mut self,
20118        ranges_to_remove: Vec<Range<Anchor>>,
20119        cx: &mut Context<Self>,
20120    ) {
20121        let snapshot = self.buffer().read(cx).snapshot(cx);
20122        let Some((color_fetcher, mut gutter_highlights)) =
20123            self.gutter_highlights.remove(&TypeId::of::<T>())
20124        else {
20125            return;
20126        };
20127        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20128        gutter_highlights.retain(|highlight| {
20129            while let Some(range_to_remove) = ranges_to_remove.peek() {
20130                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20131                    Ordering::Less | Ordering::Equal => {
20132                        ranges_to_remove.next();
20133                    }
20134                    Ordering::Greater => {
20135                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20136                            Ordering::Less | Ordering::Equal => {
20137                                return false;
20138                            }
20139                            Ordering::Greater => break,
20140                        }
20141                    }
20142                }
20143            }
20144
20145            true
20146        });
20147        self.gutter_highlights
20148            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20149    }
20150
20151    #[cfg(feature = "test-support")]
20152    pub fn all_text_highlights(
20153        &self,
20154        window: &mut Window,
20155        cx: &mut Context<Self>,
20156    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20157        let snapshot = self.snapshot(window, cx);
20158        self.display_map.update(cx, |display_map, _| {
20159            display_map
20160                .all_text_highlights()
20161                .map(|highlight| {
20162                    let (style, ranges) = highlight.as_ref();
20163                    (
20164                        *style,
20165                        ranges
20166                            .iter()
20167                            .map(|range| range.clone().to_display_points(&snapshot))
20168                            .collect(),
20169                    )
20170                })
20171                .collect()
20172        })
20173    }
20174
20175    #[cfg(feature = "test-support")]
20176    pub fn all_text_background_highlights(
20177        &self,
20178        window: &mut Window,
20179        cx: &mut Context<Self>,
20180    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20181        let snapshot = self.snapshot(window, cx);
20182        let buffer = &snapshot.buffer_snapshot;
20183        let start = buffer.anchor_before(0);
20184        let end = buffer.anchor_after(buffer.len());
20185        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20186    }
20187
20188    #[cfg(any(test, feature = "test-support"))]
20189    pub fn sorted_background_highlights_in_range(
20190        &self,
20191        search_range: Range<Anchor>,
20192        display_snapshot: &DisplaySnapshot,
20193        theme: &Theme,
20194    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20195        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20196        res.sort_by(|a, b| {
20197            a.0.start
20198                .cmp(&b.0.start)
20199                .then_with(|| a.0.end.cmp(&b.0.end))
20200                .then_with(|| a.1.cmp(&b.1))
20201        });
20202        res
20203    }
20204
20205    #[cfg(feature = "test-support")]
20206    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20207        let snapshot = self.buffer().read(cx).snapshot(cx);
20208
20209        let highlights = self
20210            .background_highlights
20211            .get(&HighlightKey::Type(TypeId::of::<
20212                items::BufferSearchHighlights,
20213            >()));
20214
20215        if let Some((_color, ranges)) = highlights {
20216            ranges
20217                .iter()
20218                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20219                .collect_vec()
20220        } else {
20221            vec![]
20222        }
20223    }
20224
20225    fn document_highlights_for_position<'a>(
20226        &'a self,
20227        position: Anchor,
20228        buffer: &'a MultiBufferSnapshot,
20229    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20230        let read_highlights = self
20231            .background_highlights
20232            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20233            .map(|h| &h.1);
20234        let write_highlights = self
20235            .background_highlights
20236            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20237            .map(|h| &h.1);
20238        let left_position = position.bias_left(buffer);
20239        let right_position = position.bias_right(buffer);
20240        read_highlights
20241            .into_iter()
20242            .chain(write_highlights)
20243            .flat_map(move |ranges| {
20244                let start_ix = match ranges.binary_search_by(|probe| {
20245                    let cmp = probe.end.cmp(&left_position, buffer);
20246                    if cmp.is_ge() {
20247                        Ordering::Greater
20248                    } else {
20249                        Ordering::Less
20250                    }
20251                }) {
20252                    Ok(i) | Err(i) => i,
20253                };
20254
20255                ranges[start_ix..]
20256                    .iter()
20257                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20258            })
20259    }
20260
20261    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20262        self.background_highlights
20263            .get(&HighlightKey::Type(TypeId::of::<T>()))
20264            .is_some_and(|(_, highlights)| !highlights.is_empty())
20265    }
20266
20267    /// Returns all background highlights for a given range.
20268    ///
20269    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20270    pub fn background_highlights_in_range(
20271        &self,
20272        search_range: Range<Anchor>,
20273        display_snapshot: &DisplaySnapshot,
20274        theme: &Theme,
20275    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20276        let mut results = Vec::new();
20277        for (color_fetcher, ranges) in self.background_highlights.values() {
20278            let color = color_fetcher(theme);
20279            let start_ix = match ranges.binary_search_by(|probe| {
20280                let cmp = probe
20281                    .end
20282                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20283                if cmp.is_gt() {
20284                    Ordering::Greater
20285                } else {
20286                    Ordering::Less
20287                }
20288            }) {
20289                Ok(i) | Err(i) => i,
20290            };
20291            for range in &ranges[start_ix..] {
20292                if range
20293                    .start
20294                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20295                    .is_ge()
20296                {
20297                    break;
20298                }
20299
20300                let start = range.start.to_display_point(display_snapshot);
20301                let end = range.end.to_display_point(display_snapshot);
20302                results.push((start..end, color))
20303            }
20304        }
20305        results
20306    }
20307
20308    pub fn gutter_highlights_in_range(
20309        &self,
20310        search_range: Range<Anchor>,
20311        display_snapshot: &DisplaySnapshot,
20312        cx: &App,
20313    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20314        let mut results = Vec::new();
20315        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20316            let color = color_fetcher(cx);
20317            let start_ix = match ranges.binary_search_by(|probe| {
20318                let cmp = probe
20319                    .end
20320                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20321                if cmp.is_gt() {
20322                    Ordering::Greater
20323                } else {
20324                    Ordering::Less
20325                }
20326            }) {
20327                Ok(i) | Err(i) => i,
20328            };
20329            for range in &ranges[start_ix..] {
20330                if range
20331                    .start
20332                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20333                    .is_ge()
20334                {
20335                    break;
20336                }
20337
20338                let start = range.start.to_display_point(display_snapshot);
20339                let end = range.end.to_display_point(display_snapshot);
20340                results.push((start..end, color))
20341            }
20342        }
20343        results
20344    }
20345
20346    /// Get the text ranges corresponding to the redaction query
20347    pub fn redacted_ranges(
20348        &self,
20349        search_range: Range<Anchor>,
20350        display_snapshot: &DisplaySnapshot,
20351        cx: &App,
20352    ) -> Vec<Range<DisplayPoint>> {
20353        display_snapshot
20354            .buffer_snapshot
20355            .redacted_ranges(search_range, |file| {
20356                if let Some(file) = file {
20357                    file.is_private()
20358                        && EditorSettings::get(
20359                            Some(SettingsLocation {
20360                                worktree_id: file.worktree_id(cx),
20361                                path: file.path().as_ref(),
20362                            }),
20363                            cx,
20364                        )
20365                        .redact_private_values
20366                } else {
20367                    false
20368                }
20369            })
20370            .map(|range| {
20371                range.start.to_display_point(display_snapshot)
20372                    ..range.end.to_display_point(display_snapshot)
20373            })
20374            .collect()
20375    }
20376
20377    pub fn highlight_text_key<T: 'static>(
20378        &mut self,
20379        key: usize,
20380        ranges: Vec<Range<Anchor>>,
20381        style: HighlightStyle,
20382        cx: &mut Context<Self>,
20383    ) {
20384        self.display_map.update(cx, |map, _| {
20385            map.highlight_text(
20386                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20387                ranges,
20388                style,
20389            );
20390        });
20391        cx.notify();
20392    }
20393
20394    pub fn highlight_text<T: 'static>(
20395        &mut self,
20396        ranges: Vec<Range<Anchor>>,
20397        style: HighlightStyle,
20398        cx: &mut Context<Self>,
20399    ) {
20400        self.display_map.update(cx, |map, _| {
20401            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20402        });
20403        cx.notify();
20404    }
20405
20406    pub(crate) fn highlight_inlays<T: 'static>(
20407        &mut self,
20408        highlights: Vec<InlayHighlight>,
20409        style: HighlightStyle,
20410        cx: &mut Context<Self>,
20411    ) {
20412        self.display_map.update(cx, |map, _| {
20413            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20414        });
20415        cx.notify();
20416    }
20417
20418    pub fn text_highlights<'a, T: 'static>(
20419        &'a self,
20420        cx: &'a App,
20421    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20422        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20423    }
20424
20425    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20426        let cleared = self
20427            .display_map
20428            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20429        if cleared {
20430            cx.notify();
20431        }
20432    }
20433
20434    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20435        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20436            && self.focus_handle.is_focused(window)
20437    }
20438
20439    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20440        self.show_cursor_when_unfocused = is_enabled;
20441        cx.notify();
20442    }
20443
20444    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20445        cx.notify();
20446    }
20447
20448    fn on_debug_session_event(
20449        &mut self,
20450        _session: Entity<Session>,
20451        event: &SessionEvent,
20452        cx: &mut Context<Self>,
20453    ) {
20454        if let SessionEvent::InvalidateInlineValue = event {
20455            self.refresh_inline_values(cx);
20456        }
20457    }
20458
20459    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20460        let Some(project) = self.project.clone() else {
20461            return;
20462        };
20463
20464        if !self.inline_value_cache.enabled {
20465            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20466            self.splice_inlays(&inlays, Vec::new(), cx);
20467            return;
20468        }
20469
20470        let current_execution_position = self
20471            .highlighted_rows
20472            .get(&TypeId::of::<ActiveDebugLine>())
20473            .and_then(|lines| lines.last().map(|line| line.range.end));
20474
20475        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20476            let inline_values = editor
20477                .update(cx, |editor, cx| {
20478                    let Some(current_execution_position) = current_execution_position else {
20479                        return Some(Task::ready(Ok(Vec::new())));
20480                    };
20481
20482                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20483                        let snapshot = buffer.snapshot(cx);
20484
20485                        let excerpt = snapshot.excerpt_containing(
20486                            current_execution_position..current_execution_position,
20487                        )?;
20488
20489                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20490                    })?;
20491
20492                    let range =
20493                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20494
20495                    project.inline_values(buffer, range, cx)
20496                })
20497                .ok()
20498                .flatten()?
20499                .await
20500                .context("refreshing debugger inlays")
20501                .log_err()?;
20502
20503            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20504
20505            for (buffer_id, inline_value) in inline_values
20506                .into_iter()
20507                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20508            {
20509                buffer_inline_values
20510                    .entry(buffer_id)
20511                    .or_default()
20512                    .push(inline_value);
20513            }
20514
20515            editor
20516                .update(cx, |editor, cx| {
20517                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20518                    let mut new_inlays = Vec::default();
20519
20520                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20521                        let buffer_id = buffer_snapshot.remote_id();
20522                        buffer_inline_values
20523                            .get(&buffer_id)
20524                            .into_iter()
20525                            .flatten()
20526                            .for_each(|hint| {
20527                                let inlay = Inlay::debugger(
20528                                    post_inc(&mut editor.next_inlay_id),
20529                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20530                                    hint.text(),
20531                                );
20532                                if !inlay.text.chars().contains(&'\n') {
20533                                    new_inlays.push(inlay);
20534                                }
20535                            });
20536                    }
20537
20538                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20539                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20540
20541                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20542                })
20543                .ok()?;
20544            Some(())
20545        });
20546    }
20547
20548    fn on_buffer_event(
20549        &mut self,
20550        multibuffer: &Entity<MultiBuffer>,
20551        event: &multi_buffer::Event,
20552        window: &mut Window,
20553        cx: &mut Context<Self>,
20554    ) {
20555        match event {
20556            multi_buffer::Event::Edited {
20557                singleton_buffer_edited,
20558                edited_buffer,
20559            } => {
20560                self.scrollbar_marker_state.dirty = true;
20561                self.active_indent_guides_state.dirty = true;
20562                self.refresh_active_diagnostics(cx);
20563                self.refresh_code_actions(window, cx);
20564                self.refresh_selected_text_highlights(true, window, cx);
20565                self.refresh_single_line_folds(window, cx);
20566                refresh_matching_bracket_highlights(self, window, cx);
20567                if self.has_active_edit_prediction() {
20568                    self.update_visible_edit_prediction(window, cx);
20569                }
20570                if let Some(project) = self.project.as_ref()
20571                    && let Some(edited_buffer) = edited_buffer
20572                {
20573                    project.update(cx, |project, cx| {
20574                        self.registered_buffers
20575                            .entry(edited_buffer.read(cx).remote_id())
20576                            .or_insert_with(|| {
20577                                project.register_buffer_with_language_servers(edited_buffer, cx)
20578                            });
20579                    });
20580                }
20581                cx.emit(EditorEvent::BufferEdited);
20582                cx.emit(SearchEvent::MatchesInvalidated);
20583
20584                if let Some(buffer) = edited_buffer {
20585                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20586                }
20587
20588                if *singleton_buffer_edited {
20589                    if let Some(buffer) = edited_buffer
20590                        && buffer.read(cx).file().is_none()
20591                    {
20592                        cx.emit(EditorEvent::TitleChanged);
20593                    }
20594                    if let Some(project) = &self.project {
20595                        #[allow(clippy::mutable_key_type)]
20596                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20597                            multibuffer
20598                                .all_buffers()
20599                                .into_iter()
20600                                .filter_map(|buffer| {
20601                                    buffer.update(cx, |buffer, cx| {
20602                                        let language = buffer.language()?;
20603                                        let should_discard = project.update(cx, |project, cx| {
20604                                            project.is_local()
20605                                                && !project.has_language_servers_for(buffer, cx)
20606                                        });
20607                                        should_discard.not().then_some(language.clone())
20608                                    })
20609                                })
20610                                .collect::<HashSet<_>>()
20611                        });
20612                        if !languages_affected.is_empty() {
20613                            self.refresh_inlay_hints(
20614                                InlayHintRefreshReason::BufferEdited(languages_affected),
20615                                cx,
20616                            );
20617                        }
20618                    }
20619                }
20620
20621                let Some(project) = &self.project else { return };
20622                let (telemetry, is_via_ssh) = {
20623                    let project = project.read(cx);
20624                    let telemetry = project.client().telemetry().clone();
20625                    let is_via_ssh = project.is_via_remote_server();
20626                    (telemetry, is_via_ssh)
20627                };
20628                refresh_linked_ranges(self, window, cx);
20629                telemetry.log_edit_event("editor", is_via_ssh);
20630            }
20631            multi_buffer::Event::ExcerptsAdded {
20632                buffer,
20633                predecessor,
20634                excerpts,
20635            } => {
20636                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20637                let buffer_id = buffer.read(cx).remote_id();
20638                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20639                    && let Some(project) = &self.project
20640                {
20641                    update_uncommitted_diff_for_buffer(
20642                        cx.entity(),
20643                        project,
20644                        [buffer.clone()],
20645                        self.buffer.clone(),
20646                        cx,
20647                    )
20648                    .detach();
20649                }
20650                if self.active_diagnostics != ActiveDiagnostic::All {
20651                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20652                }
20653                cx.emit(EditorEvent::ExcerptsAdded {
20654                    buffer: buffer.clone(),
20655                    predecessor: *predecessor,
20656                    excerpts: excerpts.clone(),
20657                });
20658                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20659            }
20660            multi_buffer::Event::ExcerptsRemoved {
20661                ids,
20662                removed_buffer_ids,
20663            } => {
20664                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20665                let buffer = self.buffer.read(cx);
20666                self.registered_buffers
20667                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20668                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20669                cx.emit(EditorEvent::ExcerptsRemoved {
20670                    ids: ids.clone(),
20671                    removed_buffer_ids: removed_buffer_ids.clone(),
20672                });
20673            }
20674            multi_buffer::Event::ExcerptsEdited {
20675                excerpt_ids,
20676                buffer_ids,
20677            } => {
20678                self.display_map.update(cx, |map, cx| {
20679                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20680                });
20681                cx.emit(EditorEvent::ExcerptsEdited {
20682                    ids: excerpt_ids.clone(),
20683                });
20684            }
20685            multi_buffer::Event::ExcerptsExpanded { ids } => {
20686                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20687                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20688            }
20689            multi_buffer::Event::Reparsed(buffer_id) => {
20690                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20691                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20692
20693                cx.emit(EditorEvent::Reparsed(*buffer_id));
20694            }
20695            multi_buffer::Event::DiffHunksToggled => {
20696                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20697            }
20698            multi_buffer::Event::LanguageChanged(buffer_id) => {
20699                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20700                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20701                cx.emit(EditorEvent::Reparsed(*buffer_id));
20702                cx.notify();
20703            }
20704            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20705            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20706            multi_buffer::Event::FileHandleChanged
20707            | multi_buffer::Event::Reloaded
20708            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20709            multi_buffer::Event::DiagnosticsUpdated => {
20710                self.update_diagnostics_state(window, cx);
20711            }
20712            _ => {}
20713        };
20714    }
20715
20716    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20717        if !self.diagnostics_enabled() {
20718            return;
20719        }
20720        self.refresh_active_diagnostics(cx);
20721        self.refresh_inline_diagnostics(true, window, cx);
20722        self.scrollbar_marker_state.dirty = true;
20723        cx.notify();
20724    }
20725
20726    pub fn start_temporary_diff_override(&mut self) {
20727        self.load_diff_task.take();
20728        self.temporary_diff_override = true;
20729    }
20730
20731    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20732        self.temporary_diff_override = false;
20733        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20734        self.buffer.update(cx, |buffer, cx| {
20735            buffer.set_all_diff_hunks_collapsed(cx);
20736        });
20737
20738        if let Some(project) = self.project.clone() {
20739            self.load_diff_task = Some(
20740                update_uncommitted_diff_for_buffer(
20741                    cx.entity(),
20742                    &project,
20743                    self.buffer.read(cx).all_buffers(),
20744                    self.buffer.clone(),
20745                    cx,
20746                )
20747                .shared(),
20748            );
20749        }
20750    }
20751
20752    fn on_display_map_changed(
20753        &mut self,
20754        _: Entity<DisplayMap>,
20755        _: &mut Window,
20756        cx: &mut Context<Self>,
20757    ) {
20758        cx.notify();
20759    }
20760
20761    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20762        if self.diagnostics_enabled() {
20763            let new_severity = EditorSettings::get_global(cx)
20764                .diagnostics_max_severity
20765                .unwrap_or(DiagnosticSeverity::Hint);
20766            self.set_max_diagnostics_severity(new_severity, cx);
20767        }
20768        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20769        self.update_edit_prediction_settings(cx);
20770        self.refresh_edit_prediction(true, false, window, cx);
20771        self.refresh_inline_values(cx);
20772        self.refresh_inlay_hints(
20773            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20774                self.selections.newest_anchor().head(),
20775                &self.buffer.read(cx).snapshot(cx),
20776                cx,
20777            )),
20778            cx,
20779        );
20780
20781        let old_cursor_shape = self.cursor_shape;
20782        let old_show_breadcrumbs = self.show_breadcrumbs;
20783
20784        {
20785            let editor_settings = EditorSettings::get_global(cx);
20786            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20787            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20788            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20789            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20790        }
20791
20792        if old_cursor_shape != self.cursor_shape {
20793            cx.emit(EditorEvent::CursorShapeChanged);
20794        }
20795
20796        if old_show_breadcrumbs != self.show_breadcrumbs {
20797            cx.emit(EditorEvent::BreadcrumbsChanged);
20798        }
20799
20800        let project_settings = ProjectSettings::get_global(cx);
20801        self.serialize_dirty_buffers =
20802            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20803
20804        if self.mode.is_full() {
20805            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20806            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20807            if self.show_inline_diagnostics != show_inline_diagnostics {
20808                self.show_inline_diagnostics = show_inline_diagnostics;
20809                self.refresh_inline_diagnostics(false, window, cx);
20810            }
20811
20812            if self.git_blame_inline_enabled != inline_blame_enabled {
20813                self.toggle_git_blame_inline_internal(false, window, cx);
20814            }
20815
20816            let minimap_settings = EditorSettings::get_global(cx).minimap;
20817            if self.minimap_visibility != MinimapVisibility::Disabled {
20818                if self.minimap_visibility.settings_visibility()
20819                    != minimap_settings.minimap_enabled()
20820                {
20821                    self.set_minimap_visibility(
20822                        MinimapVisibility::for_mode(self.mode(), cx),
20823                        window,
20824                        cx,
20825                    );
20826                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20827                    minimap_entity.update(cx, |minimap_editor, cx| {
20828                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20829                    })
20830                }
20831            }
20832        }
20833
20834        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20835            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20836        }) {
20837            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20838                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20839            }
20840            self.refresh_colors(false, None, window, cx);
20841        }
20842
20843        cx.notify();
20844    }
20845
20846    pub fn set_searchable(&mut self, searchable: bool) {
20847        self.searchable = searchable;
20848    }
20849
20850    pub fn searchable(&self) -> bool {
20851        self.searchable
20852    }
20853
20854    fn open_proposed_changes_editor(
20855        &mut self,
20856        _: &OpenProposedChangesEditor,
20857        window: &mut Window,
20858        cx: &mut Context<Self>,
20859    ) {
20860        let Some(workspace) = self.workspace() else {
20861            cx.propagate();
20862            return;
20863        };
20864
20865        let selections = self.selections.all::<usize>(cx);
20866        let multi_buffer = self.buffer.read(cx);
20867        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20868        let mut new_selections_by_buffer = HashMap::default();
20869        for selection in selections {
20870            for (buffer, range, _) in
20871                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20872            {
20873                let mut range = range.to_point(buffer);
20874                range.start.column = 0;
20875                range.end.column = buffer.line_len(range.end.row);
20876                new_selections_by_buffer
20877                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20878                    .or_insert(Vec::new())
20879                    .push(range)
20880            }
20881        }
20882
20883        let proposed_changes_buffers = new_selections_by_buffer
20884            .into_iter()
20885            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20886            .collect::<Vec<_>>();
20887        let proposed_changes_editor = cx.new(|cx| {
20888            ProposedChangesEditor::new(
20889                "Proposed changes",
20890                proposed_changes_buffers,
20891                self.project.clone(),
20892                window,
20893                cx,
20894            )
20895        });
20896
20897        window.defer(cx, move |window, cx| {
20898            workspace.update(cx, |workspace, cx| {
20899                workspace.active_pane().update(cx, |pane, cx| {
20900                    pane.add_item(
20901                        Box::new(proposed_changes_editor),
20902                        true,
20903                        true,
20904                        None,
20905                        window,
20906                        cx,
20907                    );
20908                });
20909            });
20910        });
20911    }
20912
20913    pub fn open_excerpts_in_split(
20914        &mut self,
20915        _: &OpenExcerptsSplit,
20916        window: &mut Window,
20917        cx: &mut Context<Self>,
20918    ) {
20919        self.open_excerpts_common(None, true, window, cx)
20920    }
20921
20922    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20923        self.open_excerpts_common(None, false, window, cx)
20924    }
20925
20926    fn open_excerpts_common(
20927        &mut self,
20928        jump_data: Option<JumpData>,
20929        split: bool,
20930        window: &mut Window,
20931        cx: &mut Context<Self>,
20932    ) {
20933        let Some(workspace) = self.workspace() else {
20934            cx.propagate();
20935            return;
20936        };
20937
20938        if self.buffer.read(cx).is_singleton() {
20939            cx.propagate();
20940            return;
20941        }
20942
20943        let mut new_selections_by_buffer = HashMap::default();
20944        match &jump_data {
20945            Some(JumpData::MultiBufferPoint {
20946                excerpt_id,
20947                position,
20948                anchor,
20949                line_offset_from_top,
20950            }) => {
20951                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20952                if let Some(buffer) = multi_buffer_snapshot
20953                    .buffer_id_for_excerpt(*excerpt_id)
20954                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20955                {
20956                    let buffer_snapshot = buffer.read(cx).snapshot();
20957                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20958                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20959                    } else {
20960                        buffer_snapshot.clip_point(*position, Bias::Left)
20961                    };
20962                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20963                    new_selections_by_buffer.insert(
20964                        buffer,
20965                        (
20966                            vec![jump_to_offset..jump_to_offset],
20967                            Some(*line_offset_from_top),
20968                        ),
20969                    );
20970                }
20971            }
20972            Some(JumpData::MultiBufferRow {
20973                row,
20974                line_offset_from_top,
20975            }) => {
20976                let point = MultiBufferPoint::new(row.0, 0);
20977                if let Some((buffer, buffer_point, _)) =
20978                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20979                {
20980                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20981                    new_selections_by_buffer
20982                        .entry(buffer)
20983                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20984                        .0
20985                        .push(buffer_offset..buffer_offset)
20986                }
20987            }
20988            None => {
20989                let selections = self.selections.all::<usize>(cx);
20990                let multi_buffer = self.buffer.read(cx);
20991                for selection in selections {
20992                    for (snapshot, range, _, anchor) in multi_buffer
20993                        .snapshot(cx)
20994                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20995                    {
20996                        if let Some(anchor) = anchor {
20997                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20998                            else {
20999                                continue;
21000                            };
21001                            let offset = text::ToOffset::to_offset(
21002                                &anchor.text_anchor,
21003                                &buffer_handle.read(cx).snapshot(),
21004                            );
21005                            let range = offset..offset;
21006                            new_selections_by_buffer
21007                                .entry(buffer_handle)
21008                                .or_insert((Vec::new(), None))
21009                                .0
21010                                .push(range)
21011                        } else {
21012                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21013                            else {
21014                                continue;
21015                            };
21016                            new_selections_by_buffer
21017                                .entry(buffer_handle)
21018                                .or_insert((Vec::new(), None))
21019                                .0
21020                                .push(range)
21021                        }
21022                    }
21023                }
21024            }
21025        }
21026
21027        new_selections_by_buffer
21028            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21029
21030        if new_selections_by_buffer.is_empty() {
21031            return;
21032        }
21033
21034        // We defer the pane interaction because we ourselves are a workspace item
21035        // and activating a new item causes the pane to call a method on us reentrantly,
21036        // which panics if we're on the stack.
21037        window.defer(cx, move |window, cx| {
21038            workspace.update(cx, |workspace, cx| {
21039                let pane = if split {
21040                    workspace.adjacent_pane(window, cx)
21041                } else {
21042                    workspace.active_pane().clone()
21043                };
21044
21045                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21046                    let editor = buffer
21047                        .read(cx)
21048                        .file()
21049                        .is_none()
21050                        .then(|| {
21051                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21052                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21053                            // Instead, we try to activate the existing editor in the pane first.
21054                            let (editor, pane_item_index) =
21055                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21056                                    let editor = item.downcast::<Editor>()?;
21057                                    let singleton_buffer =
21058                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21059                                    if singleton_buffer == buffer {
21060                                        Some((editor, i))
21061                                    } else {
21062                                        None
21063                                    }
21064                                })?;
21065                            pane.update(cx, |pane, cx| {
21066                                pane.activate_item(pane_item_index, true, true, window, cx)
21067                            });
21068                            Some(editor)
21069                        })
21070                        .flatten()
21071                        .unwrap_or_else(|| {
21072                            workspace.open_project_item::<Self>(
21073                                pane.clone(),
21074                                buffer,
21075                                true,
21076                                true,
21077                                window,
21078                                cx,
21079                            )
21080                        });
21081
21082                    editor.update(cx, |editor, cx| {
21083                        let autoscroll = match scroll_offset {
21084                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21085                            None => Autoscroll::newest(),
21086                        };
21087                        let nav_history = editor.nav_history.take();
21088                        editor.change_selections(
21089                            SelectionEffects::scroll(autoscroll),
21090                            window,
21091                            cx,
21092                            |s| {
21093                                s.select_ranges(ranges);
21094                            },
21095                        );
21096                        editor.nav_history = nav_history;
21097                    });
21098                }
21099            })
21100        });
21101    }
21102
21103    // For now, don't allow opening excerpts in buffers that aren't backed by
21104    // regular project files.
21105    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21106        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21107    }
21108
21109    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21110        let snapshot = self.buffer.read(cx).read(cx);
21111        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21112        Some(
21113            ranges
21114                .iter()
21115                .map(move |range| {
21116                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21117                })
21118                .collect(),
21119        )
21120    }
21121
21122    fn selection_replacement_ranges(
21123        &self,
21124        range: Range<OffsetUtf16>,
21125        cx: &mut App,
21126    ) -> Vec<Range<OffsetUtf16>> {
21127        let selections = self.selections.all::<OffsetUtf16>(cx);
21128        let newest_selection = selections
21129            .iter()
21130            .max_by_key(|selection| selection.id)
21131            .unwrap();
21132        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21133        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21134        let snapshot = self.buffer.read(cx).read(cx);
21135        selections
21136            .into_iter()
21137            .map(|mut selection| {
21138                selection.start.0 =
21139                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21140                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21141                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21142                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21143            })
21144            .collect()
21145    }
21146
21147    fn report_editor_event(
21148        &self,
21149        reported_event: ReportEditorEvent,
21150        file_extension: Option<String>,
21151        cx: &App,
21152    ) {
21153        if cfg!(any(test, feature = "test-support")) {
21154            return;
21155        }
21156
21157        let Some(project) = &self.project else { return };
21158
21159        // If None, we are in a file without an extension
21160        let file = self
21161            .buffer
21162            .read(cx)
21163            .as_singleton()
21164            .and_then(|b| b.read(cx).file());
21165        let file_extension = file_extension.or(file
21166            .as_ref()
21167            .and_then(|file| Path::new(file.file_name(cx)).extension())
21168            .and_then(|e| e.to_str())
21169            .map(|a| a.to_string()));
21170
21171        let vim_mode = vim_enabled(cx);
21172
21173        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21174        let copilot_enabled = edit_predictions_provider
21175            == language::language_settings::EditPredictionProvider::Copilot;
21176        let copilot_enabled_for_language = self
21177            .buffer
21178            .read(cx)
21179            .language_settings(cx)
21180            .show_edit_predictions;
21181
21182        let project = project.read(cx);
21183        let event_type = reported_event.event_type();
21184
21185        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21186            telemetry::event!(
21187                event_type,
21188                type = if auto_saved {"autosave"} else {"manual"},
21189                file_extension,
21190                vim_mode,
21191                copilot_enabled,
21192                copilot_enabled_for_language,
21193                edit_predictions_provider,
21194                is_via_ssh = project.is_via_remote_server(),
21195            );
21196        } else {
21197            telemetry::event!(
21198                event_type,
21199                file_extension,
21200                vim_mode,
21201                copilot_enabled,
21202                copilot_enabled_for_language,
21203                edit_predictions_provider,
21204                is_via_ssh = project.is_via_remote_server(),
21205            );
21206        };
21207    }
21208
21209    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21210    /// with each line being an array of {text, highlight} objects.
21211    fn copy_highlight_json(
21212        &mut self,
21213        _: &CopyHighlightJson,
21214        window: &mut Window,
21215        cx: &mut Context<Self>,
21216    ) {
21217        #[derive(Serialize)]
21218        struct Chunk<'a> {
21219            text: String,
21220            highlight: Option<&'a str>,
21221        }
21222
21223        let snapshot = self.buffer.read(cx).snapshot(cx);
21224        let range = self
21225            .selected_text_range(false, window, cx)
21226            .and_then(|selection| {
21227                if selection.range.is_empty() {
21228                    None
21229                } else {
21230                    Some(selection.range)
21231                }
21232            })
21233            .unwrap_or_else(|| 0..snapshot.len());
21234
21235        let chunks = snapshot.chunks(range, true);
21236        let mut lines = Vec::new();
21237        let mut line: VecDeque<Chunk> = VecDeque::new();
21238
21239        let Some(style) = self.style.as_ref() else {
21240            return;
21241        };
21242
21243        for chunk in chunks {
21244            let highlight = chunk
21245                .syntax_highlight_id
21246                .and_then(|id| id.name(&style.syntax));
21247            let mut chunk_lines = chunk.text.split('\n').peekable();
21248            while let Some(text) = chunk_lines.next() {
21249                let mut merged_with_last_token = false;
21250                if let Some(last_token) = line.back_mut()
21251                    && last_token.highlight == highlight
21252                {
21253                    last_token.text.push_str(text);
21254                    merged_with_last_token = true;
21255                }
21256
21257                if !merged_with_last_token {
21258                    line.push_back(Chunk {
21259                        text: text.into(),
21260                        highlight,
21261                    });
21262                }
21263
21264                if chunk_lines.peek().is_some() {
21265                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21266                        line.pop_front();
21267                    }
21268                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21269                        line.pop_back();
21270                    }
21271
21272                    lines.push(mem::take(&mut line));
21273                }
21274            }
21275        }
21276
21277        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21278            return;
21279        };
21280        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21281    }
21282
21283    pub fn open_context_menu(
21284        &mut self,
21285        _: &OpenContextMenu,
21286        window: &mut Window,
21287        cx: &mut Context<Self>,
21288    ) {
21289        self.request_autoscroll(Autoscroll::newest(), cx);
21290        let position = self.selections.newest_display(cx).start;
21291        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21292    }
21293
21294    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21295        &self.inlay_hint_cache
21296    }
21297
21298    pub fn replay_insert_event(
21299        &mut self,
21300        text: &str,
21301        relative_utf16_range: Option<Range<isize>>,
21302        window: &mut Window,
21303        cx: &mut Context<Self>,
21304    ) {
21305        if !self.input_enabled {
21306            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21307            return;
21308        }
21309        if let Some(relative_utf16_range) = relative_utf16_range {
21310            let selections = self.selections.all::<OffsetUtf16>(cx);
21311            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21312                let new_ranges = selections.into_iter().map(|range| {
21313                    let start = OffsetUtf16(
21314                        range
21315                            .head()
21316                            .0
21317                            .saturating_add_signed(relative_utf16_range.start),
21318                    );
21319                    let end = OffsetUtf16(
21320                        range
21321                            .head()
21322                            .0
21323                            .saturating_add_signed(relative_utf16_range.end),
21324                    );
21325                    start..end
21326                });
21327                s.select_ranges(new_ranges);
21328            });
21329        }
21330
21331        self.handle_input(text, window, cx);
21332    }
21333
21334    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21335        let Some(provider) = self.semantics_provider.as_ref() else {
21336            return false;
21337        };
21338
21339        let mut supports = false;
21340        self.buffer().update(cx, |this, cx| {
21341            this.for_each_buffer(|buffer| {
21342                supports |= provider.supports_inlay_hints(buffer, cx);
21343            });
21344        });
21345
21346        supports
21347    }
21348
21349    pub fn is_focused(&self, window: &Window) -> bool {
21350        self.focus_handle.is_focused(window)
21351    }
21352
21353    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21354        cx.emit(EditorEvent::Focused);
21355
21356        if let Some(descendant) = self
21357            .last_focused_descendant
21358            .take()
21359            .and_then(|descendant| descendant.upgrade())
21360        {
21361            window.focus(&descendant);
21362        } else {
21363            if let Some(blame) = self.blame.as_ref() {
21364                blame.update(cx, GitBlame::focus)
21365            }
21366
21367            self.blink_manager.update(cx, BlinkManager::enable);
21368            self.show_cursor_names(window, cx);
21369            self.buffer.update(cx, |buffer, cx| {
21370                buffer.finalize_last_transaction(cx);
21371                if self.leader_id.is_none() {
21372                    buffer.set_active_selections(
21373                        &self.selections.disjoint_anchors_arc(),
21374                        self.selections.line_mode,
21375                        self.cursor_shape,
21376                        cx,
21377                    );
21378                }
21379            });
21380        }
21381    }
21382
21383    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21384        cx.emit(EditorEvent::FocusedIn)
21385    }
21386
21387    fn handle_focus_out(
21388        &mut self,
21389        event: FocusOutEvent,
21390        _window: &mut Window,
21391        cx: &mut Context<Self>,
21392    ) {
21393        if event.blurred != self.focus_handle {
21394            self.last_focused_descendant = Some(event.blurred);
21395        }
21396        self.selection_drag_state = SelectionDragState::None;
21397        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21398    }
21399
21400    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21401        self.blink_manager.update(cx, BlinkManager::disable);
21402        self.buffer
21403            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21404
21405        if let Some(blame) = self.blame.as_ref() {
21406            blame.update(cx, GitBlame::blur)
21407        }
21408        if !self.hover_state.focused(window, cx) {
21409            hide_hover(self, cx);
21410        }
21411        if !self
21412            .context_menu
21413            .borrow()
21414            .as_ref()
21415            .is_some_and(|context_menu| context_menu.focused(window, cx))
21416        {
21417            self.hide_context_menu(window, cx);
21418        }
21419        self.discard_edit_prediction(false, cx);
21420        cx.emit(EditorEvent::Blurred);
21421        cx.notify();
21422    }
21423
21424    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21425        let mut pending: String = window
21426            .pending_input_keystrokes()
21427            .into_iter()
21428            .flatten()
21429            .filter_map(|keystroke| {
21430                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21431                    keystroke.key_char.clone()
21432                } else {
21433                    None
21434                }
21435            })
21436            .collect();
21437
21438        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21439            pending = "".to_string();
21440        }
21441
21442        let existing_pending = self
21443            .text_highlights::<PendingInput>(cx)
21444            .map(|(_, ranges)| ranges.to_vec());
21445        if existing_pending.is_none() && pending.is_empty() {
21446            return;
21447        }
21448        let transaction =
21449            self.transact(window, cx, |this, window, cx| {
21450                let selections = this.selections.all::<usize>(cx);
21451                let edits = selections
21452                    .iter()
21453                    .map(|selection| (selection.end..selection.end, pending.clone()));
21454                this.edit(edits, cx);
21455                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21456                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21457                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21458                    }));
21459                });
21460                if let Some(existing_ranges) = existing_pending {
21461                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21462                    this.edit(edits, cx);
21463                }
21464            });
21465
21466        let snapshot = self.snapshot(window, cx);
21467        let ranges = self
21468            .selections
21469            .all::<usize>(cx)
21470            .into_iter()
21471            .map(|selection| {
21472                snapshot.buffer_snapshot.anchor_after(selection.end)
21473                    ..snapshot
21474                        .buffer_snapshot
21475                        .anchor_before(selection.end + pending.len())
21476            })
21477            .collect();
21478
21479        if pending.is_empty() {
21480            self.clear_highlights::<PendingInput>(cx);
21481        } else {
21482            self.highlight_text::<PendingInput>(
21483                ranges,
21484                HighlightStyle {
21485                    underline: Some(UnderlineStyle {
21486                        thickness: px(1.),
21487                        color: None,
21488                        wavy: false,
21489                    }),
21490                    ..Default::default()
21491                },
21492                cx,
21493            );
21494        }
21495
21496        self.ime_transaction = self.ime_transaction.or(transaction);
21497        if let Some(transaction) = self.ime_transaction {
21498            self.buffer.update(cx, |buffer, cx| {
21499                buffer.group_until_transaction(transaction, cx);
21500            });
21501        }
21502
21503        if self.text_highlights::<PendingInput>(cx).is_none() {
21504            self.ime_transaction.take();
21505        }
21506    }
21507
21508    pub fn register_action_renderer(
21509        &mut self,
21510        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21511    ) -> Subscription {
21512        let id = self.next_editor_action_id.post_inc();
21513        self.editor_actions
21514            .borrow_mut()
21515            .insert(id, Box::new(listener));
21516
21517        let editor_actions = self.editor_actions.clone();
21518        Subscription::new(move || {
21519            editor_actions.borrow_mut().remove(&id);
21520        })
21521    }
21522
21523    pub fn register_action<A: Action>(
21524        &mut self,
21525        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21526    ) -> Subscription {
21527        let id = self.next_editor_action_id.post_inc();
21528        let listener = Arc::new(listener);
21529        self.editor_actions.borrow_mut().insert(
21530            id,
21531            Box::new(move |_, window, _| {
21532                let listener = listener.clone();
21533                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21534                    let action = action.downcast_ref().unwrap();
21535                    if phase == DispatchPhase::Bubble {
21536                        listener(action, window, cx)
21537                    }
21538                })
21539            }),
21540        );
21541
21542        let editor_actions = self.editor_actions.clone();
21543        Subscription::new(move || {
21544            editor_actions.borrow_mut().remove(&id);
21545        })
21546    }
21547
21548    pub fn file_header_size(&self) -> u32 {
21549        FILE_HEADER_HEIGHT
21550    }
21551
21552    pub fn restore(
21553        &mut self,
21554        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21555        window: &mut Window,
21556        cx: &mut Context<Self>,
21557    ) {
21558        let workspace = self.workspace();
21559        let project = self.project();
21560        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21561            let mut tasks = Vec::new();
21562            for (buffer_id, changes) in revert_changes {
21563                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21564                    buffer.update(cx, |buffer, cx| {
21565                        buffer.edit(
21566                            changes
21567                                .into_iter()
21568                                .map(|(range, text)| (range, text.to_string())),
21569                            None,
21570                            cx,
21571                        );
21572                    });
21573
21574                    if let Some(project) =
21575                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21576                    {
21577                        project.update(cx, |project, cx| {
21578                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21579                        })
21580                    }
21581                }
21582            }
21583            tasks
21584        });
21585        cx.spawn_in(window, async move |_, cx| {
21586            for (buffer, task) in save_tasks {
21587                let result = task.await;
21588                if result.is_err() {
21589                    let Some(path) = buffer
21590                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21591                        .ok()
21592                    else {
21593                        continue;
21594                    };
21595                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21596                        let Some(task) = cx
21597                            .update_window_entity(workspace, |workspace, window, cx| {
21598                                workspace
21599                                    .open_path_preview(path, None, false, false, false, window, cx)
21600                            })
21601                            .ok()
21602                        else {
21603                            continue;
21604                        };
21605                        task.await.log_err();
21606                    }
21607                }
21608            }
21609        })
21610        .detach();
21611        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21612            selections.refresh()
21613        });
21614    }
21615
21616    pub fn to_pixel_point(
21617        &self,
21618        source: multi_buffer::Anchor,
21619        editor_snapshot: &EditorSnapshot,
21620        window: &mut Window,
21621    ) -> Option<gpui::Point<Pixels>> {
21622        let source_point = source.to_display_point(editor_snapshot);
21623        self.display_to_pixel_point(source_point, editor_snapshot, window)
21624    }
21625
21626    pub fn display_to_pixel_point(
21627        &self,
21628        source: DisplayPoint,
21629        editor_snapshot: &EditorSnapshot,
21630        window: &mut Window,
21631    ) -> Option<gpui::Point<Pixels>> {
21632        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21633        let text_layout_details = self.text_layout_details(window);
21634        let scroll_top = text_layout_details
21635            .scroll_anchor
21636            .scroll_position(editor_snapshot)
21637            .y;
21638
21639        if source.row().as_f32() < scroll_top.floor() {
21640            return None;
21641        }
21642        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21643        let source_y = line_height * (source.row().as_f32() - scroll_top);
21644        Some(gpui::Point::new(source_x, source_y))
21645    }
21646
21647    pub fn has_visible_completions_menu(&self) -> bool {
21648        !self.edit_prediction_preview_is_active()
21649            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21650                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21651            })
21652    }
21653
21654    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21655        if self.mode.is_minimap() {
21656            return;
21657        }
21658        self.addons
21659            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21660    }
21661
21662    pub fn unregister_addon<T: Addon>(&mut self) {
21663        self.addons.remove(&std::any::TypeId::of::<T>());
21664    }
21665
21666    pub fn addon<T: Addon>(&self) -> Option<&T> {
21667        let type_id = std::any::TypeId::of::<T>();
21668        self.addons
21669            .get(&type_id)
21670            .and_then(|item| item.to_any().downcast_ref::<T>())
21671    }
21672
21673    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21674        let type_id = std::any::TypeId::of::<T>();
21675        self.addons
21676            .get_mut(&type_id)
21677            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21678    }
21679
21680    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21681        let text_layout_details = self.text_layout_details(window);
21682        let style = &text_layout_details.editor_style;
21683        let font_id = window.text_system().resolve_font(&style.text.font());
21684        let font_size = style.text.font_size.to_pixels(window.rem_size());
21685        let line_height = style.text.line_height_in_pixels(window.rem_size());
21686        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21687        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21688
21689        CharacterDimensions {
21690            em_width,
21691            em_advance,
21692            line_height,
21693        }
21694    }
21695
21696    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21697        self.load_diff_task.clone()
21698    }
21699
21700    fn read_metadata_from_db(
21701        &mut self,
21702        item_id: u64,
21703        workspace_id: WorkspaceId,
21704        window: &mut Window,
21705        cx: &mut Context<Editor>,
21706    ) {
21707        if self.is_singleton(cx)
21708            && !self.mode.is_minimap()
21709            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21710        {
21711            let buffer_snapshot = OnceCell::new();
21712
21713            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21714                && !folds.is_empty()
21715            {
21716                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21717                self.fold_ranges(
21718                    folds
21719                        .into_iter()
21720                        .map(|(start, end)| {
21721                            snapshot.clip_offset(start, Bias::Left)
21722                                ..snapshot.clip_offset(end, Bias::Right)
21723                        })
21724                        .collect(),
21725                    false,
21726                    window,
21727                    cx,
21728                );
21729            }
21730
21731            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21732                && !selections.is_empty()
21733            {
21734                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21735                // skip adding the initial selection to selection history
21736                self.selection_history.mode = SelectionHistoryMode::Skipping;
21737                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21738                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21739                        snapshot.clip_offset(start, Bias::Left)
21740                            ..snapshot.clip_offset(end, Bias::Right)
21741                    }));
21742                });
21743                self.selection_history.mode = SelectionHistoryMode::Normal;
21744            };
21745        }
21746
21747        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21748    }
21749
21750    fn update_lsp_data(
21751        &mut self,
21752        ignore_cache: bool,
21753        for_buffer: Option<BufferId>,
21754        window: &mut Window,
21755        cx: &mut Context<'_, Self>,
21756    ) {
21757        self.pull_diagnostics(for_buffer, window, cx);
21758        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21759    }
21760}
21761
21762fn edit_for_markdown_paste<'a>(
21763    buffer: &MultiBufferSnapshot,
21764    range: Range<usize>,
21765    to_insert: &'a str,
21766    url: Option<url::Url>,
21767) -> (Range<usize>, Cow<'a, str>) {
21768    if url.is_none() {
21769        return (range, Cow::Borrowed(to_insert));
21770    };
21771
21772    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21773
21774    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21775        Cow::Borrowed(to_insert)
21776    } else {
21777        Cow::Owned(format!("[{old_text}]({to_insert})"))
21778    };
21779    (range, new_text)
21780}
21781
21782fn vim_enabled(cx: &App) -> bool {
21783    vim_mode_setting::VimModeSetting::try_get(cx)
21784        .map(|vim_mode| vim_mode.0)
21785        .unwrap_or(false)
21786}
21787
21788fn process_completion_for_edit(
21789    completion: &Completion,
21790    intent: CompletionIntent,
21791    buffer: &Entity<Buffer>,
21792    cursor_position: &text::Anchor,
21793    cx: &mut Context<Editor>,
21794) -> CompletionEdit {
21795    let buffer = buffer.read(cx);
21796    let buffer_snapshot = buffer.snapshot();
21797    let (snippet, new_text) = if completion.is_snippet() {
21798        // Workaround for typescript language server issues so that methods don't expand within
21799        // strings and functions with type expressions. The previous point is used because the query
21800        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21801        let mut snippet_source = completion.new_text.clone();
21802        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21803        previous_point.column = previous_point.column.saturating_sub(1);
21804        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21805            && scope.prefers_label_for_snippet_in_completion()
21806            && let Some(label) = completion.label()
21807            && matches!(
21808                completion.kind(),
21809                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21810            )
21811        {
21812            snippet_source = label;
21813        }
21814        match Snippet::parse(&snippet_source).log_err() {
21815            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21816            None => (None, completion.new_text.clone()),
21817        }
21818    } else {
21819        (None, completion.new_text.clone())
21820    };
21821
21822    let mut range_to_replace = {
21823        let replace_range = &completion.replace_range;
21824        if let CompletionSource::Lsp {
21825            insert_range: Some(insert_range),
21826            ..
21827        } = &completion.source
21828        {
21829            debug_assert_eq!(
21830                insert_range.start, replace_range.start,
21831                "insert_range and replace_range should start at the same position"
21832            );
21833            debug_assert!(
21834                insert_range
21835                    .start
21836                    .cmp(cursor_position, &buffer_snapshot)
21837                    .is_le(),
21838                "insert_range should start before or at cursor position"
21839            );
21840            debug_assert!(
21841                replace_range
21842                    .start
21843                    .cmp(cursor_position, &buffer_snapshot)
21844                    .is_le(),
21845                "replace_range should start before or at cursor position"
21846            );
21847
21848            let should_replace = match intent {
21849                CompletionIntent::CompleteWithInsert => false,
21850                CompletionIntent::CompleteWithReplace => true,
21851                CompletionIntent::Complete | CompletionIntent::Compose => {
21852                    let insert_mode =
21853                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21854                            .completions
21855                            .lsp_insert_mode;
21856                    match insert_mode {
21857                        LspInsertMode::Insert => false,
21858                        LspInsertMode::Replace => true,
21859                        LspInsertMode::ReplaceSubsequence => {
21860                            let mut text_to_replace = buffer.chars_for_range(
21861                                buffer.anchor_before(replace_range.start)
21862                                    ..buffer.anchor_after(replace_range.end),
21863                            );
21864                            let mut current_needle = text_to_replace.next();
21865                            for haystack_ch in completion.label.text.chars() {
21866                                if let Some(needle_ch) = current_needle
21867                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21868                                {
21869                                    current_needle = text_to_replace.next();
21870                                }
21871                            }
21872                            current_needle.is_none()
21873                        }
21874                        LspInsertMode::ReplaceSuffix => {
21875                            if replace_range
21876                                .end
21877                                .cmp(cursor_position, &buffer_snapshot)
21878                                .is_gt()
21879                            {
21880                                let range_after_cursor = *cursor_position..replace_range.end;
21881                                let text_after_cursor = buffer
21882                                    .text_for_range(
21883                                        buffer.anchor_before(range_after_cursor.start)
21884                                            ..buffer.anchor_after(range_after_cursor.end),
21885                                    )
21886                                    .collect::<String>()
21887                                    .to_ascii_lowercase();
21888                                completion
21889                                    .label
21890                                    .text
21891                                    .to_ascii_lowercase()
21892                                    .ends_with(&text_after_cursor)
21893                            } else {
21894                                true
21895                            }
21896                        }
21897                    }
21898                }
21899            };
21900
21901            if should_replace {
21902                replace_range.clone()
21903            } else {
21904                insert_range.clone()
21905            }
21906        } else {
21907            replace_range.clone()
21908        }
21909    };
21910
21911    if range_to_replace
21912        .end
21913        .cmp(cursor_position, &buffer_snapshot)
21914        .is_lt()
21915    {
21916        range_to_replace.end = *cursor_position;
21917    }
21918
21919    CompletionEdit {
21920        new_text,
21921        replace_range: range_to_replace.to_offset(buffer),
21922        snippet,
21923    }
21924}
21925
21926struct CompletionEdit {
21927    new_text: String,
21928    replace_range: Range<usize>,
21929    snippet: Option<Snippet>,
21930}
21931
21932fn insert_extra_newline_brackets(
21933    buffer: &MultiBufferSnapshot,
21934    range: Range<usize>,
21935    language: &language::LanguageScope,
21936) -> bool {
21937    let leading_whitespace_len = buffer
21938        .reversed_chars_at(range.start)
21939        .take_while(|c| c.is_whitespace() && *c != '\n')
21940        .map(|c| c.len_utf8())
21941        .sum::<usize>();
21942    let trailing_whitespace_len = buffer
21943        .chars_at(range.end)
21944        .take_while(|c| c.is_whitespace() && *c != '\n')
21945        .map(|c| c.len_utf8())
21946        .sum::<usize>();
21947    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21948
21949    language.brackets().any(|(pair, enabled)| {
21950        let pair_start = pair.start.trim_end();
21951        let pair_end = pair.end.trim_start();
21952
21953        enabled
21954            && pair.newline
21955            && buffer.contains_str_at(range.end, pair_end)
21956            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21957    })
21958}
21959
21960fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21961    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21962        [(buffer, range, _)] => (*buffer, range.clone()),
21963        _ => return false,
21964    };
21965    let pair = {
21966        let mut result: Option<BracketMatch> = None;
21967
21968        for pair in buffer
21969            .all_bracket_ranges(range.clone())
21970            .filter(move |pair| {
21971                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21972            })
21973        {
21974            let len = pair.close_range.end - pair.open_range.start;
21975
21976            if let Some(existing) = &result {
21977                let existing_len = existing.close_range.end - existing.open_range.start;
21978                if len > existing_len {
21979                    continue;
21980                }
21981            }
21982
21983            result = Some(pair);
21984        }
21985
21986        result
21987    };
21988    let Some(pair) = pair else {
21989        return false;
21990    };
21991    pair.newline_only
21992        && buffer
21993            .chars_for_range(pair.open_range.end..range.start)
21994            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21995            .all(|c| c.is_whitespace() && c != '\n')
21996}
21997
21998fn update_uncommitted_diff_for_buffer(
21999    editor: Entity<Editor>,
22000    project: &Entity<Project>,
22001    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22002    buffer: Entity<MultiBuffer>,
22003    cx: &mut App,
22004) -> Task<()> {
22005    let mut tasks = Vec::new();
22006    project.update(cx, |project, cx| {
22007        for buffer in buffers {
22008            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22009                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22010            }
22011        }
22012    });
22013    cx.spawn(async move |cx| {
22014        let diffs = future::join_all(tasks).await;
22015        if editor
22016            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22017            .unwrap_or(false)
22018        {
22019            return;
22020        }
22021
22022        buffer
22023            .update(cx, |buffer, cx| {
22024                for diff in diffs.into_iter().flatten() {
22025                    buffer.add_diff(diff, cx);
22026                }
22027            })
22028            .ok();
22029    })
22030}
22031
22032fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22033    let tab_size = tab_size.get() as usize;
22034    let mut width = offset;
22035
22036    for ch in text.chars() {
22037        width += if ch == '\t' {
22038            tab_size - (width % tab_size)
22039        } else {
22040            1
22041        };
22042    }
22043
22044    width - offset
22045}
22046
22047#[cfg(test)]
22048mod tests {
22049    use super::*;
22050
22051    #[test]
22052    fn test_string_size_with_expanded_tabs() {
22053        let nz = |val| NonZeroU32::new(val).unwrap();
22054        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22055        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22056        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22057        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22058        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22059        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22060        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22061        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22062    }
22063}
22064
22065/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22066struct WordBreakingTokenizer<'a> {
22067    input: &'a str,
22068}
22069
22070impl<'a> WordBreakingTokenizer<'a> {
22071    fn new(input: &'a str) -> Self {
22072        Self { input }
22073    }
22074}
22075
22076fn is_char_ideographic(ch: char) -> bool {
22077    use unicode_script::Script::*;
22078    use unicode_script::UnicodeScript;
22079    matches!(ch.script(), Han | Tangut | Yi)
22080}
22081
22082fn is_grapheme_ideographic(text: &str) -> bool {
22083    text.chars().any(is_char_ideographic)
22084}
22085
22086fn is_grapheme_whitespace(text: &str) -> bool {
22087    text.chars().any(|x| x.is_whitespace())
22088}
22089
22090fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22091    text.chars()
22092        .next()
22093        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22094}
22095
22096#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22097enum WordBreakToken<'a> {
22098    Word { token: &'a str, grapheme_len: usize },
22099    InlineWhitespace { token: &'a str, grapheme_len: usize },
22100    Newline,
22101}
22102
22103impl<'a> Iterator for WordBreakingTokenizer<'a> {
22104    /// Yields a span, the count of graphemes in the token, and whether it was
22105    /// whitespace. Note that it also breaks at word boundaries.
22106    type Item = WordBreakToken<'a>;
22107
22108    fn next(&mut self) -> Option<Self::Item> {
22109        use unicode_segmentation::UnicodeSegmentation;
22110        if self.input.is_empty() {
22111            return None;
22112        }
22113
22114        let mut iter = self.input.graphemes(true).peekable();
22115        let mut offset = 0;
22116        let mut grapheme_len = 0;
22117        if let Some(first_grapheme) = iter.next() {
22118            let is_newline = first_grapheme == "\n";
22119            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22120            offset += first_grapheme.len();
22121            grapheme_len += 1;
22122            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22123                if let Some(grapheme) = iter.peek().copied()
22124                    && should_stay_with_preceding_ideograph(grapheme)
22125                {
22126                    offset += grapheme.len();
22127                    grapheme_len += 1;
22128                }
22129            } else {
22130                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22131                let mut next_word_bound = words.peek().copied();
22132                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22133                    next_word_bound = words.next();
22134                }
22135                while let Some(grapheme) = iter.peek().copied() {
22136                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22137                        break;
22138                    };
22139                    if is_grapheme_whitespace(grapheme) != is_whitespace
22140                        || (grapheme == "\n") != is_newline
22141                    {
22142                        break;
22143                    };
22144                    offset += grapheme.len();
22145                    grapheme_len += 1;
22146                    iter.next();
22147                }
22148            }
22149            let token = &self.input[..offset];
22150            self.input = &self.input[offset..];
22151            if token == "\n" {
22152                Some(WordBreakToken::Newline)
22153            } else if is_whitespace {
22154                Some(WordBreakToken::InlineWhitespace {
22155                    token,
22156                    grapheme_len,
22157                })
22158            } else {
22159                Some(WordBreakToken::Word {
22160                    token,
22161                    grapheme_len,
22162                })
22163            }
22164        } else {
22165            None
22166        }
22167    }
22168}
22169
22170#[test]
22171fn test_word_breaking_tokenizer() {
22172    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22173        ("", &[]),
22174        ("  ", &[whitespace("  ", 2)]),
22175        ("Ʒ", &[word("Ʒ", 1)]),
22176        ("Ǽ", &[word("Ǽ", 1)]),
22177        ("", &[word("", 1)]),
22178        ("⋑⋑", &[word("⋑⋑", 2)]),
22179        (
22180            "原理,进而",
22181            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22182        ),
22183        (
22184            "hello world",
22185            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22186        ),
22187        (
22188            "hello, world",
22189            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22190        ),
22191        (
22192            "  hello world",
22193            &[
22194                whitespace("  ", 2),
22195                word("hello", 5),
22196                whitespace(" ", 1),
22197                word("world", 5),
22198            ],
22199        ),
22200        (
22201            "这是什么 \n 钢笔",
22202            &[
22203                word("", 1),
22204                word("", 1),
22205                word("", 1),
22206                word("", 1),
22207                whitespace(" ", 1),
22208                newline(),
22209                whitespace(" ", 1),
22210                word("", 1),
22211                word("", 1),
22212            ],
22213        ),
22214        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22215    ];
22216
22217    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22218        WordBreakToken::Word {
22219            token,
22220            grapheme_len,
22221        }
22222    }
22223
22224    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22225        WordBreakToken::InlineWhitespace {
22226            token,
22227            grapheme_len,
22228        }
22229    }
22230
22231    fn newline() -> WordBreakToken<'static> {
22232        WordBreakToken::Newline
22233    }
22234
22235    for (input, result) in tests {
22236        assert_eq!(
22237            WordBreakingTokenizer::new(input)
22238                .collect::<Vec<_>>()
22239                .as_slice(),
22240            *result,
22241        );
22242    }
22243}
22244
22245fn wrap_with_prefix(
22246    first_line_prefix: String,
22247    subsequent_lines_prefix: String,
22248    unwrapped_text: String,
22249    wrap_column: usize,
22250    tab_size: NonZeroU32,
22251    preserve_existing_whitespace: bool,
22252) -> String {
22253    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22254    let subsequent_lines_prefix_len =
22255        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22256    let mut wrapped_text = String::new();
22257    let mut current_line = first_line_prefix;
22258    let mut is_first_line = true;
22259
22260    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22261    let mut current_line_len = first_line_prefix_len;
22262    let mut in_whitespace = false;
22263    for token in tokenizer {
22264        let have_preceding_whitespace = in_whitespace;
22265        match token {
22266            WordBreakToken::Word {
22267                token,
22268                grapheme_len,
22269            } => {
22270                in_whitespace = false;
22271                let current_prefix_len = if is_first_line {
22272                    first_line_prefix_len
22273                } else {
22274                    subsequent_lines_prefix_len
22275                };
22276                if current_line_len + grapheme_len > wrap_column
22277                    && current_line_len != current_prefix_len
22278                {
22279                    wrapped_text.push_str(current_line.trim_end());
22280                    wrapped_text.push('\n');
22281                    is_first_line = false;
22282                    current_line = subsequent_lines_prefix.clone();
22283                    current_line_len = subsequent_lines_prefix_len;
22284                }
22285                current_line.push_str(token);
22286                current_line_len += grapheme_len;
22287            }
22288            WordBreakToken::InlineWhitespace {
22289                mut token,
22290                mut grapheme_len,
22291            } => {
22292                in_whitespace = true;
22293                if have_preceding_whitespace && !preserve_existing_whitespace {
22294                    continue;
22295                }
22296                if !preserve_existing_whitespace {
22297                    token = " ";
22298                    grapheme_len = 1;
22299                }
22300                let current_prefix_len = if is_first_line {
22301                    first_line_prefix_len
22302                } else {
22303                    subsequent_lines_prefix_len
22304                };
22305                if current_line_len + grapheme_len > wrap_column {
22306                    wrapped_text.push_str(current_line.trim_end());
22307                    wrapped_text.push('\n');
22308                    is_first_line = false;
22309                    current_line = subsequent_lines_prefix.clone();
22310                    current_line_len = subsequent_lines_prefix_len;
22311                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22312                    current_line.push_str(token);
22313                    current_line_len += grapheme_len;
22314                }
22315            }
22316            WordBreakToken::Newline => {
22317                in_whitespace = true;
22318                let current_prefix_len = if is_first_line {
22319                    first_line_prefix_len
22320                } else {
22321                    subsequent_lines_prefix_len
22322                };
22323                if preserve_existing_whitespace {
22324                    wrapped_text.push_str(current_line.trim_end());
22325                    wrapped_text.push('\n');
22326                    is_first_line = false;
22327                    current_line = subsequent_lines_prefix.clone();
22328                    current_line_len = subsequent_lines_prefix_len;
22329                } else if have_preceding_whitespace {
22330                    continue;
22331                } else if current_line_len + 1 > wrap_column
22332                    && current_line_len != current_prefix_len
22333                {
22334                    wrapped_text.push_str(current_line.trim_end());
22335                    wrapped_text.push('\n');
22336                    is_first_line = false;
22337                    current_line = subsequent_lines_prefix.clone();
22338                    current_line_len = subsequent_lines_prefix_len;
22339                } else if current_line_len != current_prefix_len {
22340                    current_line.push(' ');
22341                    current_line_len += 1;
22342                }
22343            }
22344        }
22345    }
22346
22347    if !current_line.is_empty() {
22348        wrapped_text.push_str(&current_line);
22349    }
22350    wrapped_text
22351}
22352
22353#[test]
22354fn test_wrap_with_prefix() {
22355    assert_eq!(
22356        wrap_with_prefix(
22357            "# ".to_string(),
22358            "# ".to_string(),
22359            "abcdefg".to_string(),
22360            4,
22361            NonZeroU32::new(4).unwrap(),
22362            false,
22363        ),
22364        "# abcdefg"
22365    );
22366    assert_eq!(
22367        wrap_with_prefix(
22368            "".to_string(),
22369            "".to_string(),
22370            "\thello world".to_string(),
22371            8,
22372            NonZeroU32::new(4).unwrap(),
22373            false,
22374        ),
22375        "hello\nworld"
22376    );
22377    assert_eq!(
22378        wrap_with_prefix(
22379            "// ".to_string(),
22380            "// ".to_string(),
22381            "xx \nyy zz aa bb cc".to_string(),
22382            12,
22383            NonZeroU32::new(4).unwrap(),
22384            false,
22385        ),
22386        "// xx yy zz\n// aa bb cc"
22387    );
22388    assert_eq!(
22389        wrap_with_prefix(
22390            String::new(),
22391            String::new(),
22392            "这是什么 \n 钢笔".to_string(),
22393            3,
22394            NonZeroU32::new(4).unwrap(),
22395            false,
22396        ),
22397        "这是什\n么 钢\n"
22398    );
22399}
22400
22401pub trait CollaborationHub {
22402    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22403    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22404    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22405}
22406
22407impl CollaborationHub for Entity<Project> {
22408    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22409        self.read(cx).collaborators()
22410    }
22411
22412    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22413        self.read(cx).user_store().read(cx).participant_indices()
22414    }
22415
22416    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22417        let this = self.read(cx);
22418        let user_ids = this.collaborators().values().map(|c| c.user_id);
22419        this.user_store().read(cx).participant_names(user_ids, cx)
22420    }
22421}
22422
22423pub trait SemanticsProvider {
22424    fn hover(
22425        &self,
22426        buffer: &Entity<Buffer>,
22427        position: text::Anchor,
22428        cx: &mut App,
22429    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22430
22431    fn inline_values(
22432        &self,
22433        buffer_handle: Entity<Buffer>,
22434        range: Range<text::Anchor>,
22435        cx: &mut App,
22436    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22437
22438    fn inlay_hints(
22439        &self,
22440        buffer_handle: Entity<Buffer>,
22441        range: Range<text::Anchor>,
22442        cx: &mut App,
22443    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22444
22445    fn resolve_inlay_hint(
22446        &self,
22447        hint: InlayHint,
22448        buffer_handle: Entity<Buffer>,
22449        server_id: LanguageServerId,
22450        cx: &mut App,
22451    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22452
22453    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22454
22455    fn document_highlights(
22456        &self,
22457        buffer: &Entity<Buffer>,
22458        position: text::Anchor,
22459        cx: &mut App,
22460    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22461
22462    fn definitions(
22463        &self,
22464        buffer: &Entity<Buffer>,
22465        position: text::Anchor,
22466        kind: GotoDefinitionKind,
22467        cx: &mut App,
22468    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22469
22470    fn range_for_rename(
22471        &self,
22472        buffer: &Entity<Buffer>,
22473        position: text::Anchor,
22474        cx: &mut App,
22475    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22476
22477    fn perform_rename(
22478        &self,
22479        buffer: &Entity<Buffer>,
22480        position: text::Anchor,
22481        new_name: String,
22482        cx: &mut App,
22483    ) -> Option<Task<Result<ProjectTransaction>>>;
22484}
22485
22486pub trait CompletionProvider {
22487    fn completions(
22488        &self,
22489        excerpt_id: ExcerptId,
22490        buffer: &Entity<Buffer>,
22491        buffer_position: text::Anchor,
22492        trigger: CompletionContext,
22493        window: &mut Window,
22494        cx: &mut Context<Editor>,
22495    ) -> Task<Result<Vec<CompletionResponse>>>;
22496
22497    fn resolve_completions(
22498        &self,
22499        _buffer: Entity<Buffer>,
22500        _completion_indices: Vec<usize>,
22501        _completions: Rc<RefCell<Box<[Completion]>>>,
22502        _cx: &mut Context<Editor>,
22503    ) -> Task<Result<bool>> {
22504        Task::ready(Ok(false))
22505    }
22506
22507    fn apply_additional_edits_for_completion(
22508        &self,
22509        _buffer: Entity<Buffer>,
22510        _completions: Rc<RefCell<Box<[Completion]>>>,
22511        _completion_index: usize,
22512        _push_to_history: bool,
22513        _cx: &mut Context<Editor>,
22514    ) -> Task<Result<Option<language::Transaction>>> {
22515        Task::ready(Ok(None))
22516    }
22517
22518    fn is_completion_trigger(
22519        &self,
22520        buffer: &Entity<Buffer>,
22521        position: language::Anchor,
22522        text: &str,
22523        trigger_in_words: bool,
22524        menu_is_open: bool,
22525        cx: &mut Context<Editor>,
22526    ) -> bool;
22527
22528    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22529
22530    fn sort_completions(&self) -> bool {
22531        true
22532    }
22533
22534    fn filter_completions(&self) -> bool {
22535        true
22536    }
22537}
22538
22539pub trait CodeActionProvider {
22540    fn id(&self) -> Arc<str>;
22541
22542    fn code_actions(
22543        &self,
22544        buffer: &Entity<Buffer>,
22545        range: Range<text::Anchor>,
22546        window: &mut Window,
22547        cx: &mut App,
22548    ) -> Task<Result<Vec<CodeAction>>>;
22549
22550    fn apply_code_action(
22551        &self,
22552        buffer_handle: Entity<Buffer>,
22553        action: CodeAction,
22554        excerpt_id: ExcerptId,
22555        push_to_history: bool,
22556        window: &mut Window,
22557        cx: &mut App,
22558    ) -> Task<Result<ProjectTransaction>>;
22559}
22560
22561impl CodeActionProvider for Entity<Project> {
22562    fn id(&self) -> Arc<str> {
22563        "project".into()
22564    }
22565
22566    fn code_actions(
22567        &self,
22568        buffer: &Entity<Buffer>,
22569        range: Range<text::Anchor>,
22570        _window: &mut Window,
22571        cx: &mut App,
22572    ) -> Task<Result<Vec<CodeAction>>> {
22573        self.update(cx, |project, cx| {
22574            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22575            let code_actions = project.code_actions(buffer, range, None, cx);
22576            cx.background_spawn(async move {
22577                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22578                Ok(code_lens_actions
22579                    .context("code lens fetch")?
22580                    .into_iter()
22581                    .flatten()
22582                    .chain(
22583                        code_actions
22584                            .context("code action fetch")?
22585                            .into_iter()
22586                            .flatten(),
22587                    )
22588                    .collect())
22589            })
22590        })
22591    }
22592
22593    fn apply_code_action(
22594        &self,
22595        buffer_handle: Entity<Buffer>,
22596        action: CodeAction,
22597        _excerpt_id: ExcerptId,
22598        push_to_history: bool,
22599        _window: &mut Window,
22600        cx: &mut App,
22601    ) -> Task<Result<ProjectTransaction>> {
22602        self.update(cx, |project, cx| {
22603            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22604        })
22605    }
22606}
22607
22608fn snippet_completions(
22609    project: &Project,
22610    buffer: &Entity<Buffer>,
22611    buffer_position: text::Anchor,
22612    cx: &mut App,
22613) -> Task<Result<CompletionResponse>> {
22614    let languages = buffer.read(cx).languages_at(buffer_position);
22615    let snippet_store = project.snippets().read(cx);
22616
22617    let scopes: Vec<_> = languages
22618        .iter()
22619        .filter_map(|language| {
22620            let language_name = language.lsp_id();
22621            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22622
22623            if snippets.is_empty() {
22624                None
22625            } else {
22626                Some((language.default_scope(), snippets))
22627            }
22628        })
22629        .collect();
22630
22631    if scopes.is_empty() {
22632        return Task::ready(Ok(CompletionResponse {
22633            completions: vec![],
22634            display_options: CompletionDisplayOptions::default(),
22635            is_incomplete: false,
22636        }));
22637    }
22638
22639    let snapshot = buffer.read(cx).text_snapshot();
22640    let chars: String = snapshot
22641        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22642        .collect();
22643    let executor = cx.background_executor().clone();
22644
22645    cx.background_spawn(async move {
22646        let mut is_incomplete = false;
22647        let mut completions: Vec<Completion> = Vec::new();
22648        for (scope, snippets) in scopes.into_iter() {
22649            let classifier =
22650                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22651            let mut last_word = chars
22652                .chars()
22653                .take_while(|c| classifier.is_word(*c))
22654                .collect::<String>();
22655            last_word = last_word.chars().rev().collect();
22656
22657            if last_word.is_empty() {
22658                return Ok(CompletionResponse {
22659                    completions: vec![],
22660                    display_options: CompletionDisplayOptions::default(),
22661                    is_incomplete: true,
22662                });
22663            }
22664
22665            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22666            let to_lsp = |point: &text::Anchor| {
22667                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22668                point_to_lsp(end)
22669            };
22670            let lsp_end = to_lsp(&buffer_position);
22671
22672            let candidates = snippets
22673                .iter()
22674                .enumerate()
22675                .flat_map(|(ix, snippet)| {
22676                    snippet
22677                        .prefix
22678                        .iter()
22679                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22680                })
22681                .collect::<Vec<StringMatchCandidate>>();
22682
22683            const MAX_RESULTS: usize = 100;
22684            let mut matches = fuzzy::match_strings(
22685                &candidates,
22686                &last_word,
22687                last_word.chars().any(|c| c.is_uppercase()),
22688                true,
22689                MAX_RESULTS,
22690                &Default::default(),
22691                executor.clone(),
22692            )
22693            .await;
22694
22695            if matches.len() >= MAX_RESULTS {
22696                is_incomplete = true;
22697            }
22698
22699            // Remove all candidates where the query's start does not match the start of any word in the candidate
22700            if let Some(query_start) = last_word.chars().next() {
22701                matches.retain(|string_match| {
22702                    split_words(&string_match.string).any(|word| {
22703                        // Check that the first codepoint of the word as lowercase matches the first
22704                        // codepoint of the query as lowercase
22705                        word.chars()
22706                            .flat_map(|codepoint| codepoint.to_lowercase())
22707                            .zip(query_start.to_lowercase())
22708                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22709                    })
22710                });
22711            }
22712
22713            let matched_strings = matches
22714                .into_iter()
22715                .map(|m| m.string)
22716                .collect::<HashSet<_>>();
22717
22718            completions.extend(snippets.iter().filter_map(|snippet| {
22719                let matching_prefix = snippet
22720                    .prefix
22721                    .iter()
22722                    .find(|prefix| matched_strings.contains(*prefix))?;
22723                let start = as_offset - last_word.len();
22724                let start = snapshot.anchor_before(start);
22725                let range = start..buffer_position;
22726                let lsp_start = to_lsp(&start);
22727                let lsp_range = lsp::Range {
22728                    start: lsp_start,
22729                    end: lsp_end,
22730                };
22731                Some(Completion {
22732                    replace_range: range,
22733                    new_text: snippet.body.clone(),
22734                    source: CompletionSource::Lsp {
22735                        insert_range: None,
22736                        server_id: LanguageServerId(usize::MAX),
22737                        resolved: true,
22738                        lsp_completion: Box::new(lsp::CompletionItem {
22739                            label: snippet.prefix.first().unwrap().clone(),
22740                            kind: Some(CompletionItemKind::SNIPPET),
22741                            label_details: snippet.description.as_ref().map(|description| {
22742                                lsp::CompletionItemLabelDetails {
22743                                    detail: Some(description.clone()),
22744                                    description: None,
22745                                }
22746                            }),
22747                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22748                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22749                                lsp::InsertReplaceEdit {
22750                                    new_text: snippet.body.clone(),
22751                                    insert: lsp_range,
22752                                    replace: lsp_range,
22753                                },
22754                            )),
22755                            filter_text: Some(snippet.body.clone()),
22756                            sort_text: Some(char::MAX.to_string()),
22757                            ..lsp::CompletionItem::default()
22758                        }),
22759                        lsp_defaults: None,
22760                    },
22761                    label: CodeLabel {
22762                        text: matching_prefix.clone(),
22763                        runs: Vec::new(),
22764                        filter_range: 0..matching_prefix.len(),
22765                    },
22766                    icon_path: None,
22767                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22768                        single_line: snippet.name.clone().into(),
22769                        plain_text: snippet
22770                            .description
22771                            .clone()
22772                            .map(|description| description.into()),
22773                    }),
22774                    insert_text_mode: None,
22775                    confirm: None,
22776                })
22777            }))
22778        }
22779
22780        Ok(CompletionResponse {
22781            completions,
22782            display_options: CompletionDisplayOptions::default(),
22783            is_incomplete,
22784        })
22785    })
22786}
22787
22788impl CompletionProvider for Entity<Project> {
22789    fn completions(
22790        &self,
22791        _excerpt_id: ExcerptId,
22792        buffer: &Entity<Buffer>,
22793        buffer_position: text::Anchor,
22794        options: CompletionContext,
22795        _window: &mut Window,
22796        cx: &mut Context<Editor>,
22797    ) -> Task<Result<Vec<CompletionResponse>>> {
22798        self.update(cx, |project, cx| {
22799            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22800            let project_completions = project.completions(buffer, buffer_position, options, cx);
22801            cx.background_spawn(async move {
22802                let mut responses = project_completions.await?;
22803                let snippets = snippets.await?;
22804                if !snippets.completions.is_empty() {
22805                    responses.push(snippets);
22806                }
22807                Ok(responses)
22808            })
22809        })
22810    }
22811
22812    fn resolve_completions(
22813        &self,
22814        buffer: Entity<Buffer>,
22815        completion_indices: Vec<usize>,
22816        completions: Rc<RefCell<Box<[Completion]>>>,
22817        cx: &mut Context<Editor>,
22818    ) -> Task<Result<bool>> {
22819        self.update(cx, |project, cx| {
22820            project.lsp_store().update(cx, |lsp_store, cx| {
22821                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22822            })
22823        })
22824    }
22825
22826    fn apply_additional_edits_for_completion(
22827        &self,
22828        buffer: Entity<Buffer>,
22829        completions: Rc<RefCell<Box<[Completion]>>>,
22830        completion_index: usize,
22831        push_to_history: bool,
22832        cx: &mut Context<Editor>,
22833    ) -> Task<Result<Option<language::Transaction>>> {
22834        self.update(cx, |project, cx| {
22835            project.lsp_store().update(cx, |lsp_store, cx| {
22836                lsp_store.apply_additional_edits_for_completion(
22837                    buffer,
22838                    completions,
22839                    completion_index,
22840                    push_to_history,
22841                    cx,
22842                )
22843            })
22844        })
22845    }
22846
22847    fn is_completion_trigger(
22848        &self,
22849        buffer: &Entity<Buffer>,
22850        position: language::Anchor,
22851        text: &str,
22852        trigger_in_words: bool,
22853        menu_is_open: bool,
22854        cx: &mut Context<Editor>,
22855    ) -> bool {
22856        let mut chars = text.chars();
22857        let char = if let Some(char) = chars.next() {
22858            char
22859        } else {
22860            return false;
22861        };
22862        if chars.next().is_some() {
22863            return false;
22864        }
22865
22866        let buffer = buffer.read(cx);
22867        let snapshot = buffer.snapshot();
22868        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22869            return false;
22870        }
22871        let classifier = snapshot
22872            .char_classifier_at(position)
22873            .scope_context(Some(CharScopeContext::Completion));
22874        if trigger_in_words && classifier.is_word(char) {
22875            return true;
22876        }
22877
22878        buffer.completion_triggers().contains(text)
22879    }
22880}
22881
22882impl SemanticsProvider for Entity<Project> {
22883    fn hover(
22884        &self,
22885        buffer: &Entity<Buffer>,
22886        position: text::Anchor,
22887        cx: &mut App,
22888    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22889        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22890    }
22891
22892    fn document_highlights(
22893        &self,
22894        buffer: &Entity<Buffer>,
22895        position: text::Anchor,
22896        cx: &mut App,
22897    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22898        Some(self.update(cx, |project, cx| {
22899            project.document_highlights(buffer, position, cx)
22900        }))
22901    }
22902
22903    fn definitions(
22904        &self,
22905        buffer: &Entity<Buffer>,
22906        position: text::Anchor,
22907        kind: GotoDefinitionKind,
22908        cx: &mut App,
22909    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22910        Some(self.update(cx, |project, cx| match kind {
22911            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22912            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22913            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22914            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22915        }))
22916    }
22917
22918    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22919        self.update(cx, |project, cx| {
22920            if project
22921                .active_debug_session(cx)
22922                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22923            {
22924                return true;
22925            }
22926
22927            buffer.update(cx, |buffer, cx| {
22928                project.any_language_server_supports_inlay_hints(buffer, cx)
22929            })
22930        })
22931    }
22932
22933    fn inline_values(
22934        &self,
22935        buffer_handle: Entity<Buffer>,
22936        range: Range<text::Anchor>,
22937        cx: &mut App,
22938    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22939        self.update(cx, |project, cx| {
22940            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22941
22942            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22943        })
22944    }
22945
22946    fn inlay_hints(
22947        &self,
22948        buffer_handle: Entity<Buffer>,
22949        range: Range<text::Anchor>,
22950        cx: &mut App,
22951    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22952        Some(self.update(cx, |project, cx| {
22953            project.inlay_hints(buffer_handle, range, cx)
22954        }))
22955    }
22956
22957    fn resolve_inlay_hint(
22958        &self,
22959        hint: InlayHint,
22960        buffer_handle: Entity<Buffer>,
22961        server_id: LanguageServerId,
22962        cx: &mut App,
22963    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22964        Some(self.update(cx, |project, cx| {
22965            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22966        }))
22967    }
22968
22969    fn range_for_rename(
22970        &self,
22971        buffer: &Entity<Buffer>,
22972        position: text::Anchor,
22973        cx: &mut App,
22974    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22975        Some(self.update(cx, |project, cx| {
22976            let buffer = buffer.clone();
22977            let task = project.prepare_rename(buffer.clone(), position, cx);
22978            cx.spawn(async move |_, cx| {
22979                Ok(match task.await? {
22980                    PrepareRenameResponse::Success(range) => Some(range),
22981                    PrepareRenameResponse::InvalidPosition => None,
22982                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22983                        // Fallback on using TreeSitter info to determine identifier range
22984                        buffer.read_with(cx, |buffer, _| {
22985                            let snapshot = buffer.snapshot();
22986                            let (range, kind) = snapshot.surrounding_word(position, None);
22987                            if kind != Some(CharKind::Word) {
22988                                return None;
22989                            }
22990                            Some(
22991                                snapshot.anchor_before(range.start)
22992                                    ..snapshot.anchor_after(range.end),
22993                            )
22994                        })?
22995                    }
22996                })
22997            })
22998        }))
22999    }
23000
23001    fn perform_rename(
23002        &self,
23003        buffer: &Entity<Buffer>,
23004        position: text::Anchor,
23005        new_name: String,
23006        cx: &mut App,
23007    ) -> Option<Task<Result<ProjectTransaction>>> {
23008        Some(self.update(cx, |project, cx| {
23009            project.perform_rename(buffer.clone(), position, new_name, cx)
23010        }))
23011    }
23012}
23013
23014fn inlay_hint_settings(
23015    location: Anchor,
23016    snapshot: &MultiBufferSnapshot,
23017    cx: &mut Context<Editor>,
23018) -> InlayHintSettings {
23019    let file = snapshot.file_at(location);
23020    let language = snapshot.language_at(location).map(|l| l.name());
23021    language_settings(language, file, cx).inlay_hints
23022}
23023
23024fn consume_contiguous_rows(
23025    contiguous_row_selections: &mut Vec<Selection<Point>>,
23026    selection: &Selection<Point>,
23027    display_map: &DisplaySnapshot,
23028    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23029) -> (MultiBufferRow, MultiBufferRow) {
23030    contiguous_row_selections.push(selection.clone());
23031    let start_row = starting_row(selection, display_map);
23032    let mut end_row = ending_row(selection, display_map);
23033
23034    while let Some(next_selection) = selections.peek() {
23035        if next_selection.start.row <= end_row.0 {
23036            end_row = ending_row(next_selection, display_map);
23037            contiguous_row_selections.push(selections.next().unwrap().clone());
23038        } else {
23039            break;
23040        }
23041    }
23042    (start_row, end_row)
23043}
23044
23045fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23046    if selection.start.column > 0 {
23047        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23048    } else {
23049        MultiBufferRow(selection.start.row)
23050    }
23051}
23052
23053fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23054    if next_selection.end.column > 0 || next_selection.is_empty() {
23055        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23056    } else {
23057        MultiBufferRow(next_selection.end.row)
23058    }
23059}
23060
23061impl EditorSnapshot {
23062    pub fn remote_selections_in_range<'a>(
23063        &'a self,
23064        range: &'a Range<Anchor>,
23065        collaboration_hub: &dyn CollaborationHub,
23066        cx: &'a App,
23067    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23068        let participant_names = collaboration_hub.user_names(cx);
23069        let participant_indices = collaboration_hub.user_participant_indices(cx);
23070        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23071        let collaborators_by_replica_id = collaborators_by_peer_id
23072            .values()
23073            .map(|collaborator| (collaborator.replica_id, collaborator))
23074            .collect::<HashMap<_, _>>();
23075        self.buffer_snapshot
23076            .selections_in_range(range, false)
23077            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23078                if replica_id == AGENT_REPLICA_ID {
23079                    Some(RemoteSelection {
23080                        replica_id,
23081                        selection,
23082                        cursor_shape,
23083                        line_mode,
23084                        collaborator_id: CollaboratorId::Agent,
23085                        user_name: Some("Agent".into()),
23086                        color: cx.theme().players().agent(),
23087                    })
23088                } else {
23089                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23090                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23091                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23092                    Some(RemoteSelection {
23093                        replica_id,
23094                        selection,
23095                        cursor_shape,
23096                        line_mode,
23097                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23098                        user_name,
23099                        color: if let Some(index) = participant_index {
23100                            cx.theme().players().color_for_participant(index.0)
23101                        } else {
23102                            cx.theme().players().absent()
23103                        },
23104                    })
23105                }
23106            })
23107    }
23108
23109    pub fn hunks_for_ranges(
23110        &self,
23111        ranges: impl IntoIterator<Item = Range<Point>>,
23112    ) -> Vec<MultiBufferDiffHunk> {
23113        let mut hunks = Vec::new();
23114        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23115            HashMap::default();
23116        for query_range in ranges {
23117            let query_rows =
23118                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23119            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23120                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23121            ) {
23122                // Include deleted hunks that are adjacent to the query range, because
23123                // otherwise they would be missed.
23124                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23125                if hunk.status().is_deleted() {
23126                    intersects_range |= hunk.row_range.start == query_rows.end;
23127                    intersects_range |= hunk.row_range.end == query_rows.start;
23128                }
23129                if intersects_range {
23130                    if !processed_buffer_rows
23131                        .entry(hunk.buffer_id)
23132                        .or_default()
23133                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23134                    {
23135                        continue;
23136                    }
23137                    hunks.push(hunk);
23138                }
23139            }
23140        }
23141
23142        hunks
23143    }
23144
23145    fn display_diff_hunks_for_rows<'a>(
23146        &'a self,
23147        display_rows: Range<DisplayRow>,
23148        folded_buffers: &'a HashSet<BufferId>,
23149    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23150        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23151        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23152
23153        self.buffer_snapshot
23154            .diff_hunks_in_range(buffer_start..buffer_end)
23155            .filter_map(|hunk| {
23156                if folded_buffers.contains(&hunk.buffer_id) {
23157                    return None;
23158                }
23159
23160                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23161                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23162
23163                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23164                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23165
23166                let display_hunk = if hunk_display_start.column() != 0 {
23167                    DisplayDiffHunk::Folded {
23168                        display_row: hunk_display_start.row(),
23169                    }
23170                } else {
23171                    let mut end_row = hunk_display_end.row();
23172                    if hunk_display_end.column() > 0 {
23173                        end_row.0 += 1;
23174                    }
23175                    let is_created_file = hunk.is_created_file();
23176                    DisplayDiffHunk::Unfolded {
23177                        status: hunk.status(),
23178                        diff_base_byte_range: hunk.diff_base_byte_range,
23179                        display_row_range: hunk_display_start.row()..end_row,
23180                        multi_buffer_range: Anchor::range_in_buffer(
23181                            hunk.excerpt_id,
23182                            hunk.buffer_id,
23183                            hunk.buffer_range,
23184                        ),
23185                        is_created_file,
23186                    }
23187                };
23188
23189                Some(display_hunk)
23190            })
23191    }
23192
23193    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23194        self.display_snapshot.buffer_snapshot.language_at(position)
23195    }
23196
23197    pub fn is_focused(&self) -> bool {
23198        self.is_focused
23199    }
23200
23201    pub fn placeholder_text(&self) -> Option<String> {
23202        self.placeholder_display_snapshot
23203            .as_ref()
23204            .map(|display_map| display_map.text())
23205    }
23206
23207    pub fn scroll_position(&self) -> gpui::Point<f32> {
23208        self.scroll_anchor.scroll_position(&self.display_snapshot)
23209    }
23210
23211    fn gutter_dimensions(
23212        &self,
23213        font_id: FontId,
23214        font_size: Pixels,
23215        max_line_number_width: Pixels,
23216        cx: &App,
23217    ) -> Option<GutterDimensions> {
23218        if !self.show_gutter {
23219            return None;
23220        }
23221
23222        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23223        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23224
23225        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23226            matches!(
23227                ProjectSettings::get_global(cx).git.git_gutter,
23228                GitGutterSetting::TrackedFiles
23229            )
23230        });
23231        let gutter_settings = EditorSettings::get_global(cx).gutter;
23232        let show_line_numbers = self
23233            .show_line_numbers
23234            .unwrap_or(gutter_settings.line_numbers);
23235        let line_gutter_width = if show_line_numbers {
23236            // Avoid flicker-like gutter resizes when the line number gains another digit by
23237            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23238            let min_width_for_number_on_gutter =
23239                ch_advance * gutter_settings.min_line_number_digits as f32;
23240            max_line_number_width.max(min_width_for_number_on_gutter)
23241        } else {
23242            0.0.into()
23243        };
23244
23245        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23246        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23247
23248        let git_blame_entries_width =
23249            self.git_blame_gutter_max_author_length
23250                .map(|max_author_length| {
23251                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23252                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23253
23254                    /// The number of characters to dedicate to gaps and margins.
23255                    const SPACING_WIDTH: usize = 4;
23256
23257                    let max_char_count = max_author_length.min(renderer.max_author_length())
23258                        + ::git::SHORT_SHA_LENGTH
23259                        + MAX_RELATIVE_TIMESTAMP.len()
23260                        + SPACING_WIDTH;
23261
23262                    ch_advance * max_char_count
23263                });
23264
23265        let is_singleton = self.buffer_snapshot.is_singleton();
23266
23267        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23268        left_padding += if !is_singleton {
23269            ch_width * 4.0
23270        } else if show_runnables || show_breakpoints {
23271            ch_width * 3.0
23272        } else if show_git_gutter && show_line_numbers {
23273            ch_width * 2.0
23274        } else if show_git_gutter || show_line_numbers {
23275            ch_width
23276        } else {
23277            px(0.)
23278        };
23279
23280        let shows_folds = is_singleton && gutter_settings.folds;
23281
23282        let right_padding = if shows_folds && show_line_numbers {
23283            ch_width * 4.0
23284        } else if shows_folds || (!is_singleton && show_line_numbers) {
23285            ch_width * 3.0
23286        } else if show_line_numbers {
23287            ch_width
23288        } else {
23289            px(0.)
23290        };
23291
23292        Some(GutterDimensions {
23293            left_padding,
23294            right_padding,
23295            width: line_gutter_width + left_padding + right_padding,
23296            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23297            git_blame_entries_width,
23298        })
23299    }
23300
23301    pub fn render_crease_toggle(
23302        &self,
23303        buffer_row: MultiBufferRow,
23304        row_contains_cursor: bool,
23305        editor: Entity<Editor>,
23306        window: &mut Window,
23307        cx: &mut App,
23308    ) -> Option<AnyElement> {
23309        let folded = self.is_line_folded(buffer_row);
23310        let mut is_foldable = false;
23311
23312        if let Some(crease) = self
23313            .crease_snapshot
23314            .query_row(buffer_row, &self.buffer_snapshot)
23315        {
23316            is_foldable = true;
23317            match crease {
23318                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23319                    if let Some(render_toggle) = render_toggle {
23320                        let toggle_callback =
23321                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23322                                if folded {
23323                                    editor.update(cx, |editor, cx| {
23324                                        editor.fold_at(buffer_row, window, cx)
23325                                    });
23326                                } else {
23327                                    editor.update(cx, |editor, cx| {
23328                                        editor.unfold_at(buffer_row, window, cx)
23329                                    });
23330                                }
23331                            });
23332                        return Some((render_toggle)(
23333                            buffer_row,
23334                            folded,
23335                            toggle_callback,
23336                            window,
23337                            cx,
23338                        ));
23339                    }
23340                }
23341            }
23342        }
23343
23344        is_foldable |= self.starts_indent(buffer_row);
23345
23346        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23347            Some(
23348                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23349                    .toggle_state(folded)
23350                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23351                        if folded {
23352                            this.unfold_at(buffer_row, window, cx);
23353                        } else {
23354                            this.fold_at(buffer_row, window, cx);
23355                        }
23356                    }))
23357                    .into_any_element(),
23358            )
23359        } else {
23360            None
23361        }
23362    }
23363
23364    pub fn render_crease_trailer(
23365        &self,
23366        buffer_row: MultiBufferRow,
23367        window: &mut Window,
23368        cx: &mut App,
23369    ) -> Option<AnyElement> {
23370        let folded = self.is_line_folded(buffer_row);
23371        if let Crease::Inline { render_trailer, .. } = self
23372            .crease_snapshot
23373            .query_row(buffer_row, &self.buffer_snapshot)?
23374        {
23375            let render_trailer = render_trailer.as_ref()?;
23376            Some(render_trailer(buffer_row, folded, window, cx))
23377        } else {
23378            None
23379        }
23380    }
23381}
23382
23383impl Deref for EditorSnapshot {
23384    type Target = DisplaySnapshot;
23385
23386    fn deref(&self) -> &Self::Target {
23387        &self.display_snapshot
23388    }
23389}
23390
23391#[derive(Clone, Debug, PartialEq, Eq)]
23392pub enum EditorEvent {
23393    InputIgnored {
23394        text: Arc<str>,
23395    },
23396    InputHandled {
23397        utf16_range_to_replace: Option<Range<isize>>,
23398        text: Arc<str>,
23399    },
23400    ExcerptsAdded {
23401        buffer: Entity<Buffer>,
23402        predecessor: ExcerptId,
23403        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23404    },
23405    ExcerptsRemoved {
23406        ids: Vec<ExcerptId>,
23407        removed_buffer_ids: Vec<BufferId>,
23408    },
23409    BufferFoldToggled {
23410        ids: Vec<ExcerptId>,
23411        folded: bool,
23412    },
23413    ExcerptsEdited {
23414        ids: Vec<ExcerptId>,
23415    },
23416    ExcerptsExpanded {
23417        ids: Vec<ExcerptId>,
23418    },
23419    BufferEdited,
23420    Edited {
23421        transaction_id: clock::Lamport,
23422    },
23423    Reparsed(BufferId),
23424    Focused,
23425    FocusedIn,
23426    Blurred,
23427    DirtyChanged,
23428    Saved,
23429    TitleChanged,
23430    SelectionsChanged {
23431        local: bool,
23432    },
23433    ScrollPositionChanged {
23434        local: bool,
23435        autoscroll: bool,
23436    },
23437    TransactionUndone {
23438        transaction_id: clock::Lamport,
23439    },
23440    TransactionBegun {
23441        transaction_id: clock::Lamport,
23442    },
23443    CursorShapeChanged,
23444    BreadcrumbsChanged,
23445    PushedToNavHistory {
23446        anchor: Anchor,
23447        is_deactivate: bool,
23448    },
23449}
23450
23451impl EventEmitter<EditorEvent> for Editor {}
23452
23453impl Focusable for Editor {
23454    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23455        self.focus_handle.clone()
23456    }
23457}
23458
23459impl Render for Editor {
23460    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23461        let settings = ThemeSettings::get_global(cx);
23462
23463        let mut text_style = match self.mode {
23464            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23465                color: cx.theme().colors().editor_foreground,
23466                font_family: settings.ui_font.family.clone(),
23467                font_features: settings.ui_font.features.clone(),
23468                font_fallbacks: settings.ui_font.fallbacks.clone(),
23469                font_size: rems(0.875).into(),
23470                font_weight: settings.ui_font.weight,
23471                line_height: relative(settings.buffer_line_height.value()),
23472                ..Default::default()
23473            },
23474            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23475                color: cx.theme().colors().editor_foreground,
23476                font_family: settings.buffer_font.family.clone(),
23477                font_features: settings.buffer_font.features.clone(),
23478                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23479                font_size: settings.buffer_font_size(cx).into(),
23480                font_weight: settings.buffer_font.weight,
23481                line_height: relative(settings.buffer_line_height.value()),
23482                ..Default::default()
23483            },
23484        };
23485        if let Some(text_style_refinement) = &self.text_style_refinement {
23486            text_style.refine(text_style_refinement)
23487        }
23488
23489        let background = match self.mode {
23490            EditorMode::SingleLine => cx.theme().system().transparent,
23491            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23492            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23493            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23494        };
23495
23496        EditorElement::new(
23497            &cx.entity(),
23498            EditorStyle {
23499                background,
23500                border: cx.theme().colors().border,
23501                local_player: cx.theme().players().local(),
23502                text: text_style,
23503                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23504                syntax: cx.theme().syntax().clone(),
23505                status: cx.theme().status().clone(),
23506                inlay_hints_style: make_inlay_hints_style(cx),
23507                edit_prediction_styles: make_suggestion_styles(cx),
23508                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23509                show_underlines: self.diagnostics_enabled(),
23510            },
23511        )
23512    }
23513}
23514
23515impl EntityInputHandler for Editor {
23516    fn text_for_range(
23517        &mut self,
23518        range_utf16: Range<usize>,
23519        adjusted_range: &mut Option<Range<usize>>,
23520        _: &mut Window,
23521        cx: &mut Context<Self>,
23522    ) -> Option<String> {
23523        let snapshot = self.buffer.read(cx).read(cx);
23524        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23525        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23526        if (start.0..end.0) != range_utf16 {
23527            adjusted_range.replace(start.0..end.0);
23528        }
23529        Some(snapshot.text_for_range(start..end).collect())
23530    }
23531
23532    fn selected_text_range(
23533        &mut self,
23534        ignore_disabled_input: bool,
23535        _: &mut Window,
23536        cx: &mut Context<Self>,
23537    ) -> Option<UTF16Selection> {
23538        // Prevent the IME menu from appearing when holding down an alphabetic key
23539        // while input is disabled.
23540        if !ignore_disabled_input && !self.input_enabled {
23541            return None;
23542        }
23543
23544        let selection = self.selections.newest::<OffsetUtf16>(cx);
23545        let range = selection.range();
23546
23547        Some(UTF16Selection {
23548            range: range.start.0..range.end.0,
23549            reversed: selection.reversed,
23550        })
23551    }
23552
23553    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23554        let snapshot = self.buffer.read(cx).read(cx);
23555        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23556        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23557    }
23558
23559    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23560        self.clear_highlights::<InputComposition>(cx);
23561        self.ime_transaction.take();
23562    }
23563
23564    fn replace_text_in_range(
23565        &mut self,
23566        range_utf16: Option<Range<usize>>,
23567        text: &str,
23568        window: &mut Window,
23569        cx: &mut Context<Self>,
23570    ) {
23571        if !self.input_enabled {
23572            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23573            return;
23574        }
23575
23576        self.transact(window, cx, |this, window, cx| {
23577            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23578                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23579                Some(this.selection_replacement_ranges(range_utf16, cx))
23580            } else {
23581                this.marked_text_ranges(cx)
23582            };
23583
23584            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23585                let newest_selection_id = this.selections.newest_anchor().id;
23586                this.selections
23587                    .all::<OffsetUtf16>(cx)
23588                    .iter()
23589                    .zip(ranges_to_replace.iter())
23590                    .find_map(|(selection, range)| {
23591                        if selection.id == newest_selection_id {
23592                            Some(
23593                                (range.start.0 as isize - selection.head().0 as isize)
23594                                    ..(range.end.0 as isize - selection.head().0 as isize),
23595                            )
23596                        } else {
23597                            None
23598                        }
23599                    })
23600            });
23601
23602            cx.emit(EditorEvent::InputHandled {
23603                utf16_range_to_replace: range_to_replace,
23604                text: text.into(),
23605            });
23606
23607            if let Some(new_selected_ranges) = new_selected_ranges {
23608                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23609                    selections.select_ranges(new_selected_ranges)
23610                });
23611                this.backspace(&Default::default(), window, cx);
23612            }
23613
23614            this.handle_input(text, window, cx);
23615        });
23616
23617        if let Some(transaction) = self.ime_transaction {
23618            self.buffer.update(cx, |buffer, cx| {
23619                buffer.group_until_transaction(transaction, cx);
23620            });
23621        }
23622
23623        self.unmark_text(window, cx);
23624    }
23625
23626    fn replace_and_mark_text_in_range(
23627        &mut self,
23628        range_utf16: Option<Range<usize>>,
23629        text: &str,
23630        new_selected_range_utf16: Option<Range<usize>>,
23631        window: &mut Window,
23632        cx: &mut Context<Self>,
23633    ) {
23634        if !self.input_enabled {
23635            return;
23636        }
23637
23638        let transaction = self.transact(window, cx, |this, window, cx| {
23639            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23640                let snapshot = this.buffer.read(cx).read(cx);
23641                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23642                    for marked_range in &mut marked_ranges {
23643                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23644                        marked_range.start.0 += relative_range_utf16.start;
23645                        marked_range.start =
23646                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23647                        marked_range.end =
23648                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23649                    }
23650                }
23651                Some(marked_ranges)
23652            } else if let Some(range_utf16) = range_utf16 {
23653                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23654                Some(this.selection_replacement_ranges(range_utf16, cx))
23655            } else {
23656                None
23657            };
23658
23659            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23660                let newest_selection_id = this.selections.newest_anchor().id;
23661                this.selections
23662                    .all::<OffsetUtf16>(cx)
23663                    .iter()
23664                    .zip(ranges_to_replace.iter())
23665                    .find_map(|(selection, range)| {
23666                        if selection.id == newest_selection_id {
23667                            Some(
23668                                (range.start.0 as isize - selection.head().0 as isize)
23669                                    ..(range.end.0 as isize - selection.head().0 as isize),
23670                            )
23671                        } else {
23672                            None
23673                        }
23674                    })
23675            });
23676
23677            cx.emit(EditorEvent::InputHandled {
23678                utf16_range_to_replace: range_to_replace,
23679                text: text.into(),
23680            });
23681
23682            if let Some(ranges) = ranges_to_replace {
23683                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23684                    s.select_ranges(ranges)
23685                });
23686            }
23687
23688            let marked_ranges = {
23689                let snapshot = this.buffer.read(cx).read(cx);
23690                this.selections
23691                    .disjoint_anchors_arc()
23692                    .iter()
23693                    .map(|selection| {
23694                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23695                    })
23696                    .collect::<Vec<_>>()
23697            };
23698
23699            if text.is_empty() {
23700                this.unmark_text(window, cx);
23701            } else {
23702                this.highlight_text::<InputComposition>(
23703                    marked_ranges.clone(),
23704                    HighlightStyle {
23705                        underline: Some(UnderlineStyle {
23706                            thickness: px(1.),
23707                            color: None,
23708                            wavy: false,
23709                        }),
23710                        ..Default::default()
23711                    },
23712                    cx,
23713                );
23714            }
23715
23716            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23717            let use_autoclose = this.use_autoclose;
23718            let use_auto_surround = this.use_auto_surround;
23719            this.set_use_autoclose(false);
23720            this.set_use_auto_surround(false);
23721            this.handle_input(text, window, cx);
23722            this.set_use_autoclose(use_autoclose);
23723            this.set_use_auto_surround(use_auto_surround);
23724
23725            if let Some(new_selected_range) = new_selected_range_utf16 {
23726                let snapshot = this.buffer.read(cx).read(cx);
23727                let new_selected_ranges = marked_ranges
23728                    .into_iter()
23729                    .map(|marked_range| {
23730                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23731                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23732                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23733                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23734                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23735                    })
23736                    .collect::<Vec<_>>();
23737
23738                drop(snapshot);
23739                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23740                    selections.select_ranges(new_selected_ranges)
23741                });
23742            }
23743        });
23744
23745        self.ime_transaction = self.ime_transaction.or(transaction);
23746        if let Some(transaction) = self.ime_transaction {
23747            self.buffer.update(cx, |buffer, cx| {
23748                buffer.group_until_transaction(transaction, cx);
23749            });
23750        }
23751
23752        if self.text_highlights::<InputComposition>(cx).is_none() {
23753            self.ime_transaction.take();
23754        }
23755    }
23756
23757    fn bounds_for_range(
23758        &mut self,
23759        range_utf16: Range<usize>,
23760        element_bounds: gpui::Bounds<Pixels>,
23761        window: &mut Window,
23762        cx: &mut Context<Self>,
23763    ) -> Option<gpui::Bounds<Pixels>> {
23764        let text_layout_details = self.text_layout_details(window);
23765        let CharacterDimensions {
23766            em_width,
23767            em_advance,
23768            line_height,
23769        } = self.character_dimensions(window);
23770
23771        let snapshot = self.snapshot(window, cx);
23772        let scroll_position = snapshot.scroll_position();
23773        let scroll_left = scroll_position.x * em_advance;
23774
23775        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23776        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23777            + self.gutter_dimensions.full_width();
23778        let y = line_height * (start.row().as_f32() - scroll_position.y);
23779
23780        Some(Bounds {
23781            origin: element_bounds.origin + point(x, y),
23782            size: size(em_width, line_height),
23783        })
23784    }
23785
23786    fn character_index_for_point(
23787        &mut self,
23788        point: gpui::Point<Pixels>,
23789        _window: &mut Window,
23790        _cx: &mut Context<Self>,
23791    ) -> Option<usize> {
23792        let position_map = self.last_position_map.as_ref()?;
23793        if !position_map.text_hitbox.contains(&point) {
23794            return None;
23795        }
23796        let display_point = position_map.point_for_position(point).previous_valid;
23797        let anchor = position_map
23798            .snapshot
23799            .display_point_to_anchor(display_point, Bias::Left);
23800        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23801        Some(utf16_offset.0)
23802    }
23803}
23804
23805trait SelectionExt {
23806    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23807    fn spanned_rows(
23808        &self,
23809        include_end_if_at_line_start: bool,
23810        map: &DisplaySnapshot,
23811    ) -> Range<MultiBufferRow>;
23812}
23813
23814impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23815    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23816        let start = self
23817            .start
23818            .to_point(&map.buffer_snapshot)
23819            .to_display_point(map);
23820        let end = self
23821            .end
23822            .to_point(&map.buffer_snapshot)
23823            .to_display_point(map);
23824        if self.reversed {
23825            end..start
23826        } else {
23827            start..end
23828        }
23829    }
23830
23831    fn spanned_rows(
23832        &self,
23833        include_end_if_at_line_start: bool,
23834        map: &DisplaySnapshot,
23835    ) -> Range<MultiBufferRow> {
23836        let start = self.start.to_point(&map.buffer_snapshot);
23837        let mut end = self.end.to_point(&map.buffer_snapshot);
23838        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23839            end.row -= 1;
23840        }
23841
23842        let buffer_start = map.prev_line_boundary(start).0;
23843        let buffer_end = map.next_line_boundary(end).0;
23844        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23845    }
23846}
23847
23848impl<T: InvalidationRegion> InvalidationStack<T> {
23849    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23850    where
23851        S: Clone + ToOffset,
23852    {
23853        while let Some(region) = self.last() {
23854            let all_selections_inside_invalidation_ranges =
23855                if selections.len() == region.ranges().len() {
23856                    selections
23857                        .iter()
23858                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23859                        .all(|(selection, invalidation_range)| {
23860                            let head = selection.head().to_offset(buffer);
23861                            invalidation_range.start <= head && invalidation_range.end >= head
23862                        })
23863                } else {
23864                    false
23865                };
23866
23867            if all_selections_inside_invalidation_ranges {
23868                break;
23869            } else {
23870                self.pop();
23871            }
23872        }
23873    }
23874}
23875
23876impl<T> Default for InvalidationStack<T> {
23877    fn default() -> Self {
23878        Self(Default::default())
23879    }
23880}
23881
23882impl<T> Deref for InvalidationStack<T> {
23883    type Target = Vec<T>;
23884
23885    fn deref(&self) -> &Self::Target {
23886        &self.0
23887    }
23888}
23889
23890impl<T> DerefMut for InvalidationStack<T> {
23891    fn deref_mut(&mut self) -> &mut Self::Target {
23892        &mut self.0
23893    }
23894}
23895
23896impl InvalidationRegion for SnippetState {
23897    fn ranges(&self) -> &[Range<Anchor>] {
23898        &self.ranges[self.active_index]
23899    }
23900}
23901
23902fn edit_prediction_edit_text(
23903    current_snapshot: &BufferSnapshot,
23904    edits: &[(Range<Anchor>, String)],
23905    edit_preview: &EditPreview,
23906    include_deletions: bool,
23907    cx: &App,
23908) -> HighlightedText {
23909    let edits = edits
23910        .iter()
23911        .map(|(anchor, text)| {
23912            (
23913                anchor.start.text_anchor..anchor.end.text_anchor,
23914                text.clone(),
23915            )
23916        })
23917        .collect::<Vec<_>>();
23918
23919    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23920}
23921
23922fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23923    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23924    // Just show the raw edit text with basic styling
23925    let mut text = String::new();
23926    let mut highlights = Vec::new();
23927
23928    let insertion_highlight_style = HighlightStyle {
23929        color: Some(cx.theme().colors().text),
23930        ..Default::default()
23931    };
23932
23933    for (_, edit_text) in edits {
23934        let start_offset = text.len();
23935        text.push_str(edit_text);
23936        let end_offset = text.len();
23937
23938        if start_offset < end_offset {
23939            highlights.push((start_offset..end_offset, insertion_highlight_style));
23940        }
23941    }
23942
23943    HighlightedText {
23944        text: text.into(),
23945        highlights,
23946    }
23947}
23948
23949pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23950    match severity {
23951        lsp::DiagnosticSeverity::ERROR => colors.error,
23952        lsp::DiagnosticSeverity::WARNING => colors.warning,
23953        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23954        lsp::DiagnosticSeverity::HINT => colors.info,
23955        _ => colors.ignored,
23956    }
23957}
23958
23959pub fn styled_runs_for_code_label<'a>(
23960    label: &'a CodeLabel,
23961    syntax_theme: &'a theme::SyntaxTheme,
23962) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23963    let fade_out = HighlightStyle {
23964        fade_out: Some(0.35),
23965        ..Default::default()
23966    };
23967
23968    let mut prev_end = label.filter_range.end;
23969    label
23970        .runs
23971        .iter()
23972        .enumerate()
23973        .flat_map(move |(ix, (range, highlight_id))| {
23974            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23975                style
23976            } else {
23977                return Default::default();
23978            };
23979            let muted_style = style.highlight(fade_out);
23980
23981            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23982            if range.start >= label.filter_range.end {
23983                if range.start > prev_end {
23984                    runs.push((prev_end..range.start, fade_out));
23985                }
23986                runs.push((range.clone(), muted_style));
23987            } else if range.end <= label.filter_range.end {
23988                runs.push((range.clone(), style));
23989            } else {
23990                runs.push((range.start..label.filter_range.end, style));
23991                runs.push((label.filter_range.end..range.end, muted_style));
23992            }
23993            prev_end = cmp::max(prev_end, range.end);
23994
23995            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23996                runs.push((prev_end..label.text.len(), fade_out));
23997            }
23998
23999            runs
24000        })
24001}
24002
24003pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24004    let mut prev_index = 0;
24005    let mut prev_codepoint: Option<char> = None;
24006    text.char_indices()
24007        .chain([(text.len(), '\0')])
24008        .filter_map(move |(index, codepoint)| {
24009            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24010            let is_boundary = index == text.len()
24011                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24012                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24013            if is_boundary {
24014                let chunk = &text[prev_index..index];
24015                prev_index = index;
24016                Some(chunk)
24017            } else {
24018                None
24019            }
24020        })
24021}
24022
24023pub trait RangeToAnchorExt: Sized {
24024    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24025
24026    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24027        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24028        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24029    }
24030}
24031
24032impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24033    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24034        let start_offset = self.start.to_offset(snapshot);
24035        let end_offset = self.end.to_offset(snapshot);
24036        if start_offset == end_offset {
24037            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24038        } else {
24039            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24040        }
24041    }
24042}
24043
24044pub trait RowExt {
24045    fn as_f32(&self) -> f32;
24046
24047    fn next_row(&self) -> Self;
24048
24049    fn previous_row(&self) -> Self;
24050
24051    fn minus(&self, other: Self) -> u32;
24052}
24053
24054impl RowExt for DisplayRow {
24055    fn as_f32(&self) -> f32 {
24056        self.0 as f32
24057    }
24058
24059    fn next_row(&self) -> Self {
24060        Self(self.0 + 1)
24061    }
24062
24063    fn previous_row(&self) -> Self {
24064        Self(self.0.saturating_sub(1))
24065    }
24066
24067    fn minus(&self, other: Self) -> u32 {
24068        self.0 - other.0
24069    }
24070}
24071
24072impl RowExt for MultiBufferRow {
24073    fn as_f32(&self) -> f32 {
24074        self.0 as f32
24075    }
24076
24077    fn next_row(&self) -> Self {
24078        Self(self.0 + 1)
24079    }
24080
24081    fn previous_row(&self) -> Self {
24082        Self(self.0.saturating_sub(1))
24083    }
24084
24085    fn minus(&self, other: Self) -> u32 {
24086        self.0 - other.0
24087    }
24088}
24089
24090trait RowRangeExt {
24091    type Row;
24092
24093    fn len(&self) -> usize;
24094
24095    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24096}
24097
24098impl RowRangeExt for Range<MultiBufferRow> {
24099    type Row = MultiBufferRow;
24100
24101    fn len(&self) -> usize {
24102        (self.end.0 - self.start.0) as usize
24103    }
24104
24105    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24106        (self.start.0..self.end.0).map(MultiBufferRow)
24107    }
24108}
24109
24110impl RowRangeExt for Range<DisplayRow> {
24111    type Row = DisplayRow;
24112
24113    fn len(&self) -> usize {
24114        (self.end.0 - self.start.0) as usize
24115    }
24116
24117    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24118        (self.start.0..self.end.0).map(DisplayRow)
24119    }
24120}
24121
24122/// If select range has more than one line, we
24123/// just point the cursor to range.start.
24124fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24125    if range.start.row == range.end.row {
24126        range
24127    } else {
24128        range.start..range.start
24129    }
24130}
24131pub struct KillRing(ClipboardItem);
24132impl Global for KillRing {}
24133
24134const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24135
24136enum BreakpointPromptEditAction {
24137    Log,
24138    Condition,
24139    HitCondition,
24140}
24141
24142struct BreakpointPromptEditor {
24143    pub(crate) prompt: Entity<Editor>,
24144    editor: WeakEntity<Editor>,
24145    breakpoint_anchor: Anchor,
24146    breakpoint: Breakpoint,
24147    edit_action: BreakpointPromptEditAction,
24148    block_ids: HashSet<CustomBlockId>,
24149    editor_margins: Arc<Mutex<EditorMargins>>,
24150    _subscriptions: Vec<Subscription>,
24151}
24152
24153impl BreakpointPromptEditor {
24154    const MAX_LINES: u8 = 4;
24155
24156    fn new(
24157        editor: WeakEntity<Editor>,
24158        breakpoint_anchor: Anchor,
24159        breakpoint: Breakpoint,
24160        edit_action: BreakpointPromptEditAction,
24161        window: &mut Window,
24162        cx: &mut Context<Self>,
24163    ) -> Self {
24164        let base_text = match edit_action {
24165            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24166            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24167            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24168        }
24169        .map(|msg| msg.to_string())
24170        .unwrap_or_default();
24171
24172        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24173        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24174
24175        let prompt = cx.new(|cx| {
24176            let mut prompt = Editor::new(
24177                EditorMode::AutoHeight {
24178                    min_lines: 1,
24179                    max_lines: Some(Self::MAX_LINES as usize),
24180                },
24181                buffer,
24182                None,
24183                window,
24184                cx,
24185            );
24186            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24187            prompt.set_show_cursor_when_unfocused(false, cx);
24188            prompt.set_placeholder_text(
24189                match edit_action {
24190                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24191                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24192                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24193                },
24194                window,
24195                cx,
24196            );
24197
24198            prompt
24199        });
24200
24201        Self {
24202            prompt,
24203            editor,
24204            breakpoint_anchor,
24205            breakpoint,
24206            edit_action,
24207            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24208            block_ids: Default::default(),
24209            _subscriptions: vec![],
24210        }
24211    }
24212
24213    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24214        self.block_ids.extend(block_ids)
24215    }
24216
24217    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24218        if let Some(editor) = self.editor.upgrade() {
24219            let message = self
24220                .prompt
24221                .read(cx)
24222                .buffer
24223                .read(cx)
24224                .as_singleton()
24225                .expect("A multi buffer in breakpoint prompt isn't possible")
24226                .read(cx)
24227                .as_rope()
24228                .to_string();
24229
24230            editor.update(cx, |editor, cx| {
24231                editor.edit_breakpoint_at_anchor(
24232                    self.breakpoint_anchor,
24233                    self.breakpoint.clone(),
24234                    match self.edit_action {
24235                        BreakpointPromptEditAction::Log => {
24236                            BreakpointEditAction::EditLogMessage(message.into())
24237                        }
24238                        BreakpointPromptEditAction::Condition => {
24239                            BreakpointEditAction::EditCondition(message.into())
24240                        }
24241                        BreakpointPromptEditAction::HitCondition => {
24242                            BreakpointEditAction::EditHitCondition(message.into())
24243                        }
24244                    },
24245                    cx,
24246                );
24247
24248                editor.remove_blocks(self.block_ids.clone(), None, cx);
24249                cx.focus_self(window);
24250            });
24251        }
24252    }
24253
24254    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24255        self.editor
24256            .update(cx, |editor, cx| {
24257                editor.remove_blocks(self.block_ids.clone(), None, cx);
24258                window.focus(&editor.focus_handle);
24259            })
24260            .log_err();
24261    }
24262
24263    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24264        let settings = ThemeSettings::get_global(cx);
24265        let text_style = TextStyle {
24266            color: if self.prompt.read(cx).read_only(cx) {
24267                cx.theme().colors().text_disabled
24268            } else {
24269                cx.theme().colors().text
24270            },
24271            font_family: settings.buffer_font.family.clone(),
24272            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24273            font_size: settings.buffer_font_size(cx).into(),
24274            font_weight: settings.buffer_font.weight,
24275            line_height: relative(settings.buffer_line_height.value()),
24276            ..Default::default()
24277        };
24278        EditorElement::new(
24279            &self.prompt,
24280            EditorStyle {
24281                background: cx.theme().colors().editor_background,
24282                local_player: cx.theme().players().local(),
24283                text: text_style,
24284                ..Default::default()
24285            },
24286        )
24287    }
24288}
24289
24290impl Render for BreakpointPromptEditor {
24291    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24292        let editor_margins = *self.editor_margins.lock();
24293        let gutter_dimensions = editor_margins.gutter;
24294        h_flex()
24295            .key_context("Editor")
24296            .bg(cx.theme().colors().editor_background)
24297            .border_y_1()
24298            .border_color(cx.theme().status().info_border)
24299            .size_full()
24300            .py(window.line_height() / 2.5)
24301            .on_action(cx.listener(Self::confirm))
24302            .on_action(cx.listener(Self::cancel))
24303            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24304            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24305    }
24306}
24307
24308impl Focusable for BreakpointPromptEditor {
24309    fn focus_handle(&self, cx: &App) -> FocusHandle {
24310        self.prompt.focus_handle(cx)
24311    }
24312}
24313
24314fn all_edits_insertions_or_deletions(
24315    edits: &Vec<(Range<Anchor>, String)>,
24316    snapshot: &MultiBufferSnapshot,
24317) -> bool {
24318    let mut all_insertions = true;
24319    let mut all_deletions = true;
24320
24321    for (range, new_text) in edits.iter() {
24322        let range_is_empty = range.to_offset(snapshot).is_empty();
24323        let text_is_empty = new_text.is_empty();
24324
24325        if range_is_empty != text_is_empty {
24326            if range_is_empty {
24327                all_deletions = false;
24328            } else {
24329                all_insertions = false;
24330            }
24331        } else {
24332            return false;
24333        }
24334
24335        if !all_insertions && !all_deletions {
24336            return false;
24337        }
24338    }
24339    all_insertions || all_deletions
24340}
24341
24342struct MissingEditPredictionKeybindingTooltip;
24343
24344impl Render for MissingEditPredictionKeybindingTooltip {
24345    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24346        ui::tooltip_container(window, cx, |container, _, cx| {
24347            container
24348                .flex_shrink_0()
24349                .max_w_80()
24350                .min_h(rems_from_px(124.))
24351                .justify_between()
24352                .child(
24353                    v_flex()
24354                        .flex_1()
24355                        .text_ui_sm(cx)
24356                        .child(Label::new("Conflict with Accept Keybinding"))
24357                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24358                )
24359                .child(
24360                    h_flex()
24361                        .pb_1()
24362                        .gap_1()
24363                        .items_end()
24364                        .w_full()
24365                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24366                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24367                        }))
24368                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24369                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24370                        })),
24371                )
24372        })
24373    }
24374}
24375
24376#[derive(Debug, Clone, Copy, PartialEq)]
24377pub struct LineHighlight {
24378    pub background: Background,
24379    pub border: Option<gpui::Hsla>,
24380    pub include_gutter: bool,
24381    pub type_id: Option<TypeId>,
24382}
24383
24384struct LineManipulationResult {
24385    pub new_text: String,
24386    pub line_count_before: usize,
24387    pub line_count_after: usize,
24388}
24389
24390fn render_diff_hunk_controls(
24391    row: u32,
24392    status: &DiffHunkStatus,
24393    hunk_range: Range<Anchor>,
24394    is_created_file: bool,
24395    line_height: Pixels,
24396    editor: &Entity<Editor>,
24397    _window: &mut Window,
24398    cx: &mut App,
24399) -> AnyElement {
24400    h_flex()
24401        .h(line_height)
24402        .mr_1()
24403        .gap_1()
24404        .px_0p5()
24405        .pb_1()
24406        .border_x_1()
24407        .border_b_1()
24408        .border_color(cx.theme().colors().border_variant)
24409        .rounded_b_lg()
24410        .bg(cx.theme().colors().editor_background)
24411        .gap_1()
24412        .block_mouse_except_scroll()
24413        .shadow_md()
24414        .child(if status.has_secondary_hunk() {
24415            Button::new(("stage", row as u64), "Stage")
24416                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24417                .tooltip({
24418                    let focus_handle = editor.focus_handle(cx);
24419                    move |window, cx| {
24420                        Tooltip::for_action_in(
24421                            "Stage Hunk",
24422                            &::git::ToggleStaged,
24423                            &focus_handle,
24424                            window,
24425                            cx,
24426                        )
24427                    }
24428                })
24429                .on_click({
24430                    let editor = editor.clone();
24431                    move |_event, _window, cx| {
24432                        editor.update(cx, |editor, cx| {
24433                            editor.stage_or_unstage_diff_hunks(
24434                                true,
24435                                vec![hunk_range.start..hunk_range.start],
24436                                cx,
24437                            );
24438                        });
24439                    }
24440                })
24441        } else {
24442            Button::new(("unstage", row as u64), "Unstage")
24443                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24444                .tooltip({
24445                    let focus_handle = editor.focus_handle(cx);
24446                    move |window, cx| {
24447                        Tooltip::for_action_in(
24448                            "Unstage Hunk",
24449                            &::git::ToggleStaged,
24450                            &focus_handle,
24451                            window,
24452                            cx,
24453                        )
24454                    }
24455                })
24456                .on_click({
24457                    let editor = editor.clone();
24458                    move |_event, _window, cx| {
24459                        editor.update(cx, |editor, cx| {
24460                            editor.stage_or_unstage_diff_hunks(
24461                                false,
24462                                vec![hunk_range.start..hunk_range.start],
24463                                cx,
24464                            );
24465                        });
24466                    }
24467                })
24468        })
24469        .child(
24470            Button::new(("restore", row as u64), "Restore")
24471                .tooltip({
24472                    let focus_handle = editor.focus_handle(cx);
24473                    move |window, cx| {
24474                        Tooltip::for_action_in(
24475                            "Restore Hunk",
24476                            &::git::Restore,
24477                            &focus_handle,
24478                            window,
24479                            cx,
24480                        )
24481                    }
24482                })
24483                .on_click({
24484                    let editor = editor.clone();
24485                    move |_event, window, cx| {
24486                        editor.update(cx, |editor, cx| {
24487                            let snapshot = editor.snapshot(window, cx);
24488                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24489                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24490                        });
24491                    }
24492                })
24493                .disabled(is_created_file),
24494        )
24495        .when(
24496            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24497            |el| {
24498                el.child(
24499                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24500                        .shape(IconButtonShape::Square)
24501                        .icon_size(IconSize::Small)
24502                        // .disabled(!has_multiple_hunks)
24503                        .tooltip({
24504                            let focus_handle = editor.focus_handle(cx);
24505                            move |window, cx| {
24506                                Tooltip::for_action_in(
24507                                    "Next Hunk",
24508                                    &GoToHunk,
24509                                    &focus_handle,
24510                                    window,
24511                                    cx,
24512                                )
24513                            }
24514                        })
24515                        .on_click({
24516                            let editor = editor.clone();
24517                            move |_event, window, cx| {
24518                                editor.update(cx, |editor, cx| {
24519                                    let snapshot = editor.snapshot(window, cx);
24520                                    let position =
24521                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24522                                    editor.go_to_hunk_before_or_after_position(
24523                                        &snapshot,
24524                                        position,
24525                                        Direction::Next,
24526                                        window,
24527                                        cx,
24528                                    );
24529                                    editor.expand_selected_diff_hunks(cx);
24530                                });
24531                            }
24532                        }),
24533                )
24534                .child(
24535                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24536                        .shape(IconButtonShape::Square)
24537                        .icon_size(IconSize::Small)
24538                        // .disabled(!has_multiple_hunks)
24539                        .tooltip({
24540                            let focus_handle = editor.focus_handle(cx);
24541                            move |window, cx| {
24542                                Tooltip::for_action_in(
24543                                    "Previous Hunk",
24544                                    &GoToPreviousHunk,
24545                                    &focus_handle,
24546                                    window,
24547                                    cx,
24548                                )
24549                            }
24550                        })
24551                        .on_click({
24552                            let editor = editor.clone();
24553                            move |_event, window, cx| {
24554                                editor.update(cx, |editor, cx| {
24555                                    let snapshot = editor.snapshot(window, cx);
24556                                    let point =
24557                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24558                                    editor.go_to_hunk_before_or_after_position(
24559                                        &snapshot,
24560                                        point,
24561                                        Direction::Prev,
24562                                        window,
24563                                        cx,
24564                                    );
24565                                    editor.expand_selected_diff_hunks(cx);
24566                                });
24567                            }
24568                        }),
24569                )
24570            },
24571        )
24572        .into_any_element()
24573}
24574
24575pub fn multibuffer_context_lines(cx: &App) -> u32 {
24576    EditorSettings::try_get(cx)
24577        .map(|settings| settings.excerpt_context_lines)
24578        .unwrap_or(2)
24579        .min(32)
24580}