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    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    Move {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645}
  646
  647struct EditPredictionState {
  648    inlay_ids: Vec<InlayId>,
  649    completion: EditPrediction,
  650    completion_id: Option<SharedString>,
  651    invalidation_range: Range<Anchor>,
  652}
  653
  654enum EditPredictionSettings {
  655    Disabled,
  656    Enabled {
  657        show_in_menu: bool,
  658        preview_requires_modifier: bool,
  659    },
  660}
  661
  662enum EditPredictionHighlight {}
  663
  664#[derive(Debug, Clone)]
  665struct InlineDiagnostic {
  666    message: SharedString,
  667    group_id: usize,
  668    is_primary: bool,
  669    start: Point,
  670    severity: lsp::DiagnosticSeverity,
  671}
  672
  673pub enum MenuEditPredictionsPolicy {
  674    Never,
  675    ByProvider,
  676}
  677
  678pub enum EditPredictionPreview {
  679    /// Modifier is not pressed
  680    Inactive { released_too_fast: bool },
  681    /// Modifier pressed
  682    Active {
  683        since: Instant,
  684        previous_scroll_position: Option<ScrollAnchor>,
  685    },
  686}
  687
  688impl EditPredictionPreview {
  689    pub fn released_too_fast(&self) -> bool {
  690        match self {
  691            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  692            EditPredictionPreview::Active { .. } => false,
  693        }
  694    }
  695
  696    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  697        if let EditPredictionPreview::Active {
  698            previous_scroll_position,
  699            ..
  700        } = self
  701        {
  702            *previous_scroll_position = scroll_position;
  703        }
  704    }
  705}
  706
  707pub struct ContextMenuOptions {
  708    pub min_entries_visible: usize,
  709    pub max_entries_visible: usize,
  710    pub placement: Option<ContextMenuPlacement>,
  711}
  712
  713#[derive(Debug, Clone, PartialEq, Eq)]
  714pub enum ContextMenuPlacement {
  715    Above,
  716    Below,
  717}
  718
  719#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  720struct EditorActionId(usize);
  721
  722impl EditorActionId {
  723    pub fn post_inc(&mut self) -> Self {
  724        let answer = self.0;
  725
  726        *self = Self(answer + 1);
  727
  728        Self(answer)
  729    }
  730}
  731
  732// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  733// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  734
  735type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  736type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  737
  738#[derive(Default)]
  739struct ScrollbarMarkerState {
  740    scrollbar_size: Size<Pixels>,
  741    dirty: bool,
  742    markers: Arc<[PaintQuad]>,
  743    pending_refresh: Option<Task<Result<()>>>,
  744}
  745
  746impl ScrollbarMarkerState {
  747    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  748        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  749    }
  750}
  751
  752#[derive(Clone, Copy, PartialEq, Eq)]
  753pub enum MinimapVisibility {
  754    Disabled,
  755    Enabled {
  756        /// The configuration currently present in the users settings.
  757        setting_configuration: bool,
  758        /// Whether to override the currently set visibility from the users setting.
  759        toggle_override: bool,
  760    },
  761}
  762
  763impl MinimapVisibility {
  764    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  765        if mode.is_full() {
  766            Self::Enabled {
  767                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  768                toggle_override: false,
  769            }
  770        } else {
  771            Self::Disabled
  772        }
  773    }
  774
  775    fn hidden(&self) -> Self {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => Self::Enabled {
  781                setting_configuration,
  782                toggle_override: setting_configuration,
  783            },
  784            Self::Disabled => Self::Disabled,
  785        }
  786    }
  787
  788    fn disabled(&self) -> bool {
  789        matches!(*self, Self::Disabled)
  790    }
  791
  792    fn settings_visibility(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                ..
  797            } => setting_configuration,
  798            _ => false,
  799        }
  800    }
  801
  802    fn visible(&self) -> bool {
  803        match *self {
  804            Self::Enabled {
  805                setting_configuration,
  806                toggle_override,
  807            } => setting_configuration ^ toggle_override,
  808            _ => false,
  809        }
  810    }
  811
  812    fn toggle_visibility(&self) -> Self {
  813        match *self {
  814            Self::Enabled {
  815                toggle_override,
  816                setting_configuration,
  817            } => Self::Enabled {
  818                setting_configuration,
  819                toggle_override: !toggle_override,
  820            },
  821            Self::Disabled => Self::Disabled,
  822        }
  823    }
  824}
  825
  826#[derive(Clone, Debug)]
  827struct RunnableTasks {
  828    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  829    offset: multi_buffer::Anchor,
  830    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  831    column: u32,
  832    // Values of all named captures, including those starting with '_'
  833    extra_variables: HashMap<String, String>,
  834    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  835    context_range: Range<BufferOffset>,
  836}
  837
  838impl RunnableTasks {
  839    fn resolve<'a>(
  840        &'a self,
  841        cx: &'a task::TaskContext,
  842    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  843        self.templates.iter().filter_map(|(kind, template)| {
  844            template
  845                .resolve_task(&kind.to_id_base(), cx)
  846                .map(|task| (kind.clone(), task))
  847        })
  848    }
  849}
  850
  851#[derive(Clone)]
  852pub struct ResolvedTasks {
  853    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  854    position: Anchor,
  855}
  856
  857#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  858struct BufferOffset(usize);
  859
  860/// Addons allow storing per-editor state in other crates (e.g. Vim)
  861pub trait Addon: 'static {
  862    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  863
  864    fn render_buffer_header_controls(
  865        &self,
  866        _: &ExcerptInfo,
  867        _: &Window,
  868        _: &App,
  869    ) -> Option<AnyElement> {
  870        None
  871    }
  872
  873    fn to_any(&self) -> &dyn std::any::Any;
  874
  875    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  876        None
  877    }
  878}
  879
  880struct ChangeLocation {
  881    current: Option<Vec<Anchor>>,
  882    original: Vec<Anchor>,
  883}
  884impl ChangeLocation {
  885    fn locations(&self) -> &[Anchor] {
  886        self.current.as_ref().unwrap_or(&self.original)
  887    }
  888}
  889
  890/// A set of caret positions, registered when the editor was edited.
  891pub struct ChangeList {
  892    changes: Vec<ChangeLocation>,
  893    /// Currently "selected" change.
  894    position: Option<usize>,
  895}
  896
  897impl ChangeList {
  898    pub fn new() -> Self {
  899        Self {
  900            changes: Vec::new(),
  901            position: None,
  902        }
  903    }
  904
  905    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  906    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  907    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  908        if self.changes.is_empty() {
  909            return None;
  910        }
  911
  912        let prev = self.position.unwrap_or(self.changes.len());
  913        let next = if direction == Direction::Prev {
  914            prev.saturating_sub(count)
  915        } else {
  916            (prev + count).min(self.changes.len() - 1)
  917        };
  918        self.position = Some(next);
  919        self.changes.get(next).map(|change| change.locations())
  920    }
  921
  922    /// Adds a new change to the list, resetting the change list position.
  923    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  924        self.position.take();
  925        if let Some(last) = self.changes.last_mut()
  926            && group
  927        {
  928            last.current = Some(new_positions)
  929        } else {
  930            self.changes.push(ChangeLocation {
  931                original: new_positions,
  932                current: None,
  933            });
  934        }
  935    }
  936
  937    pub fn last(&self) -> Option<&[Anchor]> {
  938        self.changes.last().map(|change| change.locations())
  939    }
  940
  941    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  942        self.changes.last().map(|change| change.original.as_slice())
  943    }
  944
  945    pub fn invert_last_group(&mut self) {
  946        if let Some(last) = self.changes.last_mut()
  947            && let Some(current) = last.current.as_mut()
  948        {
  949            mem::swap(&mut last.original, current);
  950        }
  951    }
  952}
  953
  954#[derive(Clone)]
  955struct InlineBlamePopoverState {
  956    scroll_handle: ScrollHandle,
  957    commit_message: Option<ParsedCommitMessage>,
  958    markdown: Entity<Markdown>,
  959}
  960
  961struct InlineBlamePopover {
  962    position: gpui::Point<Pixels>,
  963    hide_task: Option<Task<()>>,
  964    popover_bounds: Option<Bounds<Pixels>>,
  965    popover_state: InlineBlamePopoverState,
  966    keyboard_grace: bool,
  967}
  968
  969enum SelectionDragState {
  970    /// State when no drag related activity is detected.
  971    None,
  972    /// State when the mouse is down on a selection that is about to be dragged.
  973    ReadyToDrag {
  974        selection: Selection<Anchor>,
  975        click_position: gpui::Point<Pixels>,
  976        mouse_down_time: Instant,
  977    },
  978    /// State when the mouse is dragging the selection in the editor.
  979    Dragging {
  980        selection: Selection<Anchor>,
  981        drop_cursor: Selection<Anchor>,
  982        hide_drop_cursor: bool,
  983    },
  984}
  985
  986enum ColumnarSelectionState {
  987    FromMouse {
  988        selection_tail: Anchor,
  989        display_point: Option<DisplayPoint>,
  990    },
  991    FromSelection {
  992        selection_tail: Anchor,
  993    },
  994}
  995
  996/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  997/// a breakpoint on them.
  998#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  999struct PhantomBreakpointIndicator {
 1000    display_row: DisplayRow,
 1001    /// There's a small debounce between hovering over the line and showing the indicator.
 1002    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1003    is_active: bool,
 1004    collides_with_existing_breakpoint: bool,
 1005}
 1006
 1007/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1008///
 1009/// See the [module level documentation](self) for more information.
 1010pub struct Editor {
 1011    focus_handle: FocusHandle,
 1012    last_focused_descendant: Option<WeakFocusHandle>,
 1013    /// The text buffer being edited
 1014    buffer: Entity<MultiBuffer>,
 1015    /// Map of how text in the buffer should be displayed.
 1016    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1017    pub display_map: Entity<DisplayMap>,
 1018    placeholder_display_map: Option<Entity<DisplayMap>>,
 1019    pub selections: SelectionsCollection,
 1020    pub scroll_manager: ScrollManager,
 1021    /// When inline assist editors are linked, they all render cursors because
 1022    /// typing enters text into each of them, even the ones that aren't focused.
 1023    pub(crate) show_cursor_when_unfocused: bool,
 1024    columnar_selection_state: Option<ColumnarSelectionState>,
 1025    add_selections_state: Option<AddSelectionsState>,
 1026    select_next_state: Option<SelectNextState>,
 1027    select_prev_state: Option<SelectNextState>,
 1028    selection_history: SelectionHistory,
 1029    defer_selection_effects: bool,
 1030    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1031    autoclose_regions: Vec<AutocloseRegion>,
 1032    snippet_stack: InvalidationStack<SnippetState>,
 1033    select_syntax_node_history: SelectSyntaxNodeHistory,
 1034    ime_transaction: Option<TransactionId>,
 1035    pub diagnostics_max_severity: DiagnosticSeverity,
 1036    active_diagnostics: ActiveDiagnostic,
 1037    show_inline_diagnostics: bool,
 1038    inline_diagnostics_update: Task<()>,
 1039    inline_diagnostics_enabled: bool,
 1040    diagnostics_enabled: bool,
 1041    word_completions_enabled: bool,
 1042    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1043    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1044    hard_wrap: Option<usize>,
 1045    project: Option<Entity<Project>>,
 1046    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1047    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1048    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1049    blink_manager: Entity<BlinkManager>,
 1050    show_cursor_names: bool,
 1051    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1052    pub show_local_selections: bool,
 1053    mode: EditorMode,
 1054    show_breadcrumbs: bool,
 1055    show_gutter: bool,
 1056    show_scrollbars: ScrollbarAxes,
 1057    minimap_visibility: MinimapVisibility,
 1058    offset_content: bool,
 1059    disable_expand_excerpt_buttons: bool,
 1060    show_line_numbers: Option<bool>,
 1061    use_relative_line_numbers: Option<bool>,
 1062    show_git_diff_gutter: Option<bool>,
 1063    show_code_actions: Option<bool>,
 1064    show_runnables: Option<bool>,
 1065    show_breakpoints: Option<bool>,
 1066    show_wrap_guides: Option<bool>,
 1067    show_indent_guides: Option<bool>,
 1068    highlight_order: usize,
 1069    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1070    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1071    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1072    scrollbar_marker_state: ScrollbarMarkerState,
 1073    active_indent_guides_state: ActiveIndentGuidesState,
 1074    nav_history: Option<ItemNavHistory>,
 1075    context_menu: RefCell<Option<CodeContextMenu>>,
 1076    context_menu_options: Option<ContextMenuOptions>,
 1077    mouse_context_menu: Option<MouseContextMenu>,
 1078    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1079    inline_blame_popover: Option<InlineBlamePopover>,
 1080    inline_blame_popover_show_task: Option<Task<()>>,
 1081    signature_help_state: SignatureHelpState,
 1082    auto_signature_help: Option<bool>,
 1083    find_all_references_task_sources: Vec<Anchor>,
 1084    next_completion_id: CompletionId,
 1085    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1086    code_actions_task: Option<Task<Result<()>>>,
 1087    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1088    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1089    document_highlights_task: Option<Task<()>>,
 1090    linked_editing_range_task: Option<Task<Option<()>>>,
 1091    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1092    pending_rename: Option<RenameState>,
 1093    searchable: bool,
 1094    cursor_shape: CursorShape,
 1095    current_line_highlight: Option<CurrentLineHighlight>,
 1096    collapse_matches: bool,
 1097    autoindent_mode: Option<AutoindentMode>,
 1098    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1099    input_enabled: bool,
 1100    use_modal_editing: bool,
 1101    read_only: bool,
 1102    leader_id: Option<CollaboratorId>,
 1103    remote_id: Option<ViewId>,
 1104    pub hover_state: HoverState,
 1105    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1106    gutter_hovered: bool,
 1107    hovered_link_state: Option<HoveredLinkState>,
 1108    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1109    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1110    active_edit_prediction: Option<EditPredictionState>,
 1111    /// Used to prevent flickering as the user types while the menu is open
 1112    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1113    edit_prediction_settings: EditPredictionSettings,
 1114    edit_predictions_hidden_for_vim_mode: bool,
 1115    show_edit_predictions_override: Option<bool>,
 1116    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1117    edit_prediction_preview: EditPredictionPreview,
 1118    edit_prediction_indent_conflict: bool,
 1119    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1120    inlay_hint_cache: InlayHintCache,
 1121    next_inlay_id: usize,
 1122    _subscriptions: Vec<Subscription>,
 1123    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1124    gutter_dimensions: GutterDimensions,
 1125    style: Option<EditorStyle>,
 1126    text_style_refinement: Option<TextStyleRefinement>,
 1127    next_editor_action_id: EditorActionId,
 1128    editor_actions: Rc<
 1129        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1130    >,
 1131    use_autoclose: bool,
 1132    use_auto_surround: bool,
 1133    auto_replace_emoji_shortcode: bool,
 1134    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1135    show_git_blame_gutter: bool,
 1136    show_git_blame_inline: bool,
 1137    show_git_blame_inline_delay_task: Option<Task<()>>,
 1138    git_blame_inline_enabled: bool,
 1139    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1140    serialize_dirty_buffers: bool,
 1141    show_selection_menu: Option<bool>,
 1142    blame: Option<Entity<GitBlame>>,
 1143    blame_subscription: Option<Subscription>,
 1144    custom_context_menu: Option<
 1145        Box<
 1146            dyn 'static
 1147                + Fn(
 1148                    &mut Self,
 1149                    DisplayPoint,
 1150                    &mut Window,
 1151                    &mut Context<Self>,
 1152                ) -> Option<Entity<ui::ContextMenu>>,
 1153        >,
 1154    >,
 1155    last_bounds: Option<Bounds<Pixels>>,
 1156    last_position_map: Option<Rc<PositionMap>>,
 1157    expect_bounds_change: Option<Bounds<Pixels>>,
 1158    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1159    tasks_update_task: Option<Task<()>>,
 1160    breakpoint_store: Option<Entity<BreakpointStore>>,
 1161    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1162    hovered_diff_hunk_row: Option<DisplayRow>,
 1163    pull_diagnostics_task: Task<()>,
 1164    in_project_search: bool,
 1165    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1166    breadcrumb_header: Option<String>,
 1167    focused_block: Option<FocusedBlock>,
 1168    next_scroll_position: NextScrollCursorCenterTopBottom,
 1169    addons: HashMap<TypeId, Box<dyn Addon>>,
 1170    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1171    load_diff_task: Option<Shared<Task<()>>>,
 1172    /// Whether we are temporarily displaying a diff other than git's
 1173    temporary_diff_override: bool,
 1174    selection_mark_mode: bool,
 1175    toggle_fold_multiple_buffers: Task<()>,
 1176    _scroll_cursor_center_top_bottom_task: Task<()>,
 1177    serialize_selections: Task<()>,
 1178    serialize_folds: Task<()>,
 1179    mouse_cursor_hidden: bool,
 1180    minimap: Option<Entity<Self>>,
 1181    hide_mouse_mode: HideMouseMode,
 1182    pub change_list: ChangeList,
 1183    inline_value_cache: InlineValueCache,
 1184    selection_drag_state: SelectionDragState,
 1185    next_color_inlay_id: usize,
 1186    colors: Option<LspColorData>,
 1187    folding_newlines: Task<()>,
 1188    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1189}
 1190
 1191#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1192enum NextScrollCursorCenterTopBottom {
 1193    #[default]
 1194    Center,
 1195    Top,
 1196    Bottom,
 1197}
 1198
 1199impl NextScrollCursorCenterTopBottom {
 1200    fn next(&self) -> Self {
 1201        match self {
 1202            Self::Center => Self::Top,
 1203            Self::Top => Self::Bottom,
 1204            Self::Bottom => Self::Center,
 1205        }
 1206    }
 1207}
 1208
 1209#[derive(Clone)]
 1210pub struct EditorSnapshot {
 1211    pub mode: EditorMode,
 1212    show_gutter: bool,
 1213    show_line_numbers: Option<bool>,
 1214    show_git_diff_gutter: Option<bool>,
 1215    show_code_actions: Option<bool>,
 1216    show_runnables: Option<bool>,
 1217    show_breakpoints: Option<bool>,
 1218    git_blame_gutter_max_author_length: Option<usize>,
 1219    pub display_snapshot: DisplaySnapshot,
 1220    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1221    is_focused: bool,
 1222    scroll_anchor: ScrollAnchor,
 1223    ongoing_scroll: OngoingScroll,
 1224    current_line_highlight: CurrentLineHighlight,
 1225    gutter_hovered: bool,
 1226}
 1227
 1228#[derive(Default, Debug, Clone, Copy)]
 1229pub struct GutterDimensions {
 1230    pub left_padding: Pixels,
 1231    pub right_padding: Pixels,
 1232    pub width: Pixels,
 1233    pub margin: Pixels,
 1234    pub git_blame_entries_width: Option<Pixels>,
 1235}
 1236
 1237impl GutterDimensions {
 1238    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1239        Self {
 1240            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1241            ..Default::default()
 1242        }
 1243    }
 1244
 1245    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1246        -cx.text_system().descent(font_id, font_size)
 1247    }
 1248    /// The full width of the space taken up by the gutter.
 1249    pub fn full_width(&self) -> Pixels {
 1250        self.margin + self.width
 1251    }
 1252
 1253    /// The width of the space reserved for the fold indicators,
 1254    /// use alongside 'justify_end' and `gutter_width` to
 1255    /// right align content with the line numbers
 1256    pub fn fold_area_width(&self) -> Pixels {
 1257        self.margin + self.right_padding
 1258    }
 1259}
 1260
 1261struct CharacterDimensions {
 1262    em_width: Pixels,
 1263    em_advance: Pixels,
 1264    line_height: Pixels,
 1265}
 1266
 1267#[derive(Debug)]
 1268pub struct RemoteSelection {
 1269    pub replica_id: ReplicaId,
 1270    pub selection: Selection<Anchor>,
 1271    pub cursor_shape: CursorShape,
 1272    pub collaborator_id: CollaboratorId,
 1273    pub line_mode: bool,
 1274    pub user_name: Option<SharedString>,
 1275    pub color: PlayerColor,
 1276}
 1277
 1278#[derive(Clone, Debug)]
 1279struct SelectionHistoryEntry {
 1280    selections: Arc<[Selection<Anchor>]>,
 1281    select_next_state: Option<SelectNextState>,
 1282    select_prev_state: Option<SelectNextState>,
 1283    add_selections_state: Option<AddSelectionsState>,
 1284}
 1285
 1286#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1287enum SelectionHistoryMode {
 1288    Normal,
 1289    Undoing,
 1290    Redoing,
 1291    Skipping,
 1292}
 1293
 1294#[derive(Clone, PartialEq, Eq, Hash)]
 1295struct HoveredCursor {
 1296    replica_id: u16,
 1297    selection_id: usize,
 1298}
 1299
 1300impl Default for SelectionHistoryMode {
 1301    fn default() -> Self {
 1302        Self::Normal
 1303    }
 1304}
 1305
 1306#[derive(Debug)]
 1307/// SelectionEffects controls the side-effects of updating the selection.
 1308///
 1309/// The default behaviour does "what you mostly want":
 1310/// - it pushes to the nav history if the cursor moved by >10 lines
 1311/// - it re-triggers completion requests
 1312/// - it scrolls to fit
 1313///
 1314/// You might want to modify these behaviours. For example when doing a "jump"
 1315/// like go to definition, we always want to add to nav history; but when scrolling
 1316/// in vim mode we never do.
 1317///
 1318/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1319/// move.
 1320#[derive(Clone)]
 1321pub struct SelectionEffects {
 1322    nav_history: Option<bool>,
 1323    completions: bool,
 1324    scroll: Option<Autoscroll>,
 1325}
 1326
 1327impl Default for SelectionEffects {
 1328    fn default() -> Self {
 1329        Self {
 1330            nav_history: None,
 1331            completions: true,
 1332            scroll: Some(Autoscroll::fit()),
 1333        }
 1334    }
 1335}
 1336impl SelectionEffects {
 1337    pub fn scroll(scroll: Autoscroll) -> Self {
 1338        Self {
 1339            scroll: Some(scroll),
 1340            ..Default::default()
 1341        }
 1342    }
 1343
 1344    pub fn no_scroll() -> Self {
 1345        Self {
 1346            scroll: None,
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn completions(self, completions: bool) -> Self {
 1352        Self {
 1353            completions,
 1354            ..self
 1355        }
 1356    }
 1357
 1358    pub fn nav_history(self, nav_history: bool) -> Self {
 1359        Self {
 1360            nav_history: Some(nav_history),
 1361            ..self
 1362        }
 1363    }
 1364}
 1365
 1366struct DeferredSelectionEffectsState {
 1367    changed: bool,
 1368    effects: SelectionEffects,
 1369    old_cursor_position: Anchor,
 1370    history_entry: SelectionHistoryEntry,
 1371}
 1372
 1373#[derive(Default)]
 1374struct SelectionHistory {
 1375    #[allow(clippy::type_complexity)]
 1376    selections_by_transaction:
 1377        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1378    mode: SelectionHistoryMode,
 1379    undo_stack: VecDeque<SelectionHistoryEntry>,
 1380    redo_stack: VecDeque<SelectionHistoryEntry>,
 1381}
 1382
 1383impl SelectionHistory {
 1384    #[track_caller]
 1385    fn insert_transaction(
 1386        &mut self,
 1387        transaction_id: TransactionId,
 1388        selections: Arc<[Selection<Anchor>]>,
 1389    ) {
 1390        if selections.is_empty() {
 1391            log::error!(
 1392                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1393                std::panic::Location::caller()
 1394            );
 1395            return;
 1396        }
 1397        self.selections_by_transaction
 1398            .insert(transaction_id, (selections, None));
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction(
 1403        &self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get(&transaction_id)
 1407    }
 1408
 1409    #[allow(clippy::type_complexity)]
 1410    fn transaction_mut(
 1411        &mut self,
 1412        transaction_id: TransactionId,
 1413    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1414        self.selections_by_transaction.get_mut(&transaction_id)
 1415    }
 1416
 1417    fn push(&mut self, entry: SelectionHistoryEntry) {
 1418        if !entry.selections.is_empty() {
 1419            match self.mode {
 1420                SelectionHistoryMode::Normal => {
 1421                    self.push_undo(entry);
 1422                    self.redo_stack.clear();
 1423                }
 1424                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1425                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1426                SelectionHistoryMode::Skipping => {}
 1427            }
 1428        }
 1429    }
 1430
 1431    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1432        if self
 1433            .undo_stack
 1434            .back()
 1435            .is_none_or(|e| e.selections != entry.selections)
 1436        {
 1437            self.undo_stack.push_back(entry);
 1438            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1439                self.undo_stack.pop_front();
 1440            }
 1441        }
 1442    }
 1443
 1444    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1445        if self
 1446            .redo_stack
 1447            .back()
 1448            .is_none_or(|e| e.selections != entry.selections)
 1449        {
 1450            self.redo_stack.push_back(entry);
 1451            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1452                self.redo_stack.pop_front();
 1453            }
 1454        }
 1455    }
 1456}
 1457
 1458#[derive(Clone, Copy)]
 1459pub struct RowHighlightOptions {
 1460    pub autoscroll: bool,
 1461    pub include_gutter: bool,
 1462}
 1463
 1464impl Default for RowHighlightOptions {
 1465    fn default() -> Self {
 1466        Self {
 1467            autoscroll: Default::default(),
 1468            include_gutter: true,
 1469        }
 1470    }
 1471}
 1472
 1473struct RowHighlight {
 1474    index: usize,
 1475    range: Range<Anchor>,
 1476    color: Hsla,
 1477    options: RowHighlightOptions,
 1478    type_id: TypeId,
 1479}
 1480
 1481#[derive(Clone, Debug)]
 1482struct AddSelectionsState {
 1483    groups: Vec<AddSelectionsGroup>,
 1484}
 1485
 1486#[derive(Clone, Debug)]
 1487struct AddSelectionsGroup {
 1488    above: bool,
 1489    stack: Vec<usize>,
 1490}
 1491
 1492#[derive(Clone)]
 1493struct SelectNextState {
 1494    query: AhoCorasick,
 1495    wordwise: bool,
 1496    done: bool,
 1497}
 1498
 1499impl std::fmt::Debug for SelectNextState {
 1500    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1501        f.debug_struct(std::any::type_name::<Self>())
 1502            .field("wordwise", &self.wordwise)
 1503            .field("done", &self.done)
 1504            .finish()
 1505    }
 1506}
 1507
 1508#[derive(Debug)]
 1509struct AutocloseRegion {
 1510    selection_id: usize,
 1511    range: Range<Anchor>,
 1512    pair: BracketPair,
 1513}
 1514
 1515#[derive(Debug)]
 1516struct SnippetState {
 1517    ranges: Vec<Vec<Range<Anchor>>>,
 1518    active_index: usize,
 1519    choices: Vec<Option<Vec<String>>>,
 1520}
 1521
 1522#[doc(hidden)]
 1523pub struct RenameState {
 1524    pub range: Range<Anchor>,
 1525    pub old_name: Arc<str>,
 1526    pub editor: Entity<Editor>,
 1527    block_id: CustomBlockId,
 1528}
 1529
 1530struct InvalidationStack<T>(Vec<T>);
 1531
 1532struct RegisteredEditPredictionProvider {
 1533    provider: Arc<dyn EditPredictionProviderHandle>,
 1534    _subscription: Subscription,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538pub struct ActiveDiagnosticGroup {
 1539    pub active_range: Range<Anchor>,
 1540    pub active_message: String,
 1541    pub group_id: usize,
 1542    pub blocks: HashSet<CustomBlockId>,
 1543}
 1544
 1545#[derive(Debug, PartialEq, Eq)]
 1546
 1547pub(crate) enum ActiveDiagnostic {
 1548    None,
 1549    All,
 1550    Group(ActiveDiagnosticGroup),
 1551}
 1552
 1553#[derive(Serialize, Deserialize, Clone, Debug)]
 1554pub struct ClipboardSelection {
 1555    /// The number of bytes in this selection.
 1556    pub len: usize,
 1557    /// Whether this was a full-line selection.
 1558    pub is_entire_line: bool,
 1559    /// The indentation of the first line when this content was originally copied.
 1560    pub first_line_indent: u32,
 1561}
 1562
 1563// selections, scroll behavior, was newest selection reversed
 1564type SelectSyntaxNodeHistoryState = (
 1565    Box<[Selection<usize>]>,
 1566    SelectSyntaxNodeScrollBehavior,
 1567    bool,
 1568);
 1569
 1570#[derive(Default)]
 1571struct SelectSyntaxNodeHistory {
 1572    stack: Vec<SelectSyntaxNodeHistoryState>,
 1573    // disable temporarily to allow changing selections without losing the stack
 1574    pub disable_clearing: bool,
 1575}
 1576
 1577impl SelectSyntaxNodeHistory {
 1578    pub fn try_clear(&mut self) {
 1579        if !self.disable_clearing {
 1580            self.stack.clear();
 1581        }
 1582    }
 1583
 1584    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1585        self.stack.push(selection);
 1586    }
 1587
 1588    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1589        self.stack.pop()
 1590    }
 1591}
 1592
 1593enum SelectSyntaxNodeScrollBehavior {
 1594    CursorTop,
 1595    FitSelection,
 1596    CursorBottom,
 1597}
 1598
 1599#[derive(Debug)]
 1600pub(crate) struct NavigationData {
 1601    cursor_anchor: Anchor,
 1602    cursor_position: Point,
 1603    scroll_anchor: ScrollAnchor,
 1604    scroll_top_row: u32,
 1605}
 1606
 1607#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1608pub enum GotoDefinitionKind {
 1609    Symbol,
 1610    Declaration,
 1611    Type,
 1612    Implementation,
 1613}
 1614
 1615#[derive(Debug, Clone)]
 1616enum InlayHintRefreshReason {
 1617    ModifiersChanged(bool),
 1618    Toggle(bool),
 1619    SettingsChange(InlayHintSettings),
 1620    NewLinesShown,
 1621    BufferEdited(HashSet<Arc<Language>>),
 1622    RefreshRequested,
 1623    ExcerptsRemoved(Vec<ExcerptId>),
 1624}
 1625
 1626impl InlayHintRefreshReason {
 1627    fn description(&self) -> &'static str {
 1628        match self {
 1629            Self::ModifiersChanged(_) => "modifiers changed",
 1630            Self::Toggle(_) => "toggle",
 1631            Self::SettingsChange(_) => "settings change",
 1632            Self::NewLinesShown => "new lines shown",
 1633            Self::BufferEdited(_) => "buffer edited",
 1634            Self::RefreshRequested => "refresh requested",
 1635            Self::ExcerptsRemoved(_) => "excerpts removed",
 1636        }
 1637    }
 1638}
 1639
 1640pub enum FormatTarget {
 1641    Buffers(HashSet<Entity<Buffer>>),
 1642    Ranges(Vec<Range<MultiBufferPoint>>),
 1643}
 1644
 1645pub(crate) struct FocusedBlock {
 1646    id: BlockId,
 1647    focus_handle: WeakFocusHandle,
 1648}
 1649
 1650#[derive(Clone)]
 1651enum JumpData {
 1652    MultiBufferRow {
 1653        row: MultiBufferRow,
 1654        line_offset_from_top: u32,
 1655    },
 1656    MultiBufferPoint {
 1657        excerpt_id: ExcerptId,
 1658        position: Point,
 1659        anchor: text::Anchor,
 1660        line_offset_from_top: u32,
 1661    },
 1662}
 1663
 1664pub enum MultibufferSelectionMode {
 1665    First,
 1666    All,
 1667}
 1668
 1669#[derive(Clone, Copy, Debug, Default)]
 1670pub struct RewrapOptions {
 1671    pub override_language_settings: bool,
 1672    pub preserve_existing_whitespace: bool,
 1673}
 1674
 1675impl Editor {
 1676    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1677        let buffer = cx.new(|cx| Buffer::local("", cx));
 1678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1679        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1680    }
 1681
 1682    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(EditorMode::full(), buffer, None, window, cx)
 1686    }
 1687
 1688    pub fn auto_height(
 1689        min_lines: usize,
 1690        max_lines: usize,
 1691        window: &mut Window,
 1692        cx: &mut Context<Self>,
 1693    ) -> Self {
 1694        let buffer = cx.new(|cx| Buffer::local("", cx));
 1695        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1696        Self::new(
 1697            EditorMode::AutoHeight {
 1698                min_lines,
 1699                max_lines: Some(max_lines),
 1700            },
 1701            buffer,
 1702            None,
 1703            window,
 1704            cx,
 1705        )
 1706    }
 1707
 1708    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1709    /// The editor grows as tall as needed to fit its content.
 1710    pub fn auto_height_unbounded(
 1711        min_lines: usize,
 1712        window: &mut Window,
 1713        cx: &mut Context<Self>,
 1714    ) -> Self {
 1715        let buffer = cx.new(|cx| Buffer::local("", cx));
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(
 1718            EditorMode::AutoHeight {
 1719                min_lines,
 1720                max_lines: None,
 1721            },
 1722            buffer,
 1723            None,
 1724            window,
 1725            cx,
 1726        )
 1727    }
 1728
 1729    pub fn for_buffer(
 1730        buffer: Entity<Buffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn for_multibuffer(
 1740        buffer: Entity<MultiBuffer>,
 1741        project: Option<Entity<Project>>,
 1742        window: &mut Window,
 1743        cx: &mut Context<Self>,
 1744    ) -> Self {
 1745        Self::new(EditorMode::full(), buffer, project, window, cx)
 1746    }
 1747
 1748    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1749        let mut clone = Self::new(
 1750            self.mode.clone(),
 1751            self.buffer.clone(),
 1752            self.project.clone(),
 1753            window,
 1754            cx,
 1755        );
 1756        self.display_map.update(cx, |display_map, cx| {
 1757            let snapshot = display_map.snapshot(cx);
 1758            clone.display_map.update(cx, |display_map, cx| {
 1759                display_map.set_state(&snapshot, cx);
 1760            });
 1761        });
 1762        clone.folds_did_change(cx);
 1763        clone.selections.clone_state(&self.selections);
 1764        clone.scroll_manager.clone_state(&self.scroll_manager);
 1765        clone.searchable = self.searchable;
 1766        clone.read_only = self.read_only;
 1767        clone
 1768    }
 1769
 1770    pub fn new(
 1771        mode: EditorMode,
 1772        buffer: Entity<MultiBuffer>,
 1773        project: Option<Entity<Project>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        Editor::new_internal(mode, buffer, project, None, window, cx)
 1778    }
 1779
 1780    fn new_internal(
 1781        mode: EditorMode,
 1782        buffer: Entity<MultiBuffer>,
 1783        project: Option<Entity<Project>>,
 1784        display_map: Option<Entity<DisplayMap>>,
 1785        window: &mut Window,
 1786        cx: &mut Context<Self>,
 1787    ) -> Self {
 1788        debug_assert!(
 1789            display_map.is_none() || mode.is_minimap(),
 1790            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1791        );
 1792
 1793        let full_mode = mode.is_full();
 1794        let is_minimap = mode.is_minimap();
 1795        let diagnostics_max_severity = if full_mode {
 1796            EditorSettings::get_global(cx)
 1797                .diagnostics_max_severity
 1798                .unwrap_or(DiagnosticSeverity::Hint)
 1799        } else {
 1800            DiagnosticSeverity::Off
 1801        };
 1802        let style = window.text_style();
 1803        let font_size = style.font_size.to_pixels(window.rem_size());
 1804        let editor = cx.entity().downgrade();
 1805        let fold_placeholder = FoldPlaceholder {
 1806            constrain_width: false,
 1807            render: Arc::new(move |fold_id, fold_range, cx| {
 1808                let editor = editor.clone();
 1809                div()
 1810                    .id(fold_id)
 1811                    .bg(cx.theme().colors().ghost_element_background)
 1812                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1813                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1814                    .rounded_xs()
 1815                    .size_full()
 1816                    .cursor_pointer()
 1817                    .child("")
 1818                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1819                    .on_click(move |_, _window, cx| {
 1820                        editor
 1821                            .update(cx, |editor, cx| {
 1822                                editor.unfold_ranges(
 1823                                    &[fold_range.start..fold_range.end],
 1824                                    true,
 1825                                    false,
 1826                                    cx,
 1827                                );
 1828                                cx.stop_propagation();
 1829                            })
 1830                            .ok();
 1831                    })
 1832                    .into_any()
 1833            }),
 1834            merge_adjacent: true,
 1835            ..FoldPlaceholder::default()
 1836        };
 1837        let display_map = display_map.unwrap_or_else(|| {
 1838            cx.new(|cx| {
 1839                DisplayMap::new(
 1840                    buffer.clone(),
 1841                    style.font(),
 1842                    font_size,
 1843                    None,
 1844                    FILE_HEADER_HEIGHT,
 1845                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1846                    fold_placeholder,
 1847                    diagnostics_max_severity,
 1848                    cx,
 1849                )
 1850            })
 1851        });
 1852
 1853        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1854
 1855        let blink_manager = cx.new(|cx| {
 1856            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1857            if is_minimap {
 1858                blink_manager.disable(cx);
 1859            }
 1860            blink_manager
 1861        });
 1862
 1863        let soft_wrap_mode_override =
 1864            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1865
 1866        let mut project_subscriptions = Vec::new();
 1867        if full_mode && let Some(project) = project.as_ref() {
 1868            project_subscriptions.push(cx.subscribe_in(
 1869                project,
 1870                window,
 1871                |editor, _, event, window, cx| match event {
 1872                    project::Event::RefreshCodeLens => {
 1873                        // we always query lens with actions, without storing them, always refreshing them
 1874                    }
 1875                    project::Event::RefreshInlayHints => {
 1876                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1877                    }
 1878                    project::Event::LanguageServerAdded(..)
 1879                    | project::Event::LanguageServerRemoved(..) => {
 1880                        if editor.tasks_update_task.is_none() {
 1881                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1882                        }
 1883                    }
 1884                    project::Event::SnippetEdit(id, snippet_edits) => {
 1885                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1886                            let focus_handle = editor.focus_handle(cx);
 1887                            if focus_handle.is_focused(window) {
 1888                                let snapshot = buffer.read(cx).snapshot();
 1889                                for (range, snippet) in snippet_edits {
 1890                                    let editor_range =
 1891                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1892                                    editor
 1893                                        .insert_snippet(
 1894                                            &[editor_range],
 1895                                            snippet.clone(),
 1896                                            window,
 1897                                            cx,
 1898                                        )
 1899                                        .ok();
 1900                                }
 1901                            }
 1902                        }
 1903                    }
 1904                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1905                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1906                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1907                        }
 1908                    }
 1909
 1910                    project::Event::EntryRenamed(transaction) => {
 1911                        let Some(workspace) = editor.workspace() else {
 1912                            return;
 1913                        };
 1914                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1915                        else {
 1916                            return;
 1917                        };
 1918                        if active_editor.entity_id() == cx.entity_id() {
 1919                            let edited_buffers_already_open = {
 1920                                let other_editors: Vec<Entity<Editor>> = workspace
 1921                                    .read(cx)
 1922                                    .panes()
 1923                                    .iter()
 1924                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1925                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1926                                    .collect();
 1927
 1928                                transaction.0.keys().all(|buffer| {
 1929                                    other_editors.iter().any(|editor| {
 1930                                        let multi_buffer = editor.read(cx).buffer();
 1931                                        multi_buffer.read(cx).is_singleton()
 1932                                            && multi_buffer.read(cx).as_singleton().map_or(
 1933                                                false,
 1934                                                |singleton| {
 1935                                                    singleton.entity_id() == buffer.entity_id()
 1936                                                },
 1937                                            )
 1938                                    })
 1939                                })
 1940                            };
 1941
 1942                            if !edited_buffers_already_open {
 1943                                let workspace = workspace.downgrade();
 1944                                let transaction = transaction.clone();
 1945                                cx.defer_in(window, move |_, window, cx| {
 1946                                    cx.spawn_in(window, async move |editor, cx| {
 1947                                        Self::open_project_transaction(
 1948                                            &editor,
 1949                                            workspace,
 1950                                            transaction,
 1951                                            "Rename".to_string(),
 1952                                            cx,
 1953                                        )
 1954                                        .await
 1955                                        .ok()
 1956                                    })
 1957                                    .detach();
 1958                                });
 1959                            }
 1960                        }
 1961                    }
 1962
 1963                    _ => {}
 1964                },
 1965            ));
 1966            if let Some(task_inventory) = project
 1967                .read(cx)
 1968                .task_store()
 1969                .read(cx)
 1970                .task_inventory()
 1971                .cloned()
 1972            {
 1973                project_subscriptions.push(cx.observe_in(
 1974                    &task_inventory,
 1975                    window,
 1976                    |editor, _, window, cx| {
 1977                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1978                    },
 1979                ));
 1980            };
 1981
 1982            project_subscriptions.push(cx.subscribe_in(
 1983                &project.read(cx).breakpoint_store(),
 1984                window,
 1985                |editor, _, event, window, cx| match event {
 1986                    BreakpointStoreEvent::ClearDebugLines => {
 1987                        editor.clear_row_highlights::<ActiveDebugLine>();
 1988                        editor.refresh_inline_values(cx);
 1989                    }
 1990                    BreakpointStoreEvent::SetDebugLine => {
 1991                        if editor.go_to_active_debug_line(window, cx) {
 1992                            cx.stop_propagation();
 1993                        }
 1994
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    _ => {}
 1998                },
 1999            ));
 2000            let git_store = project.read(cx).git_store().clone();
 2001            let project = project.clone();
 2002            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2003                if let GitStoreEvent::RepositoryUpdated(
 2004                    _,
 2005                    RepositoryEvent::Updated {
 2006                        new_instance: true, ..
 2007                    },
 2008                    _,
 2009                ) = event
 2010                {
 2011                    this.load_diff_task = Some(
 2012                        update_uncommitted_diff_for_buffer(
 2013                            cx.entity(),
 2014                            &project,
 2015                            this.buffer.read(cx).all_buffers(),
 2016                            this.buffer.clone(),
 2017                            cx,
 2018                        )
 2019                        .shared(),
 2020                    );
 2021                }
 2022            }));
 2023        }
 2024
 2025        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2026
 2027        let inlay_hint_settings =
 2028            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2029        let focus_handle = cx.focus_handle();
 2030        if !is_minimap {
 2031            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2032                .detach();
 2033            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2034                .detach();
 2035            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2036                .detach();
 2037            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2038                .detach();
 2039            cx.observe_pending_input(window, Self::observe_pending_input)
 2040                .detach();
 2041        }
 2042
 2043        let show_indent_guides =
 2044            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2045                Some(false)
 2046            } else {
 2047                None
 2048            };
 2049
 2050        let breakpoint_store = match (&mode, project.as_ref()) {
 2051            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2052            _ => None,
 2053        };
 2054
 2055        let mut code_action_providers = Vec::new();
 2056        let mut load_uncommitted_diff = None;
 2057        if let Some(project) = project.clone() {
 2058            load_uncommitted_diff = Some(
 2059                update_uncommitted_diff_for_buffer(
 2060                    cx.entity(),
 2061                    &project,
 2062                    buffer.read(cx).all_buffers(),
 2063                    buffer.clone(),
 2064                    cx,
 2065                )
 2066                .shared(),
 2067            );
 2068            code_action_providers.push(Rc::new(project) as Rc<_>);
 2069        }
 2070
 2071        let mut editor = Self {
 2072            focus_handle,
 2073            show_cursor_when_unfocused: false,
 2074            last_focused_descendant: None,
 2075            buffer: buffer.clone(),
 2076            display_map: display_map.clone(),
 2077            placeholder_display_map: None,
 2078            selections,
 2079            scroll_manager: ScrollManager::new(cx),
 2080            columnar_selection_state: None,
 2081            add_selections_state: None,
 2082            select_next_state: None,
 2083            select_prev_state: None,
 2084            selection_history: SelectionHistory::default(),
 2085            defer_selection_effects: false,
 2086            deferred_selection_effects_state: None,
 2087            autoclose_regions: Vec::new(),
 2088            snippet_stack: InvalidationStack::default(),
 2089            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2090            ime_transaction: None,
 2091            active_diagnostics: ActiveDiagnostic::None,
 2092            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2093            inline_diagnostics_update: Task::ready(()),
 2094            inline_diagnostics: Vec::new(),
 2095            soft_wrap_mode_override,
 2096            diagnostics_max_severity,
 2097            hard_wrap: None,
 2098            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2099            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2100            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2101            project,
 2102            blink_manager: blink_manager.clone(),
 2103            show_local_selections: true,
 2104            show_scrollbars: ScrollbarAxes {
 2105                horizontal: full_mode,
 2106                vertical: full_mode,
 2107            },
 2108            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2109            offset_content: !matches!(mode, EditorMode::SingleLine),
 2110            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2111            show_gutter: full_mode,
 2112            show_line_numbers: (!full_mode).then_some(false),
 2113            use_relative_line_numbers: None,
 2114            disable_expand_excerpt_buttons: !full_mode,
 2115            show_git_diff_gutter: None,
 2116            show_code_actions: None,
 2117            show_runnables: None,
 2118            show_breakpoints: None,
 2119            show_wrap_guides: None,
 2120            show_indent_guides,
 2121            highlight_order: 0,
 2122            highlighted_rows: HashMap::default(),
 2123            background_highlights: HashMap::default(),
 2124            gutter_highlights: HashMap::default(),
 2125            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2126            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2127            nav_history: None,
 2128            context_menu: RefCell::new(None),
 2129            context_menu_options: None,
 2130            mouse_context_menu: None,
 2131            completion_tasks: Vec::new(),
 2132            inline_blame_popover: None,
 2133            inline_blame_popover_show_task: None,
 2134            signature_help_state: SignatureHelpState::default(),
 2135            auto_signature_help: None,
 2136            find_all_references_task_sources: Vec::new(),
 2137            next_completion_id: 0,
 2138            next_inlay_id: 0,
 2139            code_action_providers,
 2140            available_code_actions: None,
 2141            code_actions_task: None,
 2142            quick_selection_highlight_task: None,
 2143            debounced_selection_highlight_task: None,
 2144            document_highlights_task: None,
 2145            linked_editing_range_task: None,
 2146            pending_rename: None,
 2147            searchable: !is_minimap,
 2148            cursor_shape: EditorSettings::get_global(cx)
 2149                .cursor_shape
 2150                .unwrap_or_default(),
 2151            current_line_highlight: None,
 2152            autoindent_mode: Some(AutoindentMode::EachLine),
 2153            collapse_matches: false,
 2154            workspace: None,
 2155            input_enabled: !is_minimap,
 2156            use_modal_editing: full_mode,
 2157            read_only: is_minimap,
 2158            use_autoclose: true,
 2159            use_auto_surround: true,
 2160            auto_replace_emoji_shortcode: false,
 2161            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2162            leader_id: None,
 2163            remote_id: None,
 2164            hover_state: HoverState::default(),
 2165            pending_mouse_down: None,
 2166            hovered_link_state: None,
 2167            edit_prediction_provider: None,
 2168            active_edit_prediction: None,
 2169            stale_edit_prediction_in_menu: None,
 2170            edit_prediction_preview: EditPredictionPreview::Inactive {
 2171                released_too_fast: false,
 2172            },
 2173            inline_diagnostics_enabled: full_mode,
 2174            diagnostics_enabled: full_mode,
 2175            word_completions_enabled: full_mode,
 2176            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2177            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2178            gutter_hovered: false,
 2179            pixel_position_of_newest_cursor: None,
 2180            last_bounds: None,
 2181            last_position_map: None,
 2182            expect_bounds_change: None,
 2183            gutter_dimensions: GutterDimensions::default(),
 2184            style: None,
 2185            show_cursor_names: false,
 2186            hovered_cursors: HashMap::default(),
 2187            next_editor_action_id: EditorActionId::default(),
 2188            editor_actions: Rc::default(),
 2189            edit_predictions_hidden_for_vim_mode: false,
 2190            show_edit_predictions_override: None,
 2191            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2192            edit_prediction_settings: EditPredictionSettings::Disabled,
 2193            edit_prediction_indent_conflict: false,
 2194            edit_prediction_requires_modifier_in_indent_conflict: true,
 2195            custom_context_menu: None,
 2196            show_git_blame_gutter: false,
 2197            show_git_blame_inline: false,
 2198            show_selection_menu: None,
 2199            show_git_blame_inline_delay_task: None,
 2200            git_blame_inline_enabled: full_mode
 2201                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2202            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2203            serialize_dirty_buffers: !is_minimap
 2204                && ProjectSettings::get_global(cx)
 2205                    .session
 2206                    .restore_unsaved_buffers,
 2207            blame: None,
 2208            blame_subscription: None,
 2209            tasks: BTreeMap::default(),
 2210
 2211            breakpoint_store,
 2212            gutter_breakpoint_indicator: (None, None),
 2213            hovered_diff_hunk_row: None,
 2214            _subscriptions: (!is_minimap)
 2215                .then(|| {
 2216                    vec![
 2217                        cx.observe(&buffer, Self::on_buffer_changed),
 2218                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2219                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2220                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2221                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2222                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2223                        cx.observe_window_activation(window, |editor, window, cx| {
 2224                            let active = window.is_window_active();
 2225                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2226                                if active {
 2227                                    blink_manager.enable(cx);
 2228                                } else {
 2229                                    blink_manager.disable(cx);
 2230                                }
 2231                            });
 2232                            if active {
 2233                                editor.show_mouse_cursor(cx);
 2234                            }
 2235                        }),
 2236                    ]
 2237                })
 2238                .unwrap_or_default(),
 2239            tasks_update_task: None,
 2240            pull_diagnostics_task: Task::ready(()),
 2241            colors: None,
 2242            next_color_inlay_id: 0,
 2243            linked_edit_ranges: Default::default(),
 2244            in_project_search: false,
 2245            previous_search_ranges: None,
 2246            breadcrumb_header: None,
 2247            focused_block: None,
 2248            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2249            addons: HashMap::default(),
 2250            registered_buffers: HashMap::default(),
 2251            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2252            selection_mark_mode: false,
 2253            toggle_fold_multiple_buffers: Task::ready(()),
 2254            serialize_selections: Task::ready(()),
 2255            serialize_folds: Task::ready(()),
 2256            text_style_refinement: None,
 2257            load_diff_task: load_uncommitted_diff,
 2258            temporary_diff_override: false,
 2259            mouse_cursor_hidden: false,
 2260            minimap: None,
 2261            hide_mouse_mode: EditorSettings::get_global(cx)
 2262                .hide_mouse
 2263                .unwrap_or_default(),
 2264            change_list: ChangeList::new(),
 2265            mode,
 2266            selection_drag_state: SelectionDragState::None,
 2267            folding_newlines: Task::ready(()),
 2268            lookup_key: None,
 2269        };
 2270
 2271        if is_minimap {
 2272            return editor;
 2273        }
 2274
 2275        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2276            editor
 2277                ._subscriptions
 2278                .push(cx.observe(breakpoints, |_, _, cx| {
 2279                    cx.notify();
 2280                }));
 2281        }
 2282        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2283        editor._subscriptions.extend(project_subscriptions);
 2284
 2285        editor._subscriptions.push(cx.subscribe_in(
 2286            &cx.entity(),
 2287            window,
 2288            |editor, _, e: &EditorEvent, window, cx| match e {
 2289                EditorEvent::ScrollPositionChanged { local, .. } => {
 2290                    if *local {
 2291                        let new_anchor = editor.scroll_manager.anchor();
 2292                        let snapshot = editor.snapshot(window, cx);
 2293                        editor.update_restoration_data(cx, move |data| {
 2294                            data.scroll_position = (
 2295                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2296                                new_anchor.offset,
 2297                            );
 2298                        });
 2299                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2300                        editor.inline_blame_popover.take();
 2301                    }
 2302                }
 2303                EditorEvent::Edited { .. } => {
 2304                    if !vim_enabled(cx) {
 2305                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2306                        let pop_state = editor
 2307                            .change_list
 2308                            .last()
 2309                            .map(|previous| {
 2310                                previous.len() == selections.len()
 2311                                    && previous.iter().enumerate().all(|(ix, p)| {
 2312                                        p.to_display_point(&map).row()
 2313                                            == selections[ix].head().row()
 2314                                    })
 2315                            })
 2316                            .unwrap_or(false);
 2317                        let new_positions = selections
 2318                            .into_iter()
 2319                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2320                            .collect();
 2321                        editor
 2322                            .change_list
 2323                            .push_to_change_list(pop_state, new_positions);
 2324                    }
 2325                }
 2326                _ => (),
 2327            },
 2328        ));
 2329
 2330        if let Some(dap_store) = editor
 2331            .project
 2332            .as_ref()
 2333            .map(|project| project.read(cx).dap_store())
 2334        {
 2335            let weak_editor = cx.weak_entity();
 2336
 2337            editor
 2338                ._subscriptions
 2339                .push(
 2340                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2341                        let session_entity = cx.entity();
 2342                        weak_editor
 2343                            .update(cx, |editor, cx| {
 2344                                editor._subscriptions.push(
 2345                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2346                                );
 2347                            })
 2348                            .ok();
 2349                    }),
 2350                );
 2351
 2352            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2353                editor
 2354                    ._subscriptions
 2355                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2356            }
 2357        }
 2358
 2359        // skip adding the initial selection to selection history
 2360        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2361        editor.end_selection(window, cx);
 2362        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2363
 2364        editor.scroll_manager.show_scrollbars(window, cx);
 2365        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2366
 2367        if full_mode {
 2368            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2369            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2370
 2371            if editor.git_blame_inline_enabled {
 2372                editor.start_git_blame_inline(false, window, cx);
 2373            }
 2374
 2375            editor.go_to_active_debug_line(window, cx);
 2376
 2377            if let Some(buffer) = buffer.read(cx).as_singleton()
 2378                && let Some(project) = editor.project()
 2379            {
 2380                let handle = project.update(cx, |project, cx| {
 2381                    project.register_buffer_with_language_servers(&buffer, cx)
 2382                });
 2383                editor
 2384                    .registered_buffers
 2385                    .insert(buffer.read(cx).remote_id(), handle);
 2386            }
 2387
 2388            editor.minimap =
 2389                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2390            editor.colors = Some(LspColorData::new(cx));
 2391            editor.update_lsp_data(false, None, window, cx);
 2392        }
 2393
 2394        if editor.mode.is_full() {
 2395            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2396        }
 2397
 2398        editor
 2399    }
 2400
 2401    pub fn deploy_mouse_context_menu(
 2402        &mut self,
 2403        position: gpui::Point<Pixels>,
 2404        context_menu: Entity<ContextMenu>,
 2405        window: &mut Window,
 2406        cx: &mut Context<Self>,
 2407    ) {
 2408        self.mouse_context_menu = Some(MouseContextMenu::new(
 2409            self,
 2410            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2411            context_menu,
 2412            window,
 2413            cx,
 2414        ));
 2415    }
 2416
 2417    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2418        self.mouse_context_menu
 2419            .as_ref()
 2420            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2421    }
 2422
 2423    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2424        if self
 2425            .selections
 2426            .pending_anchor()
 2427            .is_some_and(|pending_selection| {
 2428                let snapshot = self.buffer().read(cx).snapshot(cx);
 2429                pending_selection.range().includes(range, &snapshot)
 2430            })
 2431        {
 2432            return true;
 2433        }
 2434
 2435        self.selections
 2436            .disjoint_in_range::<usize>(range.clone(), cx)
 2437            .into_iter()
 2438            .any(|selection| {
 2439                // This is needed to cover a corner case, if we just check for an existing
 2440                // selection in the fold range, having a cursor at the start of the fold
 2441                // marks it as selected. Non-empty selections don't cause this.
 2442                let length = selection.end - selection.start;
 2443                length > 0
 2444            })
 2445    }
 2446
 2447    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2448        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2449    }
 2450
 2451    fn key_context_internal(
 2452        &self,
 2453        has_active_edit_prediction: bool,
 2454        window: &Window,
 2455        cx: &App,
 2456    ) -> KeyContext {
 2457        let mut key_context = KeyContext::new_with_defaults();
 2458        key_context.add("Editor");
 2459        let mode = match self.mode {
 2460            EditorMode::SingleLine => "single_line",
 2461            EditorMode::AutoHeight { .. } => "auto_height",
 2462            EditorMode::Minimap { .. } => "minimap",
 2463            EditorMode::Full { .. } => "full",
 2464        };
 2465
 2466        if EditorSettings::jupyter_enabled(cx) {
 2467            key_context.add("jupyter");
 2468        }
 2469
 2470        key_context.set("mode", mode);
 2471        if self.pending_rename.is_some() {
 2472            key_context.add("renaming");
 2473        }
 2474
 2475        match self.context_menu.borrow().as_ref() {
 2476            Some(CodeContextMenu::Completions(menu)) => {
 2477                if menu.visible() {
 2478                    key_context.add("menu");
 2479                    key_context.add("showing_completions");
 2480                }
 2481            }
 2482            Some(CodeContextMenu::CodeActions(menu)) => {
 2483                if menu.visible() {
 2484                    key_context.add("menu");
 2485                    key_context.add("showing_code_actions")
 2486                }
 2487            }
 2488            None => {}
 2489        }
 2490
 2491        if self.signature_help_state.has_multiple_signatures() {
 2492            key_context.add("showing_signature_help");
 2493        }
 2494
 2495        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2496        if !self.focus_handle(cx).contains_focused(window, cx)
 2497            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2498        {
 2499            for addon in self.addons.values() {
 2500                addon.extend_key_context(&mut key_context, cx)
 2501            }
 2502        }
 2503
 2504        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2505            if let Some(extension) = singleton_buffer
 2506                .read(cx)
 2507                .file()
 2508                .and_then(|file| file.path().extension())
 2509            {
 2510                key_context.set("extension", extension.to_string());
 2511            }
 2512        } else {
 2513            key_context.add("multibuffer");
 2514        }
 2515
 2516        if has_active_edit_prediction {
 2517            if self.edit_prediction_in_conflict() {
 2518                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2519            } else {
 2520                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2521                key_context.add("copilot_suggestion");
 2522            }
 2523        }
 2524
 2525        if self.selection_mark_mode {
 2526            key_context.add("selection_mode");
 2527        }
 2528
 2529        key_context
 2530    }
 2531
 2532    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2533        self.last_bounds.as_ref()
 2534    }
 2535
 2536    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2537        if self.mouse_cursor_hidden {
 2538            self.mouse_cursor_hidden = false;
 2539            cx.notify();
 2540        }
 2541    }
 2542
 2543    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2544        let hide_mouse_cursor = match origin {
 2545            HideMouseCursorOrigin::TypingAction => {
 2546                matches!(
 2547                    self.hide_mouse_mode,
 2548                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2549                )
 2550            }
 2551            HideMouseCursorOrigin::MovementAction => {
 2552                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2553            }
 2554        };
 2555        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2556            self.mouse_cursor_hidden = hide_mouse_cursor;
 2557            cx.notify();
 2558        }
 2559    }
 2560
 2561    pub fn edit_prediction_in_conflict(&self) -> bool {
 2562        if !self.show_edit_predictions_in_menu() {
 2563            return false;
 2564        }
 2565
 2566        let showing_completions = self
 2567            .context_menu
 2568            .borrow()
 2569            .as_ref()
 2570            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2571
 2572        showing_completions
 2573            || self.edit_prediction_requires_modifier()
 2574            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2575            // bindings to insert tab characters.
 2576            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2577    }
 2578
 2579    pub fn accept_edit_prediction_keybind(
 2580        &self,
 2581        accept_partial: bool,
 2582        window: &Window,
 2583        cx: &App,
 2584    ) -> AcceptEditPredictionBinding {
 2585        let key_context = self.key_context_internal(true, window, cx);
 2586        let in_conflict = self.edit_prediction_in_conflict();
 2587
 2588        let bindings = if accept_partial {
 2589            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2590        } else {
 2591            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2592        };
 2593
 2594        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2595        // just the first one.
 2596        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2597            !in_conflict
 2598                || binding
 2599                    .keystrokes()
 2600                    .first()
 2601                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2602        }))
 2603    }
 2604
 2605    pub fn new_file(
 2606        workspace: &mut Workspace,
 2607        _: &workspace::NewFile,
 2608        window: &mut Window,
 2609        cx: &mut Context<Workspace>,
 2610    ) {
 2611        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2612            "Failed to create buffer",
 2613            window,
 2614            cx,
 2615            |e, _, _| match e.error_code() {
 2616                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2617                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2618                e.error_tag("required").unwrap_or("the latest version")
 2619            )),
 2620                _ => None,
 2621            },
 2622        );
 2623    }
 2624
 2625    pub fn new_in_workspace(
 2626        workspace: &mut Workspace,
 2627        window: &mut Window,
 2628        cx: &mut Context<Workspace>,
 2629    ) -> Task<Result<Entity<Editor>>> {
 2630        let project = workspace.project().clone();
 2631        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2632
 2633        cx.spawn_in(window, async move |workspace, cx| {
 2634            let buffer = create.await?;
 2635            workspace.update_in(cx, |workspace, window, cx| {
 2636                let editor =
 2637                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2638                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2639                editor
 2640            })
 2641        })
 2642    }
 2643
 2644    fn new_file_vertical(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitVertical,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_horizontal(
 2654        workspace: &mut Workspace,
 2655        _: &workspace::NewFileSplitHorizontal,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2660    }
 2661
 2662    fn new_file_in_direction(
 2663        workspace: &mut Workspace,
 2664        direction: SplitDirection,
 2665        window: &mut Window,
 2666        cx: &mut Context<Workspace>,
 2667    ) {
 2668        let project = workspace.project().clone();
 2669        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2670
 2671        cx.spawn_in(window, async move |workspace, cx| {
 2672            let buffer = create.await?;
 2673            workspace.update_in(cx, move |workspace, window, cx| {
 2674                workspace.split_item(
 2675                    direction,
 2676                    Box::new(
 2677                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2678                    ),
 2679                    window,
 2680                    cx,
 2681                )
 2682            })?;
 2683            anyhow::Ok(())
 2684        })
 2685        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2686            match e.error_code() {
 2687                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2688                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2689                e.error_tag("required").unwrap_or("the latest version")
 2690            )),
 2691                _ => None,
 2692            }
 2693        });
 2694    }
 2695
 2696    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2697        self.leader_id
 2698    }
 2699
 2700    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2701        &self.buffer
 2702    }
 2703
 2704    pub fn project(&self) -> Option<&Entity<Project>> {
 2705        self.project.as_ref()
 2706    }
 2707
 2708    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2709        self.workspace.as_ref()?.0.upgrade()
 2710    }
 2711
 2712    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2713        self.buffer().read(cx).title(cx)
 2714    }
 2715
 2716    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2717        let git_blame_gutter_max_author_length = self
 2718            .render_git_blame_gutter(cx)
 2719            .then(|| {
 2720                if let Some(blame) = self.blame.as_ref() {
 2721                    let max_author_length =
 2722                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2723                    Some(max_author_length)
 2724                } else {
 2725                    None
 2726                }
 2727            })
 2728            .flatten();
 2729
 2730        EditorSnapshot {
 2731            mode: self.mode.clone(),
 2732            show_gutter: self.show_gutter,
 2733            show_line_numbers: self.show_line_numbers,
 2734            show_git_diff_gutter: self.show_git_diff_gutter,
 2735            show_code_actions: self.show_code_actions,
 2736            show_runnables: self.show_runnables,
 2737            show_breakpoints: self.show_breakpoints,
 2738            git_blame_gutter_max_author_length,
 2739            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2740            placeholder_display_snapshot: self
 2741                .placeholder_display_map
 2742                .as_ref()
 2743                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2744            scroll_anchor: self.scroll_manager.anchor(),
 2745            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2746            is_focused: self.focus_handle.is_focused(window),
 2747            current_line_highlight: self
 2748                .current_line_highlight
 2749                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2750            gutter_hovered: self.gutter_hovered,
 2751        }
 2752    }
 2753
 2754    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2755        self.buffer.read(cx).language_at(point, cx)
 2756    }
 2757
 2758    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2759        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2760    }
 2761
 2762    pub fn active_excerpt(
 2763        &self,
 2764        cx: &App,
 2765    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2766        self.buffer
 2767            .read(cx)
 2768            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2769    }
 2770
 2771    pub fn mode(&self) -> &EditorMode {
 2772        &self.mode
 2773    }
 2774
 2775    pub fn set_mode(&mut self, mode: EditorMode) {
 2776        self.mode = mode;
 2777    }
 2778
 2779    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2780        self.collaboration_hub.as_deref()
 2781    }
 2782
 2783    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2784        self.collaboration_hub = Some(hub);
 2785    }
 2786
 2787    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2788        self.in_project_search = in_project_search;
 2789    }
 2790
 2791    pub fn set_custom_context_menu(
 2792        &mut self,
 2793        f: impl 'static
 2794        + Fn(
 2795            &mut Self,
 2796            DisplayPoint,
 2797            &mut Window,
 2798            &mut Context<Self>,
 2799        ) -> Option<Entity<ui::ContextMenu>>,
 2800    ) {
 2801        self.custom_context_menu = Some(Box::new(f))
 2802    }
 2803
 2804    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2805        self.completion_provider = provider;
 2806    }
 2807
 2808    #[cfg(any(test, feature = "test-support"))]
 2809    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2810        self.completion_provider.clone()
 2811    }
 2812
 2813    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2814        self.semantics_provider.clone()
 2815    }
 2816
 2817    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2818        self.semantics_provider = provider;
 2819    }
 2820
 2821    pub fn set_edit_prediction_provider<T>(
 2822        &mut self,
 2823        provider: Option<Entity<T>>,
 2824        window: &mut Window,
 2825        cx: &mut Context<Self>,
 2826    ) where
 2827        T: EditPredictionProvider,
 2828    {
 2829        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2830            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2831                if this.focus_handle.is_focused(window) {
 2832                    this.update_visible_edit_prediction(window, cx);
 2833                }
 2834            }),
 2835            provider: Arc::new(provider),
 2836        });
 2837        self.update_edit_prediction_settings(cx);
 2838        self.refresh_edit_prediction(false, false, window, cx);
 2839    }
 2840
 2841    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2842        self.placeholder_display_map
 2843            .as_ref()
 2844            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2845    }
 2846
 2847    pub fn set_placeholder_text(
 2848        &mut self,
 2849        placeholder_text: &str,
 2850        window: &mut Window,
 2851        cx: &mut Context<Self>,
 2852    ) {
 2853        let multibuffer = cx
 2854            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2855
 2856        let style = window.text_style();
 2857
 2858        self.placeholder_display_map = Some(cx.new(|cx| {
 2859            DisplayMap::new(
 2860                multibuffer,
 2861                style.font(),
 2862                style.font_size.to_pixels(window.rem_size()),
 2863                None,
 2864                FILE_HEADER_HEIGHT,
 2865                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2866                Default::default(),
 2867                DiagnosticSeverity::Off,
 2868                cx,
 2869            )
 2870        }));
 2871        cx.notify();
 2872    }
 2873
 2874    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2875        self.cursor_shape = cursor_shape;
 2876
 2877        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2878        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2879
 2880        cx.notify();
 2881    }
 2882
 2883    pub fn set_current_line_highlight(
 2884        &mut self,
 2885        current_line_highlight: Option<CurrentLineHighlight>,
 2886    ) {
 2887        self.current_line_highlight = current_line_highlight;
 2888    }
 2889
 2890    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2891        self.collapse_matches = collapse_matches;
 2892    }
 2893
 2894    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2895        let buffers = self.buffer.read(cx).all_buffers();
 2896        let Some(project) = self.project.as_ref() else {
 2897            return;
 2898        };
 2899        project.update(cx, |project, cx| {
 2900            for buffer in buffers {
 2901                self.registered_buffers
 2902                    .entry(buffer.read(cx).remote_id())
 2903                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2904            }
 2905        })
 2906    }
 2907
 2908    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2909        if self.collapse_matches {
 2910            return range.start..range.start;
 2911        }
 2912        range.clone()
 2913    }
 2914
 2915    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2916        if self.display_map.read(cx).clip_at_line_ends != clip {
 2917            self.display_map
 2918                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2919        }
 2920    }
 2921
 2922    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2923        self.input_enabled = input_enabled;
 2924    }
 2925
 2926    pub fn set_edit_predictions_hidden_for_vim_mode(
 2927        &mut self,
 2928        hidden: bool,
 2929        window: &mut Window,
 2930        cx: &mut Context<Self>,
 2931    ) {
 2932        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2933            self.edit_predictions_hidden_for_vim_mode = hidden;
 2934            if hidden {
 2935                self.update_visible_edit_prediction(window, cx);
 2936            } else {
 2937                self.refresh_edit_prediction(true, false, window, cx);
 2938            }
 2939        }
 2940    }
 2941
 2942    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2943        self.menu_edit_predictions_policy = value;
 2944    }
 2945
 2946    pub fn set_autoindent(&mut self, autoindent: bool) {
 2947        if autoindent {
 2948            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2949        } else {
 2950            self.autoindent_mode = None;
 2951        }
 2952    }
 2953
 2954    pub fn read_only(&self, cx: &App) -> bool {
 2955        self.read_only || self.buffer.read(cx).read_only()
 2956    }
 2957
 2958    pub fn set_read_only(&mut self, read_only: bool) {
 2959        self.read_only = read_only;
 2960    }
 2961
 2962    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2963        self.use_autoclose = autoclose;
 2964    }
 2965
 2966    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2967        self.use_auto_surround = auto_surround;
 2968    }
 2969
 2970    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2971        self.auto_replace_emoji_shortcode = auto_replace;
 2972    }
 2973
 2974    pub fn toggle_edit_predictions(
 2975        &mut self,
 2976        _: &ToggleEditPrediction,
 2977        window: &mut Window,
 2978        cx: &mut Context<Self>,
 2979    ) {
 2980        if self.show_edit_predictions_override.is_some() {
 2981            self.set_show_edit_predictions(None, window, cx);
 2982        } else {
 2983            let show_edit_predictions = !self.edit_predictions_enabled();
 2984            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2985        }
 2986    }
 2987
 2988    pub fn set_show_edit_predictions(
 2989        &mut self,
 2990        show_edit_predictions: Option<bool>,
 2991        window: &mut Window,
 2992        cx: &mut Context<Self>,
 2993    ) {
 2994        self.show_edit_predictions_override = show_edit_predictions;
 2995        self.update_edit_prediction_settings(cx);
 2996
 2997        if let Some(false) = show_edit_predictions {
 2998            self.discard_edit_prediction(false, cx);
 2999        } else {
 3000            self.refresh_edit_prediction(false, true, window, cx);
 3001        }
 3002    }
 3003
 3004    fn edit_predictions_disabled_in_scope(
 3005        &self,
 3006        buffer: &Entity<Buffer>,
 3007        buffer_position: language::Anchor,
 3008        cx: &App,
 3009    ) -> bool {
 3010        let snapshot = buffer.read(cx).snapshot();
 3011        let settings = snapshot.settings_at(buffer_position, cx);
 3012
 3013        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3014            return false;
 3015        };
 3016
 3017        scope.override_name().is_some_and(|scope_name| {
 3018            settings
 3019                .edit_predictions_disabled_in
 3020                .iter()
 3021                .any(|s| s == scope_name)
 3022        })
 3023    }
 3024
 3025    pub fn set_use_modal_editing(&mut self, to: bool) {
 3026        self.use_modal_editing = to;
 3027    }
 3028
 3029    pub fn use_modal_editing(&self) -> bool {
 3030        self.use_modal_editing
 3031    }
 3032
 3033    fn selections_did_change(
 3034        &mut self,
 3035        local: bool,
 3036        old_cursor_position: &Anchor,
 3037        effects: SelectionEffects,
 3038        window: &mut Window,
 3039        cx: &mut Context<Self>,
 3040    ) {
 3041        window.invalidate_character_coordinates();
 3042
 3043        // Copy selections to primary selection buffer
 3044        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3045        if local {
 3046            let selections = self.selections.all::<usize>(cx);
 3047            let buffer_handle = self.buffer.read(cx).read(cx);
 3048
 3049            let mut text = String::new();
 3050            for (index, selection) in selections.iter().enumerate() {
 3051                let text_for_selection = buffer_handle
 3052                    .text_for_range(selection.start..selection.end)
 3053                    .collect::<String>();
 3054
 3055                text.push_str(&text_for_selection);
 3056                if index != selections.len() - 1 {
 3057                    text.push('\n');
 3058                }
 3059            }
 3060
 3061            if !text.is_empty() {
 3062                cx.write_to_primary(ClipboardItem::new_string(text));
 3063            }
 3064        }
 3065
 3066        let selection_anchors = self.selections.disjoint_anchors_arc();
 3067
 3068        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3069            self.buffer.update(cx, |buffer, cx| {
 3070                buffer.set_active_selections(
 3071                    &selection_anchors,
 3072                    self.selections.line_mode(),
 3073                    self.cursor_shape,
 3074                    cx,
 3075                )
 3076            });
 3077        }
 3078        let display_map = self
 3079            .display_map
 3080            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3081        let buffer = &display_map.buffer_snapshot;
 3082        if self.selections.count() == 1 {
 3083            self.add_selections_state = None;
 3084        }
 3085        self.select_next_state = None;
 3086        self.select_prev_state = None;
 3087        self.select_syntax_node_history.try_clear();
 3088        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3089        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3090        self.take_rename(false, window, cx);
 3091
 3092        let newest_selection = self.selections.newest_anchor();
 3093        let new_cursor_position = newest_selection.head();
 3094        let selection_start = newest_selection.start;
 3095
 3096        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3097            self.push_to_nav_history(
 3098                *old_cursor_position,
 3099                Some(new_cursor_position.to_point(buffer)),
 3100                false,
 3101                effects.nav_history == Some(true),
 3102                cx,
 3103            );
 3104        }
 3105
 3106        if local {
 3107            if let Some(buffer_id) = new_cursor_position.buffer_id
 3108                && !self.registered_buffers.contains_key(&buffer_id)
 3109                && let Some(project) = self.project.as_ref()
 3110            {
 3111                project.update(cx, |project, cx| {
 3112                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3113                        return;
 3114                    };
 3115                    self.registered_buffers.insert(
 3116                        buffer_id,
 3117                        project.register_buffer_with_language_servers(&buffer, cx),
 3118                    );
 3119                })
 3120            }
 3121
 3122            let mut context_menu = self.context_menu.borrow_mut();
 3123            let completion_menu = match context_menu.as_ref() {
 3124                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3125                Some(CodeContextMenu::CodeActions(_)) => {
 3126                    *context_menu = None;
 3127                    None
 3128                }
 3129                None => None,
 3130            };
 3131            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3132            drop(context_menu);
 3133
 3134            if effects.completions
 3135                && let Some(completion_position) = completion_position
 3136            {
 3137                let start_offset = selection_start.to_offset(buffer);
 3138                let position_matches = start_offset == completion_position.to_offset(buffer);
 3139                let continue_showing = if position_matches {
 3140                    if self.snippet_stack.is_empty() {
 3141                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3142                            == Some(CharKind::Word)
 3143                    } else {
 3144                        // Snippet choices can be shown even when the cursor is in whitespace.
 3145                        // Dismissing the menu with actions like backspace is handled by
 3146                        // invalidation regions.
 3147                        true
 3148                    }
 3149                } else {
 3150                    false
 3151                };
 3152
 3153                if continue_showing {
 3154                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3155                } else {
 3156                    self.hide_context_menu(window, cx);
 3157                }
 3158            }
 3159
 3160            hide_hover(self, cx);
 3161
 3162            if old_cursor_position.to_display_point(&display_map).row()
 3163                != new_cursor_position.to_display_point(&display_map).row()
 3164            {
 3165                self.available_code_actions.take();
 3166            }
 3167            self.refresh_code_actions(window, cx);
 3168            self.refresh_document_highlights(cx);
 3169            self.refresh_selected_text_highlights(false, window, cx);
 3170            refresh_matching_bracket_highlights(self, window, cx);
 3171            self.update_visible_edit_prediction(window, cx);
 3172            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3173            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3174            self.inline_blame_popover.take();
 3175            if self.git_blame_inline_enabled {
 3176                self.start_inline_blame_timer(window, cx);
 3177            }
 3178        }
 3179
 3180        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3181        cx.emit(EditorEvent::SelectionsChanged { local });
 3182
 3183        let selections = &self.selections.disjoint_anchors_arc();
 3184        if selections.len() == 1 {
 3185            cx.emit(SearchEvent::ActiveMatchChanged)
 3186        }
 3187        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3188            let inmemory_selections = selections
 3189                .iter()
 3190                .map(|s| {
 3191                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3192                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3193                })
 3194                .collect();
 3195            self.update_restoration_data(cx, |data| {
 3196                data.selections = inmemory_selections;
 3197            });
 3198
 3199            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3200                && let Some(workspace_id) =
 3201                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3202            {
 3203                let snapshot = self.buffer().read(cx).snapshot(cx);
 3204                let selections = selections.clone();
 3205                let background_executor = cx.background_executor().clone();
 3206                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3207                self.serialize_selections = cx.background_spawn(async move {
 3208                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3209                            let db_selections = selections
 3210                                .iter()
 3211                                .map(|selection| {
 3212                                    (
 3213                                        selection.start.to_offset(&snapshot),
 3214                                        selection.end.to_offset(&snapshot),
 3215                                    )
 3216                                })
 3217                                .collect();
 3218
 3219                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3220                                .await
 3221                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3222                                .log_err();
 3223                        });
 3224            }
 3225        }
 3226
 3227        cx.notify();
 3228    }
 3229
 3230    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3231        use text::ToOffset as _;
 3232        use text::ToPoint as _;
 3233
 3234        if self.mode.is_minimap()
 3235            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3236        {
 3237            return;
 3238        }
 3239
 3240        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3241            return;
 3242        };
 3243
 3244        let snapshot = singleton.read(cx).snapshot();
 3245        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3246            let display_snapshot = display_map.snapshot(cx);
 3247
 3248            display_snapshot
 3249                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3250                .map(|fold| {
 3251                    fold.range.start.text_anchor.to_point(&snapshot)
 3252                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3253                })
 3254                .collect()
 3255        });
 3256        self.update_restoration_data(cx, |data| {
 3257            data.folds = inmemory_folds;
 3258        });
 3259
 3260        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3261            return;
 3262        };
 3263        let background_executor = cx.background_executor().clone();
 3264        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3265        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3266            display_map
 3267                .snapshot(cx)
 3268                .folds_in_range(0..snapshot.len())
 3269                .map(|fold| {
 3270                    (
 3271                        fold.range.start.text_anchor.to_offset(&snapshot),
 3272                        fold.range.end.text_anchor.to_offset(&snapshot),
 3273                    )
 3274                })
 3275                .collect()
 3276        });
 3277        self.serialize_folds = cx.background_spawn(async move {
 3278            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3279            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3280                .await
 3281                .with_context(|| {
 3282                    format!(
 3283                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3284                    )
 3285                })
 3286                .log_err();
 3287        });
 3288    }
 3289
 3290    pub fn sync_selections(
 3291        &mut self,
 3292        other: Entity<Editor>,
 3293        cx: &mut Context<Self>,
 3294    ) -> gpui::Subscription {
 3295        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3296        self.selections.change_with(cx, |selections| {
 3297            selections.select_anchors(other_selections);
 3298        });
 3299
 3300        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3301            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3302                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3303                if other_selections.is_empty() {
 3304                    return;
 3305                }
 3306                this.selections.change_with(cx, |selections| {
 3307                    selections.select_anchors(other_selections);
 3308                });
 3309            }
 3310        });
 3311
 3312        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3313            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3314                let these_selections = this.selections.disjoint_anchors().to_vec();
 3315                if these_selections.is_empty() {
 3316                    return;
 3317                }
 3318                other.update(cx, |other_editor, cx| {
 3319                    other_editor.selections.change_with(cx, |selections| {
 3320                        selections.select_anchors(these_selections);
 3321                    })
 3322                });
 3323            }
 3324        });
 3325
 3326        Subscription::join(other_subscription, this_subscription)
 3327    }
 3328
 3329    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3330    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3331    /// effects of selection change occur at the end of the transaction.
 3332    pub fn change_selections<R>(
 3333        &mut self,
 3334        effects: SelectionEffects,
 3335        window: &mut Window,
 3336        cx: &mut Context<Self>,
 3337        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3338    ) -> R {
 3339        if let Some(state) = &mut self.deferred_selection_effects_state {
 3340            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3341            state.effects.completions = effects.completions;
 3342            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3343            let (changed, result) = self.selections.change_with(cx, change);
 3344            state.changed |= changed;
 3345            return result;
 3346        }
 3347        let mut state = DeferredSelectionEffectsState {
 3348            changed: false,
 3349            effects,
 3350            old_cursor_position: self.selections.newest_anchor().head(),
 3351            history_entry: SelectionHistoryEntry {
 3352                selections: self.selections.disjoint_anchors_arc(),
 3353                select_next_state: self.select_next_state.clone(),
 3354                select_prev_state: self.select_prev_state.clone(),
 3355                add_selections_state: self.add_selections_state.clone(),
 3356            },
 3357        };
 3358        let (changed, result) = self.selections.change_with(cx, change);
 3359        state.changed = state.changed || changed;
 3360        if self.defer_selection_effects {
 3361            self.deferred_selection_effects_state = Some(state);
 3362        } else {
 3363            self.apply_selection_effects(state, window, cx);
 3364        }
 3365        result
 3366    }
 3367
 3368    /// Defers the effects of selection change, so that the effects of multiple calls to
 3369    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3370    /// to selection history and the state of popovers based on selection position aren't
 3371    /// erroneously updated.
 3372    pub fn with_selection_effects_deferred<R>(
 3373        &mut self,
 3374        window: &mut Window,
 3375        cx: &mut Context<Self>,
 3376        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3377    ) -> R {
 3378        let already_deferred = self.defer_selection_effects;
 3379        self.defer_selection_effects = true;
 3380        let result = update(self, window, cx);
 3381        if !already_deferred {
 3382            self.defer_selection_effects = false;
 3383            if let Some(state) = self.deferred_selection_effects_state.take() {
 3384                self.apply_selection_effects(state, window, cx);
 3385            }
 3386        }
 3387        result
 3388    }
 3389
 3390    fn apply_selection_effects(
 3391        &mut self,
 3392        state: DeferredSelectionEffectsState,
 3393        window: &mut Window,
 3394        cx: &mut Context<Self>,
 3395    ) {
 3396        if state.changed {
 3397            self.selection_history.push(state.history_entry);
 3398
 3399            if let Some(autoscroll) = state.effects.scroll {
 3400                self.request_autoscroll(autoscroll, cx);
 3401            }
 3402
 3403            let old_cursor_position = &state.old_cursor_position;
 3404
 3405            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3406
 3407            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3408                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3409            }
 3410        }
 3411    }
 3412
 3413    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3414    where
 3415        I: IntoIterator<Item = (Range<S>, T)>,
 3416        S: ToOffset,
 3417        T: Into<Arc<str>>,
 3418    {
 3419        if self.read_only(cx) {
 3420            return;
 3421        }
 3422
 3423        self.buffer
 3424            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3425    }
 3426
 3427    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3428    where
 3429        I: IntoIterator<Item = (Range<S>, T)>,
 3430        S: ToOffset,
 3431        T: Into<Arc<str>>,
 3432    {
 3433        if self.read_only(cx) {
 3434            return;
 3435        }
 3436
 3437        self.buffer.update(cx, |buffer, cx| {
 3438            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3439        });
 3440    }
 3441
 3442    pub fn edit_with_block_indent<I, S, T>(
 3443        &mut self,
 3444        edits: I,
 3445        original_indent_columns: Vec<Option<u32>>,
 3446        cx: &mut Context<Self>,
 3447    ) where
 3448        I: IntoIterator<Item = (Range<S>, T)>,
 3449        S: ToOffset,
 3450        T: Into<Arc<str>>,
 3451    {
 3452        if self.read_only(cx) {
 3453            return;
 3454        }
 3455
 3456        self.buffer.update(cx, |buffer, cx| {
 3457            buffer.edit(
 3458                edits,
 3459                Some(AutoindentMode::Block {
 3460                    original_indent_columns,
 3461                }),
 3462                cx,
 3463            )
 3464        });
 3465    }
 3466
 3467    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3468        self.hide_context_menu(window, cx);
 3469
 3470        match phase {
 3471            SelectPhase::Begin {
 3472                position,
 3473                add,
 3474                click_count,
 3475            } => self.begin_selection(position, add, click_count, window, cx),
 3476            SelectPhase::BeginColumnar {
 3477                position,
 3478                goal_column,
 3479                reset,
 3480                mode,
 3481            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3482            SelectPhase::Extend {
 3483                position,
 3484                click_count,
 3485            } => self.extend_selection(position, click_count, window, cx),
 3486            SelectPhase::Update {
 3487                position,
 3488                goal_column,
 3489                scroll_delta,
 3490            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3491            SelectPhase::End => self.end_selection(window, cx),
 3492        }
 3493    }
 3494
 3495    fn extend_selection(
 3496        &mut self,
 3497        position: DisplayPoint,
 3498        click_count: usize,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3503        let tail = self.selections.newest::<usize>(cx).tail();
 3504        self.begin_selection(position, false, click_count, window, cx);
 3505
 3506        let position = position.to_offset(&display_map, Bias::Left);
 3507        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3508
 3509        let mut pending_selection = self
 3510            .selections
 3511            .pending_anchor()
 3512            .cloned()
 3513            .expect("extend_selection not called with pending selection");
 3514        if position >= tail {
 3515            pending_selection.start = tail_anchor;
 3516        } else {
 3517            pending_selection.end = tail_anchor;
 3518            pending_selection.reversed = true;
 3519        }
 3520
 3521        let mut pending_mode = self.selections.pending_mode().unwrap();
 3522        match &mut pending_mode {
 3523            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3524            _ => {}
 3525        }
 3526
 3527        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3528            SelectionEffects::scroll(Autoscroll::fit())
 3529        } else {
 3530            SelectionEffects::no_scroll()
 3531        };
 3532
 3533        self.change_selections(effects, window, cx, |s| {
 3534            s.set_pending(pending_selection.clone(), pending_mode)
 3535        });
 3536    }
 3537
 3538    fn begin_selection(
 3539        &mut self,
 3540        position: DisplayPoint,
 3541        add: bool,
 3542        click_count: usize,
 3543        window: &mut Window,
 3544        cx: &mut Context<Self>,
 3545    ) {
 3546        if !self.focus_handle.is_focused(window) {
 3547            self.last_focused_descendant = None;
 3548            window.focus(&self.focus_handle);
 3549        }
 3550
 3551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3552        let buffer = &display_map.buffer_snapshot;
 3553        let position = display_map.clip_point(position, Bias::Left);
 3554
 3555        let start;
 3556        let end;
 3557        let mode;
 3558        let mut auto_scroll;
 3559        match click_count {
 3560            1 => {
 3561                start = buffer.anchor_before(position.to_point(&display_map));
 3562                end = start;
 3563                mode = SelectMode::Character;
 3564                auto_scroll = true;
 3565            }
 3566            2 => {
 3567                let position = display_map
 3568                    .clip_point(position, Bias::Left)
 3569                    .to_offset(&display_map, Bias::Left);
 3570                let (range, _) = buffer.surrounding_word(position, None);
 3571                start = buffer.anchor_before(range.start);
 3572                end = buffer.anchor_before(range.end);
 3573                mode = SelectMode::Word(start..end);
 3574                auto_scroll = true;
 3575            }
 3576            3 => {
 3577                let position = display_map
 3578                    .clip_point(position, Bias::Left)
 3579                    .to_point(&display_map);
 3580                let line_start = display_map.prev_line_boundary(position).0;
 3581                let next_line_start = buffer.clip_point(
 3582                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3583                    Bias::Left,
 3584                );
 3585                start = buffer.anchor_before(line_start);
 3586                end = buffer.anchor_before(next_line_start);
 3587                mode = SelectMode::Line(start..end);
 3588                auto_scroll = true;
 3589            }
 3590            _ => {
 3591                start = buffer.anchor_before(0);
 3592                end = buffer.anchor_before(buffer.len());
 3593                mode = SelectMode::All;
 3594                auto_scroll = false;
 3595            }
 3596        }
 3597        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3598
 3599        let point_to_delete: Option<usize> = {
 3600            let selected_points: Vec<Selection<Point>> =
 3601                self.selections.disjoint_in_range(start..end, cx);
 3602
 3603            if !add || click_count > 1 {
 3604                None
 3605            } else if !selected_points.is_empty() {
 3606                Some(selected_points[0].id)
 3607            } else {
 3608                let clicked_point_already_selected =
 3609                    self.selections.disjoint_anchors().iter().find(|selection| {
 3610                        selection.start.to_point(buffer) == start.to_point(buffer)
 3611                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3612                    });
 3613
 3614                clicked_point_already_selected.map(|selection| selection.id)
 3615            }
 3616        };
 3617
 3618        let selections_count = self.selections.count();
 3619        let effects = if auto_scroll {
 3620            SelectionEffects::default()
 3621        } else {
 3622            SelectionEffects::no_scroll()
 3623        };
 3624
 3625        self.change_selections(effects, window, cx, |s| {
 3626            if let Some(point_to_delete) = point_to_delete {
 3627                s.delete(point_to_delete);
 3628
 3629                if selections_count == 1 {
 3630                    s.set_pending_anchor_range(start..end, mode);
 3631                }
 3632            } else {
 3633                if !add {
 3634                    s.clear_disjoint();
 3635                }
 3636
 3637                s.set_pending_anchor_range(start..end, mode);
 3638            }
 3639        });
 3640    }
 3641
 3642    fn begin_columnar_selection(
 3643        &mut self,
 3644        position: DisplayPoint,
 3645        goal_column: u32,
 3646        reset: bool,
 3647        mode: ColumnarMode,
 3648        window: &mut Window,
 3649        cx: &mut Context<Self>,
 3650    ) {
 3651        if !self.focus_handle.is_focused(window) {
 3652            self.last_focused_descendant = None;
 3653            window.focus(&self.focus_handle);
 3654        }
 3655
 3656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3657
 3658        if reset {
 3659            let pointer_position = display_map
 3660                .buffer_snapshot
 3661                .anchor_before(position.to_point(&display_map));
 3662
 3663            self.change_selections(
 3664                SelectionEffects::scroll(Autoscroll::newest()),
 3665                window,
 3666                cx,
 3667                |s| {
 3668                    s.clear_disjoint();
 3669                    s.set_pending_anchor_range(
 3670                        pointer_position..pointer_position,
 3671                        SelectMode::Character,
 3672                    );
 3673                },
 3674            );
 3675        };
 3676
 3677        let tail = self.selections.newest::<Point>(cx).tail();
 3678        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3679        self.columnar_selection_state = match mode {
 3680            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3681                selection_tail: selection_anchor,
 3682                display_point: if reset {
 3683                    if position.column() != goal_column {
 3684                        Some(DisplayPoint::new(position.row(), goal_column))
 3685                    } else {
 3686                        None
 3687                    }
 3688                } else {
 3689                    None
 3690                },
 3691            }),
 3692            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3693                selection_tail: selection_anchor,
 3694            }),
 3695        };
 3696
 3697        if !reset {
 3698            self.select_columns(position, goal_column, &display_map, window, cx);
 3699        }
 3700    }
 3701
 3702    fn update_selection(
 3703        &mut self,
 3704        position: DisplayPoint,
 3705        goal_column: u32,
 3706        scroll_delta: gpui::Point<f32>,
 3707        window: &mut Window,
 3708        cx: &mut Context<Self>,
 3709    ) {
 3710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3711
 3712        if self.columnar_selection_state.is_some() {
 3713            self.select_columns(position, goal_column, &display_map, window, cx);
 3714        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3715            let buffer = &display_map.buffer_snapshot;
 3716            let head;
 3717            let tail;
 3718            let mode = self.selections.pending_mode().unwrap();
 3719            match &mode {
 3720                SelectMode::Character => {
 3721                    head = position.to_point(&display_map);
 3722                    tail = pending.tail().to_point(buffer);
 3723                }
 3724                SelectMode::Word(original_range) => {
 3725                    let offset = display_map
 3726                        .clip_point(position, Bias::Left)
 3727                        .to_offset(&display_map, Bias::Left);
 3728                    let original_range = original_range.to_offset(buffer);
 3729
 3730                    let head_offset = if buffer.is_inside_word(offset, None)
 3731                        || original_range.contains(&offset)
 3732                    {
 3733                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3734                        if word_range.start < original_range.start {
 3735                            word_range.start
 3736                        } else {
 3737                            word_range.end
 3738                        }
 3739                    } else {
 3740                        offset
 3741                    };
 3742
 3743                    head = head_offset.to_point(buffer);
 3744                    if head_offset <= original_range.start {
 3745                        tail = original_range.end.to_point(buffer);
 3746                    } else {
 3747                        tail = original_range.start.to_point(buffer);
 3748                    }
 3749                }
 3750                SelectMode::Line(original_range) => {
 3751                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3752
 3753                    let position = display_map
 3754                        .clip_point(position, Bias::Left)
 3755                        .to_point(&display_map);
 3756                    let line_start = display_map.prev_line_boundary(position).0;
 3757                    let next_line_start = buffer.clip_point(
 3758                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3759                        Bias::Left,
 3760                    );
 3761
 3762                    if line_start < original_range.start {
 3763                        head = line_start
 3764                    } else {
 3765                        head = next_line_start
 3766                    }
 3767
 3768                    if head <= original_range.start {
 3769                        tail = original_range.end;
 3770                    } else {
 3771                        tail = original_range.start;
 3772                    }
 3773                }
 3774                SelectMode::All => {
 3775                    return;
 3776                }
 3777            };
 3778
 3779            if head < tail {
 3780                pending.start = buffer.anchor_before(head);
 3781                pending.end = buffer.anchor_before(tail);
 3782                pending.reversed = true;
 3783            } else {
 3784                pending.start = buffer.anchor_before(tail);
 3785                pending.end = buffer.anchor_before(head);
 3786                pending.reversed = false;
 3787            }
 3788
 3789            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3790                s.set_pending(pending.clone(), mode);
 3791            });
 3792        } else {
 3793            log::error!("update_selection dispatched with no pending selection");
 3794            return;
 3795        }
 3796
 3797        self.apply_scroll_delta(scroll_delta, window, cx);
 3798        cx.notify();
 3799    }
 3800
 3801    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3802        self.columnar_selection_state.take();
 3803        if self.selections.pending_anchor().is_some() {
 3804            let selections = self.selections.all::<usize>(cx);
 3805            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3806                s.select(selections);
 3807                s.clear_pending();
 3808            });
 3809        }
 3810    }
 3811
 3812    fn select_columns(
 3813        &mut self,
 3814        head: DisplayPoint,
 3815        goal_column: u32,
 3816        display_map: &DisplaySnapshot,
 3817        window: &mut Window,
 3818        cx: &mut Context<Self>,
 3819    ) {
 3820        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3821            return;
 3822        };
 3823
 3824        let tail = match columnar_state {
 3825            ColumnarSelectionState::FromMouse {
 3826                selection_tail,
 3827                display_point,
 3828            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3829            ColumnarSelectionState::FromSelection { selection_tail } => {
 3830                selection_tail.to_display_point(display_map)
 3831            }
 3832        };
 3833
 3834        let start_row = cmp::min(tail.row(), head.row());
 3835        let end_row = cmp::max(tail.row(), head.row());
 3836        let start_column = cmp::min(tail.column(), goal_column);
 3837        let end_column = cmp::max(tail.column(), goal_column);
 3838        let reversed = start_column < tail.column();
 3839
 3840        let selection_ranges = (start_row.0..=end_row.0)
 3841            .map(DisplayRow)
 3842            .filter_map(|row| {
 3843                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3844                    || start_column <= display_map.line_len(row))
 3845                    && !display_map.is_block_line(row)
 3846                {
 3847                    let start = display_map
 3848                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3849                        .to_point(display_map);
 3850                    let end = display_map
 3851                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3852                        .to_point(display_map);
 3853                    if reversed {
 3854                        Some(end..start)
 3855                    } else {
 3856                        Some(start..end)
 3857                    }
 3858                } else {
 3859                    None
 3860                }
 3861            })
 3862            .collect::<Vec<_>>();
 3863
 3864        let ranges = match columnar_state {
 3865            ColumnarSelectionState::FromMouse { .. } => {
 3866                let mut non_empty_ranges = selection_ranges
 3867                    .iter()
 3868                    .filter(|selection_range| selection_range.start != selection_range.end)
 3869                    .peekable();
 3870                if non_empty_ranges.peek().is_some() {
 3871                    non_empty_ranges.cloned().collect()
 3872                } else {
 3873                    selection_ranges
 3874                }
 3875            }
 3876            _ => selection_ranges,
 3877        };
 3878
 3879        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3880            s.select_ranges(ranges);
 3881        });
 3882        cx.notify();
 3883    }
 3884
 3885    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3886        self.selections
 3887            .all_adjusted(cx)
 3888            .iter()
 3889            .any(|selection| !selection.is_empty())
 3890    }
 3891
 3892    pub fn has_pending_nonempty_selection(&self) -> bool {
 3893        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3894            Some(Selection { start, end, .. }) => start != end,
 3895            None => false,
 3896        };
 3897
 3898        pending_nonempty_selection
 3899            || (self.columnar_selection_state.is_some()
 3900                && self.selections.disjoint_anchors().len() > 1)
 3901    }
 3902
 3903    pub fn has_pending_selection(&self) -> bool {
 3904        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3905    }
 3906
 3907    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3908        self.selection_mark_mode = false;
 3909        self.selection_drag_state = SelectionDragState::None;
 3910
 3911        if self.clear_expanded_diff_hunks(cx) {
 3912            cx.notify();
 3913            return;
 3914        }
 3915        if self.dismiss_menus_and_popups(true, window, cx) {
 3916            return;
 3917        }
 3918
 3919        if self.mode.is_full()
 3920            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3921        {
 3922            return;
 3923        }
 3924
 3925        cx.propagate();
 3926    }
 3927
 3928    pub fn dismiss_menus_and_popups(
 3929        &mut self,
 3930        is_user_requested: bool,
 3931        window: &mut Window,
 3932        cx: &mut Context<Self>,
 3933    ) -> bool {
 3934        if self.take_rename(false, window, cx).is_some() {
 3935            return true;
 3936        }
 3937
 3938        if hide_hover(self, cx) {
 3939            return true;
 3940        }
 3941
 3942        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3943            return true;
 3944        }
 3945
 3946        if self.hide_context_menu(window, cx).is_some() {
 3947            return true;
 3948        }
 3949
 3950        if self.mouse_context_menu.take().is_some() {
 3951            return true;
 3952        }
 3953
 3954        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3955            return true;
 3956        }
 3957
 3958        if self.snippet_stack.pop().is_some() {
 3959            return true;
 3960        }
 3961
 3962        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3963            self.dismiss_diagnostics(cx);
 3964            return true;
 3965        }
 3966
 3967        false
 3968    }
 3969
 3970    fn linked_editing_ranges_for(
 3971        &self,
 3972        selection: Range<text::Anchor>,
 3973        cx: &App,
 3974    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3975        if self.linked_edit_ranges.is_empty() {
 3976            return None;
 3977        }
 3978        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3979            selection.end.buffer_id.and_then(|end_buffer_id| {
 3980                if selection.start.buffer_id != Some(end_buffer_id) {
 3981                    return None;
 3982                }
 3983                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3984                let snapshot = buffer.read(cx).snapshot();
 3985                self.linked_edit_ranges
 3986                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3987                    .map(|ranges| (ranges, snapshot, buffer))
 3988            })?;
 3989        use text::ToOffset as TO;
 3990        // find offset from the start of current range to current cursor position
 3991        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3992
 3993        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3994        let start_difference = start_offset - start_byte_offset;
 3995        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3996        let end_difference = end_offset - start_byte_offset;
 3997        // Current range has associated linked ranges.
 3998        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3999        for range in linked_ranges.iter() {
 4000            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4001            let end_offset = start_offset + end_difference;
 4002            let start_offset = start_offset + start_difference;
 4003            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4004                continue;
 4005            }
 4006            if self.selections.disjoint_anchor_ranges().any(|s| {
 4007                if s.start.buffer_id != selection.start.buffer_id
 4008                    || s.end.buffer_id != selection.end.buffer_id
 4009                {
 4010                    return false;
 4011                }
 4012                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4013                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4014            }) {
 4015                continue;
 4016            }
 4017            let start = buffer_snapshot.anchor_after(start_offset);
 4018            let end = buffer_snapshot.anchor_after(end_offset);
 4019            linked_edits
 4020                .entry(buffer.clone())
 4021                .or_default()
 4022                .push(start..end);
 4023        }
 4024        Some(linked_edits)
 4025    }
 4026
 4027    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4028        let text: Arc<str> = text.into();
 4029
 4030        if self.read_only(cx) {
 4031            return;
 4032        }
 4033
 4034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4035
 4036        let selections = self.selections.all_adjusted(cx);
 4037        let mut bracket_inserted = false;
 4038        let mut edits = Vec::new();
 4039        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4040        let mut new_selections = Vec::with_capacity(selections.len());
 4041        let mut new_autoclose_regions = Vec::new();
 4042        let snapshot = self.buffer.read(cx).read(cx);
 4043        let mut clear_linked_edit_ranges = false;
 4044
 4045        for (selection, autoclose_region) in
 4046            self.selections_with_autoclose_regions(selections, &snapshot)
 4047        {
 4048            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4049                // Determine if the inserted text matches the opening or closing
 4050                // bracket of any of this language's bracket pairs.
 4051                let mut bracket_pair = None;
 4052                let mut is_bracket_pair_start = false;
 4053                let mut is_bracket_pair_end = false;
 4054                if !text.is_empty() {
 4055                    let mut bracket_pair_matching_end = None;
 4056                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4057                    //  and they are removing the character that triggered IME popup.
 4058                    for (pair, enabled) in scope.brackets() {
 4059                        if !pair.close && !pair.surround {
 4060                            continue;
 4061                        }
 4062
 4063                        if enabled && pair.start.ends_with(text.as_ref()) {
 4064                            let prefix_len = pair.start.len() - text.len();
 4065                            let preceding_text_matches_prefix = prefix_len == 0
 4066                                || (selection.start.column >= (prefix_len as u32)
 4067                                    && snapshot.contains_str_at(
 4068                                        Point::new(
 4069                                            selection.start.row,
 4070                                            selection.start.column - (prefix_len as u32),
 4071                                        ),
 4072                                        &pair.start[..prefix_len],
 4073                                    ));
 4074                            if preceding_text_matches_prefix {
 4075                                bracket_pair = Some(pair.clone());
 4076                                is_bracket_pair_start = true;
 4077                                break;
 4078                            }
 4079                        }
 4080                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4081                        {
 4082                            // take first bracket pair matching end, but don't break in case a later bracket
 4083                            // pair matches start
 4084                            bracket_pair_matching_end = Some(pair.clone());
 4085                        }
 4086                    }
 4087                    if let Some(end) = bracket_pair_matching_end
 4088                        && bracket_pair.is_none()
 4089                    {
 4090                        bracket_pair = Some(end);
 4091                        is_bracket_pair_end = true;
 4092                    }
 4093                }
 4094
 4095                if let Some(bracket_pair) = bracket_pair {
 4096                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4097                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4098                    let auto_surround =
 4099                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4100                    if selection.is_empty() {
 4101                        if is_bracket_pair_start {
 4102                            // If the inserted text is a suffix of an opening bracket and the
 4103                            // selection is preceded by the rest of the opening bracket, then
 4104                            // insert the closing bracket.
 4105                            let following_text_allows_autoclose = snapshot
 4106                                .chars_at(selection.start)
 4107                                .next()
 4108                                .is_none_or(|c| scope.should_autoclose_before(c));
 4109
 4110                            let preceding_text_allows_autoclose = selection.start.column == 0
 4111                                || snapshot
 4112                                    .reversed_chars_at(selection.start)
 4113                                    .next()
 4114                                    .is_none_or(|c| {
 4115                                        bracket_pair.start != bracket_pair.end
 4116                                            || !snapshot
 4117                                                .char_classifier_at(selection.start)
 4118                                                .is_word(c)
 4119                                    });
 4120
 4121                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4122                                && bracket_pair.start.len() == 1
 4123                            {
 4124                                let target = bracket_pair.start.chars().next().unwrap();
 4125                                let current_line_count = snapshot
 4126                                    .reversed_chars_at(selection.start)
 4127                                    .take_while(|&c| c != '\n')
 4128                                    .filter(|&c| c == target)
 4129                                    .count();
 4130                                current_line_count % 2 == 1
 4131                            } else {
 4132                                false
 4133                            };
 4134
 4135                            if autoclose
 4136                                && bracket_pair.close
 4137                                && following_text_allows_autoclose
 4138                                && preceding_text_allows_autoclose
 4139                                && !is_closing_quote
 4140                            {
 4141                                let anchor = snapshot.anchor_before(selection.end);
 4142                                new_selections.push((selection.map(|_| anchor), text.len()));
 4143                                new_autoclose_regions.push((
 4144                                    anchor,
 4145                                    text.len(),
 4146                                    selection.id,
 4147                                    bracket_pair.clone(),
 4148                                ));
 4149                                edits.push((
 4150                                    selection.range(),
 4151                                    format!("{}{}", text, bracket_pair.end).into(),
 4152                                ));
 4153                                bracket_inserted = true;
 4154                                continue;
 4155                            }
 4156                        }
 4157
 4158                        if let Some(region) = autoclose_region {
 4159                            // If the selection is followed by an auto-inserted closing bracket,
 4160                            // then don't insert that closing bracket again; just move the selection
 4161                            // past the closing bracket.
 4162                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4163                                && text.as_ref() == region.pair.end.as_str()
 4164                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4165                            if should_skip {
 4166                                let anchor = snapshot.anchor_after(selection.end);
 4167                                new_selections
 4168                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4169                                continue;
 4170                            }
 4171                        }
 4172
 4173                        let always_treat_brackets_as_autoclosed = snapshot
 4174                            .language_settings_at(selection.start, cx)
 4175                            .always_treat_brackets_as_autoclosed;
 4176                        if always_treat_brackets_as_autoclosed
 4177                            && is_bracket_pair_end
 4178                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4179                        {
 4180                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4181                            // and the inserted text is a closing bracket and the selection is followed
 4182                            // by the closing bracket then move the selection past the closing bracket.
 4183                            let anchor = snapshot.anchor_after(selection.end);
 4184                            new_selections.push((selection.map(|_| anchor), text.len()));
 4185                            continue;
 4186                        }
 4187                    }
 4188                    // If an opening bracket is 1 character long and is typed while
 4189                    // text is selected, then surround that text with the bracket pair.
 4190                    else if auto_surround
 4191                        && bracket_pair.surround
 4192                        && is_bracket_pair_start
 4193                        && bracket_pair.start.chars().count() == 1
 4194                    {
 4195                        edits.push((selection.start..selection.start, text.clone()));
 4196                        edits.push((
 4197                            selection.end..selection.end,
 4198                            bracket_pair.end.as_str().into(),
 4199                        ));
 4200                        bracket_inserted = true;
 4201                        new_selections.push((
 4202                            Selection {
 4203                                id: selection.id,
 4204                                start: snapshot.anchor_after(selection.start),
 4205                                end: snapshot.anchor_before(selection.end),
 4206                                reversed: selection.reversed,
 4207                                goal: selection.goal,
 4208                            },
 4209                            0,
 4210                        ));
 4211                        continue;
 4212                    }
 4213                }
 4214            }
 4215
 4216            if self.auto_replace_emoji_shortcode
 4217                && selection.is_empty()
 4218                && text.as_ref().ends_with(':')
 4219                && let Some(possible_emoji_short_code) =
 4220                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4221                && !possible_emoji_short_code.is_empty()
 4222                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4223            {
 4224                let emoji_shortcode_start = Point::new(
 4225                    selection.start.row,
 4226                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4227                );
 4228
 4229                // Remove shortcode from buffer
 4230                edits.push((
 4231                    emoji_shortcode_start..selection.start,
 4232                    "".to_string().into(),
 4233                ));
 4234                new_selections.push((
 4235                    Selection {
 4236                        id: selection.id,
 4237                        start: snapshot.anchor_after(emoji_shortcode_start),
 4238                        end: snapshot.anchor_before(selection.start),
 4239                        reversed: selection.reversed,
 4240                        goal: selection.goal,
 4241                    },
 4242                    0,
 4243                ));
 4244
 4245                // Insert emoji
 4246                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4247                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4248                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4249
 4250                continue;
 4251            }
 4252
 4253            // If not handling any auto-close operation, then just replace the selected
 4254            // text with the given input and move the selection to the end of the
 4255            // newly inserted text.
 4256            let anchor = snapshot.anchor_after(selection.end);
 4257            if !self.linked_edit_ranges.is_empty() {
 4258                let start_anchor = snapshot.anchor_before(selection.start);
 4259
 4260                let is_word_char = text.chars().next().is_none_or(|char| {
 4261                    let classifier = snapshot
 4262                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4263                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4264                    classifier.is_word(char)
 4265                });
 4266
 4267                if is_word_char {
 4268                    if let Some(ranges) = self
 4269                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4270                    {
 4271                        for (buffer, edits) in ranges {
 4272                            linked_edits
 4273                                .entry(buffer.clone())
 4274                                .or_default()
 4275                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4276                        }
 4277                    }
 4278                } else {
 4279                    clear_linked_edit_ranges = true;
 4280                }
 4281            }
 4282
 4283            new_selections.push((selection.map(|_| anchor), 0));
 4284            edits.push((selection.start..selection.end, text.clone()));
 4285        }
 4286
 4287        drop(snapshot);
 4288
 4289        self.transact(window, cx, |this, window, cx| {
 4290            if clear_linked_edit_ranges {
 4291                this.linked_edit_ranges.clear();
 4292            }
 4293            let initial_buffer_versions =
 4294                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4295
 4296            this.buffer.update(cx, |buffer, cx| {
 4297                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4298            });
 4299            for (buffer, edits) in linked_edits {
 4300                buffer.update(cx, |buffer, cx| {
 4301                    let snapshot = buffer.snapshot();
 4302                    let edits = edits
 4303                        .into_iter()
 4304                        .map(|(range, text)| {
 4305                            use text::ToPoint as TP;
 4306                            let end_point = TP::to_point(&range.end, &snapshot);
 4307                            let start_point = TP::to_point(&range.start, &snapshot);
 4308                            (start_point..end_point, text)
 4309                        })
 4310                        .sorted_by_key(|(range, _)| range.start);
 4311                    buffer.edit(edits, None, cx);
 4312                })
 4313            }
 4314            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4315            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4316            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4317            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4318                .zip(new_selection_deltas)
 4319                .map(|(selection, delta)| Selection {
 4320                    id: selection.id,
 4321                    start: selection.start + delta,
 4322                    end: selection.end + delta,
 4323                    reversed: selection.reversed,
 4324                    goal: SelectionGoal::None,
 4325                })
 4326                .collect::<Vec<_>>();
 4327
 4328            let mut i = 0;
 4329            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4330                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4331                let start = map.buffer_snapshot.anchor_before(position);
 4332                let end = map.buffer_snapshot.anchor_after(position);
 4333                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4334                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4335                        Ordering::Less => i += 1,
 4336                        Ordering::Greater => break,
 4337                        Ordering::Equal => {
 4338                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4339                                Ordering::Less => i += 1,
 4340                                Ordering::Equal => break,
 4341                                Ordering::Greater => break,
 4342                            }
 4343                        }
 4344                    }
 4345                }
 4346                this.autoclose_regions.insert(
 4347                    i,
 4348                    AutocloseRegion {
 4349                        selection_id,
 4350                        range: start..end,
 4351                        pair,
 4352                    },
 4353                );
 4354            }
 4355
 4356            let had_active_edit_prediction = this.has_active_edit_prediction();
 4357            this.change_selections(
 4358                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4359                window,
 4360                cx,
 4361                |s| s.select(new_selections),
 4362            );
 4363
 4364            if !bracket_inserted
 4365                && let Some(on_type_format_task) =
 4366                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4367            {
 4368                on_type_format_task.detach_and_log_err(cx);
 4369            }
 4370
 4371            let editor_settings = EditorSettings::get_global(cx);
 4372            if bracket_inserted
 4373                && (editor_settings.auto_signature_help
 4374                    || editor_settings.show_signature_help_after_edits)
 4375            {
 4376                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4377            }
 4378
 4379            let trigger_in_words =
 4380                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4381            if this.hard_wrap.is_some() {
 4382                let latest: Range<Point> = this.selections.newest(cx).range();
 4383                if latest.is_empty()
 4384                    && this
 4385                        .buffer()
 4386                        .read(cx)
 4387                        .snapshot(cx)
 4388                        .line_len(MultiBufferRow(latest.start.row))
 4389                        == latest.start.column
 4390                {
 4391                    this.rewrap_impl(
 4392                        RewrapOptions {
 4393                            override_language_settings: true,
 4394                            preserve_existing_whitespace: true,
 4395                        },
 4396                        cx,
 4397                    )
 4398                }
 4399            }
 4400            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4401            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4402            this.refresh_edit_prediction(true, false, window, cx);
 4403            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4404        });
 4405    }
 4406
 4407    fn find_possible_emoji_shortcode_at_position(
 4408        snapshot: &MultiBufferSnapshot,
 4409        position: Point,
 4410    ) -> Option<String> {
 4411        let mut chars = Vec::new();
 4412        let mut found_colon = false;
 4413        for char in snapshot.reversed_chars_at(position).take(100) {
 4414            // Found a possible emoji shortcode in the middle of the buffer
 4415            if found_colon {
 4416                if char.is_whitespace() {
 4417                    chars.reverse();
 4418                    return Some(chars.iter().collect());
 4419                }
 4420                // If the previous character is not a whitespace, we are in the middle of a word
 4421                // and we only want to complete the shortcode if the word is made up of other emojis
 4422                let mut containing_word = String::new();
 4423                for ch in snapshot
 4424                    .reversed_chars_at(position)
 4425                    .skip(chars.len() + 1)
 4426                    .take(100)
 4427                {
 4428                    if ch.is_whitespace() {
 4429                        break;
 4430                    }
 4431                    containing_word.push(ch);
 4432                }
 4433                let containing_word = containing_word.chars().rev().collect::<String>();
 4434                if util::word_consists_of_emojis(containing_word.as_str()) {
 4435                    chars.reverse();
 4436                    return Some(chars.iter().collect());
 4437                }
 4438            }
 4439
 4440            if char.is_whitespace() || !char.is_ascii() {
 4441                return None;
 4442            }
 4443            if char == ':' {
 4444                found_colon = true;
 4445            } else {
 4446                chars.push(char);
 4447            }
 4448        }
 4449        // Found a possible emoji shortcode at the beginning of the buffer
 4450        chars.reverse();
 4451        Some(chars.iter().collect())
 4452    }
 4453
 4454    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4456        self.transact(window, cx, |this, window, cx| {
 4457            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4458                let selections = this.selections.all::<usize>(cx);
 4459                let multi_buffer = this.buffer.read(cx);
 4460                let buffer = multi_buffer.snapshot(cx);
 4461                selections
 4462                    .iter()
 4463                    .map(|selection| {
 4464                        let start_point = selection.start.to_point(&buffer);
 4465                        let mut existing_indent =
 4466                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4467                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4468                        let start = selection.start;
 4469                        let end = selection.end;
 4470                        let selection_is_empty = start == end;
 4471                        let language_scope = buffer.language_scope_at(start);
 4472                        let (
 4473                            comment_delimiter,
 4474                            doc_delimiter,
 4475                            insert_extra_newline,
 4476                            indent_on_newline,
 4477                            indent_on_extra_newline,
 4478                        ) = if let Some(language) = &language_scope {
 4479                            let mut insert_extra_newline =
 4480                                insert_extra_newline_brackets(&buffer, start..end, language)
 4481                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4482
 4483                            // Comment extension on newline is allowed only for cursor selections
 4484                            let comment_delimiter = maybe!({
 4485                                if !selection_is_empty {
 4486                                    return None;
 4487                                }
 4488
 4489                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4490                                    return None;
 4491                                }
 4492
 4493                                let delimiters = language.line_comment_prefixes();
 4494                                let max_len_of_delimiter =
 4495                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4496                                let (snapshot, range) =
 4497                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4498
 4499                                let num_of_whitespaces = snapshot
 4500                                    .chars_for_range(range.clone())
 4501                                    .take_while(|c| c.is_whitespace())
 4502                                    .count();
 4503                                let comment_candidate = snapshot
 4504                                    .chars_for_range(range.clone())
 4505                                    .skip(num_of_whitespaces)
 4506                                    .take(max_len_of_delimiter)
 4507                                    .collect::<String>();
 4508                                let (delimiter, trimmed_len) = delimiters
 4509                                    .iter()
 4510                                    .filter_map(|delimiter| {
 4511                                        let prefix = delimiter.trim_end();
 4512                                        if comment_candidate.starts_with(prefix) {
 4513                                            Some((delimiter, prefix.len()))
 4514                                        } else {
 4515                                            None
 4516                                        }
 4517                                    })
 4518                                    .max_by_key(|(_, len)| *len)?;
 4519
 4520                                if let Some(BlockCommentConfig {
 4521                                    start: block_start, ..
 4522                                }) = language.block_comment()
 4523                                {
 4524                                    let block_start_trimmed = block_start.trim_end();
 4525                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4526                                        let line_content = snapshot
 4527                                            .chars_for_range(range)
 4528                                            .skip(num_of_whitespaces)
 4529                                            .take(block_start_trimmed.len())
 4530                                            .collect::<String>();
 4531
 4532                                        if line_content.starts_with(block_start_trimmed) {
 4533                                            return None;
 4534                                        }
 4535                                    }
 4536                                }
 4537
 4538                                let cursor_is_placed_after_comment_marker =
 4539                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4540                                if cursor_is_placed_after_comment_marker {
 4541                                    Some(delimiter.clone())
 4542                                } else {
 4543                                    None
 4544                                }
 4545                            });
 4546
 4547                            let mut indent_on_newline = IndentSize::spaces(0);
 4548                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4549
 4550                            let doc_delimiter = maybe!({
 4551                                if !selection_is_empty {
 4552                                    return None;
 4553                                }
 4554
 4555                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4556                                    return None;
 4557                                }
 4558
 4559                                let BlockCommentConfig {
 4560                                    start: start_tag,
 4561                                    end: end_tag,
 4562                                    prefix: delimiter,
 4563                                    tab_size: len,
 4564                                } = language.documentation_comment()?;
 4565                                let is_within_block_comment = buffer
 4566                                    .language_scope_at(start_point)
 4567                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4568                                if !is_within_block_comment {
 4569                                    return None;
 4570                                }
 4571
 4572                                let (snapshot, range) =
 4573                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4574
 4575                                let num_of_whitespaces = snapshot
 4576                                    .chars_for_range(range.clone())
 4577                                    .take_while(|c| c.is_whitespace())
 4578                                    .count();
 4579
 4580                                // 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.
 4581                                let column = start_point.column;
 4582                                let cursor_is_after_start_tag = {
 4583                                    let start_tag_len = start_tag.len();
 4584                                    let start_tag_line = snapshot
 4585                                        .chars_for_range(range.clone())
 4586                                        .skip(num_of_whitespaces)
 4587                                        .take(start_tag_len)
 4588                                        .collect::<String>();
 4589                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4590                                        num_of_whitespaces + start_tag_len <= column as usize
 4591                                    } else {
 4592                                        false
 4593                                    }
 4594                                };
 4595
 4596                                let cursor_is_after_delimiter = {
 4597                                    let delimiter_trim = delimiter.trim_end();
 4598                                    let delimiter_line = snapshot
 4599                                        .chars_for_range(range.clone())
 4600                                        .skip(num_of_whitespaces)
 4601                                        .take(delimiter_trim.len())
 4602                                        .collect::<String>();
 4603                                    if delimiter_line.starts_with(delimiter_trim) {
 4604                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4605                                    } else {
 4606                                        false
 4607                                    }
 4608                                };
 4609
 4610                                let cursor_is_before_end_tag_if_exists = {
 4611                                    let mut char_position = 0u32;
 4612                                    let mut end_tag_offset = None;
 4613
 4614                                    'outer: for chunk in snapshot.text_for_range(range) {
 4615                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4616                                            let chars_before_match =
 4617                                                chunk[..byte_pos].chars().count() as u32;
 4618                                            end_tag_offset =
 4619                                                Some(char_position + chars_before_match);
 4620                                            break 'outer;
 4621                                        }
 4622                                        char_position += chunk.chars().count() as u32;
 4623                                    }
 4624
 4625                                    if let Some(end_tag_offset) = end_tag_offset {
 4626                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4627                                        if cursor_is_after_start_tag {
 4628                                            if cursor_is_before_end_tag {
 4629                                                insert_extra_newline = true;
 4630                                            }
 4631                                            let cursor_is_at_start_of_end_tag =
 4632                                                column == end_tag_offset;
 4633                                            if cursor_is_at_start_of_end_tag {
 4634                                                indent_on_extra_newline.len = *len;
 4635                                            }
 4636                                        }
 4637                                        cursor_is_before_end_tag
 4638                                    } else {
 4639                                        true
 4640                                    }
 4641                                };
 4642
 4643                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4644                                    && cursor_is_before_end_tag_if_exists
 4645                                {
 4646                                    if cursor_is_after_start_tag {
 4647                                        indent_on_newline.len = *len;
 4648                                    }
 4649                                    Some(delimiter.clone())
 4650                                } else {
 4651                                    None
 4652                                }
 4653                            });
 4654
 4655                            (
 4656                                comment_delimiter,
 4657                                doc_delimiter,
 4658                                insert_extra_newline,
 4659                                indent_on_newline,
 4660                                indent_on_extra_newline,
 4661                            )
 4662                        } else {
 4663                            (
 4664                                None,
 4665                                None,
 4666                                false,
 4667                                IndentSize::default(),
 4668                                IndentSize::default(),
 4669                            )
 4670                        };
 4671
 4672                        let prevent_auto_indent = doc_delimiter.is_some();
 4673                        let delimiter = comment_delimiter.or(doc_delimiter);
 4674
 4675                        let capacity_for_delimiter =
 4676                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4677                        let mut new_text = String::with_capacity(
 4678                            1 + capacity_for_delimiter
 4679                                + existing_indent.len as usize
 4680                                + indent_on_newline.len as usize
 4681                                + indent_on_extra_newline.len as usize,
 4682                        );
 4683                        new_text.push('\n');
 4684                        new_text.extend(existing_indent.chars());
 4685                        new_text.extend(indent_on_newline.chars());
 4686
 4687                        if let Some(delimiter) = &delimiter {
 4688                            new_text.push_str(delimiter);
 4689                        }
 4690
 4691                        if insert_extra_newline {
 4692                            new_text.push('\n');
 4693                            new_text.extend(existing_indent.chars());
 4694                            new_text.extend(indent_on_extra_newline.chars());
 4695                        }
 4696
 4697                        let anchor = buffer.anchor_after(end);
 4698                        let new_selection = selection.map(|_| anchor);
 4699                        (
 4700                            ((start..end, new_text), prevent_auto_indent),
 4701                            (insert_extra_newline, new_selection),
 4702                        )
 4703                    })
 4704                    .unzip()
 4705            };
 4706
 4707            let mut auto_indent_edits = Vec::new();
 4708            let mut edits = Vec::new();
 4709            for (edit, prevent_auto_indent) in edits_with_flags {
 4710                if prevent_auto_indent {
 4711                    edits.push(edit);
 4712                } else {
 4713                    auto_indent_edits.push(edit);
 4714                }
 4715            }
 4716            if !edits.is_empty() {
 4717                this.edit(edits, cx);
 4718            }
 4719            if !auto_indent_edits.is_empty() {
 4720                this.edit_with_autoindent(auto_indent_edits, cx);
 4721            }
 4722
 4723            let buffer = this.buffer.read(cx).snapshot(cx);
 4724            let new_selections = selection_info
 4725                .into_iter()
 4726                .map(|(extra_newline_inserted, new_selection)| {
 4727                    let mut cursor = new_selection.end.to_point(&buffer);
 4728                    if extra_newline_inserted {
 4729                        cursor.row -= 1;
 4730                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4731                    }
 4732                    new_selection.map(|_| cursor)
 4733                })
 4734                .collect();
 4735
 4736            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4737            this.refresh_edit_prediction(true, false, window, cx);
 4738        });
 4739    }
 4740
 4741    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4743
 4744        let buffer = self.buffer.read(cx);
 4745        let snapshot = buffer.snapshot(cx);
 4746
 4747        let mut edits = Vec::new();
 4748        let mut rows = Vec::new();
 4749
 4750        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4751            let cursor = selection.head();
 4752            let row = cursor.row;
 4753
 4754            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4755
 4756            let newline = "\n".to_string();
 4757            edits.push((start_of_line..start_of_line, newline));
 4758
 4759            rows.push(row + rows_inserted as u32);
 4760        }
 4761
 4762        self.transact(window, cx, |editor, window, cx| {
 4763            editor.edit(edits, cx);
 4764
 4765            editor.change_selections(Default::default(), window, cx, |s| {
 4766                let mut index = 0;
 4767                s.move_cursors_with(|map, _, _| {
 4768                    let row = rows[index];
 4769                    index += 1;
 4770
 4771                    let point = Point::new(row, 0);
 4772                    let boundary = map.next_line_boundary(point).1;
 4773                    let clipped = map.clip_point(boundary, Bias::Left);
 4774
 4775                    (clipped, SelectionGoal::None)
 4776                });
 4777            });
 4778
 4779            let mut indent_edits = Vec::new();
 4780            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4781            for row in rows {
 4782                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4783                for (row, indent) in indents {
 4784                    if indent.len == 0 {
 4785                        continue;
 4786                    }
 4787
 4788                    let text = match indent.kind {
 4789                        IndentKind::Space => " ".repeat(indent.len as usize),
 4790                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4791                    };
 4792                    let point = Point::new(row.0, 0);
 4793                    indent_edits.push((point..point, text));
 4794                }
 4795            }
 4796            editor.edit(indent_edits, cx);
 4797        });
 4798    }
 4799
 4800    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4802
 4803        let buffer = self.buffer.read(cx);
 4804        let snapshot = buffer.snapshot(cx);
 4805
 4806        let mut edits = Vec::new();
 4807        let mut rows = Vec::new();
 4808        let mut rows_inserted = 0;
 4809
 4810        for selection in self.selections.all_adjusted(cx) {
 4811            let cursor = selection.head();
 4812            let row = cursor.row;
 4813
 4814            let point = Point::new(row + 1, 0);
 4815            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4816
 4817            let newline = "\n".to_string();
 4818            edits.push((start_of_line..start_of_line, newline));
 4819
 4820            rows_inserted += 1;
 4821            rows.push(row + rows_inserted);
 4822        }
 4823
 4824        self.transact(window, cx, |editor, window, cx| {
 4825            editor.edit(edits, cx);
 4826
 4827            editor.change_selections(Default::default(), window, cx, |s| {
 4828                let mut index = 0;
 4829                s.move_cursors_with(|map, _, _| {
 4830                    let row = rows[index];
 4831                    index += 1;
 4832
 4833                    let point = Point::new(row, 0);
 4834                    let boundary = map.next_line_boundary(point).1;
 4835                    let clipped = map.clip_point(boundary, Bias::Left);
 4836
 4837                    (clipped, SelectionGoal::None)
 4838                });
 4839            });
 4840
 4841            let mut indent_edits = Vec::new();
 4842            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4843            for row in rows {
 4844                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4845                for (row, indent) in indents {
 4846                    if indent.len == 0 {
 4847                        continue;
 4848                    }
 4849
 4850                    let text = match indent.kind {
 4851                        IndentKind::Space => " ".repeat(indent.len as usize),
 4852                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4853                    };
 4854                    let point = Point::new(row.0, 0);
 4855                    indent_edits.push((point..point, text));
 4856                }
 4857            }
 4858            editor.edit(indent_edits, cx);
 4859        });
 4860    }
 4861
 4862    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4863        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4864            original_indent_columns: Vec::new(),
 4865        });
 4866        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4867    }
 4868
 4869    fn insert_with_autoindent_mode(
 4870        &mut self,
 4871        text: &str,
 4872        autoindent_mode: Option<AutoindentMode>,
 4873        window: &mut Window,
 4874        cx: &mut Context<Self>,
 4875    ) {
 4876        if self.read_only(cx) {
 4877            return;
 4878        }
 4879
 4880        let text: Arc<str> = text.into();
 4881        self.transact(window, cx, |this, window, cx| {
 4882            let old_selections = this.selections.all_adjusted(cx);
 4883            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4884                let anchors = {
 4885                    let snapshot = buffer.read(cx);
 4886                    old_selections
 4887                        .iter()
 4888                        .map(|s| {
 4889                            let anchor = snapshot.anchor_after(s.head());
 4890                            s.map(|_| anchor)
 4891                        })
 4892                        .collect::<Vec<_>>()
 4893                };
 4894                buffer.edit(
 4895                    old_selections
 4896                        .iter()
 4897                        .map(|s| (s.start..s.end, text.clone())),
 4898                    autoindent_mode,
 4899                    cx,
 4900                );
 4901                anchors
 4902            });
 4903
 4904            this.change_selections(Default::default(), window, cx, |s| {
 4905                s.select_anchors(selection_anchors);
 4906            });
 4907
 4908            cx.notify();
 4909        });
 4910    }
 4911
 4912    fn trigger_completion_on_input(
 4913        &mut self,
 4914        text: &str,
 4915        trigger_in_words: bool,
 4916        window: &mut Window,
 4917        cx: &mut Context<Self>,
 4918    ) {
 4919        let completions_source = self
 4920            .context_menu
 4921            .borrow()
 4922            .as_ref()
 4923            .and_then(|menu| match menu {
 4924                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4925                CodeContextMenu::CodeActions(_) => None,
 4926            });
 4927
 4928        match completions_source {
 4929            Some(CompletionsMenuSource::Words { .. }) => {
 4930                self.open_or_update_completions_menu(
 4931                    Some(CompletionsMenuSource::Words {
 4932                        ignore_threshold: false,
 4933                    }),
 4934                    None,
 4935                    window,
 4936                    cx,
 4937                );
 4938            }
 4939            Some(CompletionsMenuSource::Normal)
 4940            | Some(CompletionsMenuSource::SnippetChoices)
 4941            | None
 4942                if self.is_completion_trigger(
 4943                    text,
 4944                    trigger_in_words,
 4945                    completions_source.is_some(),
 4946                    cx,
 4947                ) =>
 4948            {
 4949                self.show_completions(
 4950                    &ShowCompletions {
 4951                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4952                    },
 4953                    window,
 4954                    cx,
 4955                )
 4956            }
 4957            _ => {
 4958                self.hide_context_menu(window, cx);
 4959            }
 4960        }
 4961    }
 4962
 4963    fn is_completion_trigger(
 4964        &self,
 4965        text: &str,
 4966        trigger_in_words: bool,
 4967        menu_is_open: bool,
 4968        cx: &mut Context<Self>,
 4969    ) -> bool {
 4970        let position = self.selections.newest_anchor().head();
 4971        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4972            return false;
 4973        };
 4974
 4975        if let Some(completion_provider) = &self.completion_provider {
 4976            completion_provider.is_completion_trigger(
 4977                &buffer,
 4978                position.text_anchor,
 4979                text,
 4980                trigger_in_words,
 4981                menu_is_open,
 4982                cx,
 4983            )
 4984        } else {
 4985            false
 4986        }
 4987    }
 4988
 4989    /// If any empty selections is touching the start of its innermost containing autoclose
 4990    /// region, expand it to select the brackets.
 4991    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4992        let selections = self.selections.all::<usize>(cx);
 4993        let buffer = self.buffer.read(cx).read(cx);
 4994        let new_selections = self
 4995            .selections_with_autoclose_regions(selections, &buffer)
 4996            .map(|(mut selection, region)| {
 4997                if !selection.is_empty() {
 4998                    return selection;
 4999                }
 5000
 5001                if let Some(region) = region {
 5002                    let mut range = region.range.to_offset(&buffer);
 5003                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5004                        range.start -= region.pair.start.len();
 5005                        if buffer.contains_str_at(range.start, &region.pair.start)
 5006                            && buffer.contains_str_at(range.end, &region.pair.end)
 5007                        {
 5008                            range.end += region.pair.end.len();
 5009                            selection.start = range.start;
 5010                            selection.end = range.end;
 5011
 5012                            return selection;
 5013                        }
 5014                    }
 5015                }
 5016
 5017                let always_treat_brackets_as_autoclosed = buffer
 5018                    .language_settings_at(selection.start, cx)
 5019                    .always_treat_brackets_as_autoclosed;
 5020
 5021                if !always_treat_brackets_as_autoclosed {
 5022                    return selection;
 5023                }
 5024
 5025                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5026                    for (pair, enabled) in scope.brackets() {
 5027                        if !enabled || !pair.close {
 5028                            continue;
 5029                        }
 5030
 5031                        if buffer.contains_str_at(selection.start, &pair.end) {
 5032                            let pair_start_len = pair.start.len();
 5033                            if buffer.contains_str_at(
 5034                                selection.start.saturating_sub(pair_start_len),
 5035                                &pair.start,
 5036                            ) {
 5037                                selection.start -= pair_start_len;
 5038                                selection.end += pair.end.len();
 5039
 5040                                return selection;
 5041                            }
 5042                        }
 5043                    }
 5044                }
 5045
 5046                selection
 5047            })
 5048            .collect();
 5049
 5050        drop(buffer);
 5051        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5052            selections.select(new_selections)
 5053        });
 5054    }
 5055
 5056    /// Iterate the given selections, and for each one, find the smallest surrounding
 5057    /// autoclose region. This uses the ordering of the selections and the autoclose
 5058    /// regions to avoid repeated comparisons.
 5059    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5060        &'a self,
 5061        selections: impl IntoIterator<Item = Selection<D>>,
 5062        buffer: &'a MultiBufferSnapshot,
 5063    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5064        let mut i = 0;
 5065        let mut regions = self.autoclose_regions.as_slice();
 5066        selections.into_iter().map(move |selection| {
 5067            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5068
 5069            let mut enclosing = None;
 5070            while let Some(pair_state) = regions.get(i) {
 5071                if pair_state.range.end.to_offset(buffer) < range.start {
 5072                    regions = &regions[i + 1..];
 5073                    i = 0;
 5074                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5075                    break;
 5076                } else {
 5077                    if pair_state.selection_id == selection.id {
 5078                        enclosing = Some(pair_state);
 5079                    }
 5080                    i += 1;
 5081                }
 5082            }
 5083
 5084            (selection, enclosing)
 5085        })
 5086    }
 5087
 5088    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5089    fn invalidate_autoclose_regions(
 5090        &mut self,
 5091        mut selections: &[Selection<Anchor>],
 5092        buffer: &MultiBufferSnapshot,
 5093    ) {
 5094        self.autoclose_regions.retain(|state| {
 5095            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5096                return false;
 5097            }
 5098
 5099            let mut i = 0;
 5100            while let Some(selection) = selections.get(i) {
 5101                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5102                    selections = &selections[1..];
 5103                    continue;
 5104                }
 5105                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5106                    break;
 5107                }
 5108                if selection.id == state.selection_id {
 5109                    return true;
 5110                } else {
 5111                    i += 1;
 5112                }
 5113            }
 5114            false
 5115        });
 5116    }
 5117
 5118    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5119        let offset = position.to_offset(buffer);
 5120        let (word_range, kind) =
 5121            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5122        if offset > word_range.start && kind == Some(CharKind::Word) {
 5123            Some(
 5124                buffer
 5125                    .text_for_range(word_range.start..offset)
 5126                    .collect::<String>(),
 5127            )
 5128        } else {
 5129            None
 5130        }
 5131    }
 5132
 5133    pub fn toggle_inline_values(
 5134        &mut self,
 5135        _: &ToggleInlineValues,
 5136        _: &mut Window,
 5137        cx: &mut Context<Self>,
 5138    ) {
 5139        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5140
 5141        self.refresh_inline_values(cx);
 5142    }
 5143
 5144    pub fn toggle_inlay_hints(
 5145        &mut self,
 5146        _: &ToggleInlayHints,
 5147        _: &mut Window,
 5148        cx: &mut Context<Self>,
 5149    ) {
 5150        self.refresh_inlay_hints(
 5151            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5152            cx,
 5153        );
 5154    }
 5155
 5156    pub fn inlay_hints_enabled(&self) -> bool {
 5157        self.inlay_hint_cache.enabled
 5158    }
 5159
 5160    pub fn inline_values_enabled(&self) -> bool {
 5161        self.inline_value_cache.enabled
 5162    }
 5163
 5164    #[cfg(any(test, feature = "test-support"))]
 5165    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5166        self.display_map
 5167            .read(cx)
 5168            .current_inlays()
 5169            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5170            .cloned()
 5171            .collect()
 5172    }
 5173
 5174    #[cfg(any(test, feature = "test-support"))]
 5175    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .cloned()
 5180            .collect()
 5181    }
 5182
 5183    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5184        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5185            return;
 5186        }
 5187
 5188        let reason_description = reason.description();
 5189        let ignore_debounce = matches!(
 5190            reason,
 5191            InlayHintRefreshReason::SettingsChange(_)
 5192                | InlayHintRefreshReason::Toggle(_)
 5193                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5194                | InlayHintRefreshReason::ModifiersChanged(_)
 5195        );
 5196        let (invalidate_cache, required_languages) = match reason {
 5197            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5198                match self.inlay_hint_cache.modifiers_override(enabled) {
 5199                    Some(enabled) => {
 5200                        if enabled {
 5201                            (InvalidationStrategy::RefreshRequested, None)
 5202                        } else {
 5203                            self.splice_inlays(
 5204                                &self
 5205                                    .visible_inlay_hints(cx)
 5206                                    .iter()
 5207                                    .map(|inlay| inlay.id)
 5208                                    .collect::<Vec<InlayId>>(),
 5209                                Vec::new(),
 5210                                cx,
 5211                            );
 5212                            return;
 5213                        }
 5214                    }
 5215                    None => return,
 5216                }
 5217            }
 5218            InlayHintRefreshReason::Toggle(enabled) => {
 5219                if self.inlay_hint_cache.toggle(enabled) {
 5220                    if enabled {
 5221                        (InvalidationStrategy::RefreshRequested, None)
 5222                    } else {
 5223                        self.splice_inlays(
 5224                            &self
 5225                                .visible_inlay_hints(cx)
 5226                                .iter()
 5227                                .map(|inlay| inlay.id)
 5228                                .collect::<Vec<InlayId>>(),
 5229                            Vec::new(),
 5230                            cx,
 5231                        );
 5232                        return;
 5233                    }
 5234                } else {
 5235                    return;
 5236                }
 5237            }
 5238            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5239                match self.inlay_hint_cache.update_settings(
 5240                    &self.buffer,
 5241                    new_settings,
 5242                    self.visible_inlay_hints(cx),
 5243                    cx,
 5244                ) {
 5245                    ControlFlow::Break(Some(InlaySplice {
 5246                        to_remove,
 5247                        to_insert,
 5248                    })) => {
 5249                        self.splice_inlays(&to_remove, to_insert, cx);
 5250                        return;
 5251                    }
 5252                    ControlFlow::Break(None) => return,
 5253                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5254                }
 5255            }
 5256            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5257                if let Some(InlaySplice {
 5258                    to_remove,
 5259                    to_insert,
 5260                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5261                {
 5262                    self.splice_inlays(&to_remove, to_insert, cx);
 5263                }
 5264                self.display_map.update(cx, |display_map, _| {
 5265                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5266                });
 5267                return;
 5268            }
 5269            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5270            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5271                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5272            }
 5273            InlayHintRefreshReason::RefreshRequested => {
 5274                (InvalidationStrategy::RefreshRequested, None)
 5275            }
 5276        };
 5277
 5278        if let Some(InlaySplice {
 5279            to_remove,
 5280            to_insert,
 5281        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5282            reason_description,
 5283            self.visible_excerpts(required_languages.as_ref(), cx),
 5284            invalidate_cache,
 5285            ignore_debounce,
 5286            cx,
 5287        ) {
 5288            self.splice_inlays(&to_remove, to_insert, cx);
 5289        }
 5290    }
 5291
 5292    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5293        self.display_map
 5294            .read(cx)
 5295            .current_inlays()
 5296            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5297            .cloned()
 5298            .collect()
 5299    }
 5300
 5301    pub fn visible_excerpts(
 5302        &self,
 5303        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5304        cx: &mut Context<Editor>,
 5305    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5306        let Some(project) = self.project() else {
 5307            return HashMap::default();
 5308        };
 5309        let project = project.read(cx);
 5310        let multi_buffer = self.buffer().read(cx);
 5311        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5312        let multi_buffer_visible_start = self
 5313            .scroll_manager
 5314            .anchor()
 5315            .anchor
 5316            .to_point(&multi_buffer_snapshot);
 5317        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5318            multi_buffer_visible_start
 5319                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5320            Bias::Left,
 5321        );
 5322        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5323        multi_buffer_snapshot
 5324            .range_to_buffer_ranges(multi_buffer_visible_range)
 5325            .into_iter()
 5326            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5327            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5328                let buffer_file = project::File::from_dyn(buffer.file())?;
 5329                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5330                let worktree_entry = buffer_worktree
 5331                    .read(cx)
 5332                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5333                if worktree_entry.is_ignored {
 5334                    return None;
 5335                }
 5336
 5337                let language = buffer.language()?;
 5338                if let Some(restrict_to_languages) = restrict_to_languages
 5339                    && !restrict_to_languages.contains(language)
 5340                {
 5341                    return None;
 5342                }
 5343                Some((
 5344                    excerpt_id,
 5345                    (
 5346                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5347                        buffer.version().clone(),
 5348                        excerpt_visible_range,
 5349                    ),
 5350                ))
 5351            })
 5352            .collect()
 5353    }
 5354
 5355    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5356        TextLayoutDetails {
 5357            text_system: window.text_system().clone(),
 5358            editor_style: self.style.clone().unwrap(),
 5359            rem_size: window.rem_size(),
 5360            scroll_anchor: self.scroll_manager.anchor(),
 5361            visible_rows: self.visible_line_count(),
 5362            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5363        }
 5364    }
 5365
 5366    pub fn splice_inlays(
 5367        &self,
 5368        to_remove: &[InlayId],
 5369        to_insert: Vec<Inlay>,
 5370        cx: &mut Context<Self>,
 5371    ) {
 5372        self.display_map.update(cx, |display_map, cx| {
 5373            display_map.splice_inlays(to_remove, to_insert, cx)
 5374        });
 5375        cx.notify();
 5376    }
 5377
 5378    fn trigger_on_type_formatting(
 5379        &self,
 5380        input: String,
 5381        window: &mut Window,
 5382        cx: &mut Context<Self>,
 5383    ) -> Option<Task<Result<()>>> {
 5384        if input.len() != 1 {
 5385            return None;
 5386        }
 5387
 5388        let project = self.project()?;
 5389        let position = self.selections.newest_anchor().head();
 5390        let (buffer, buffer_position) = self
 5391            .buffer
 5392            .read(cx)
 5393            .text_anchor_for_position(position, cx)?;
 5394
 5395        let settings = language_settings::language_settings(
 5396            buffer
 5397                .read(cx)
 5398                .language_at(buffer_position)
 5399                .map(|l| l.name()),
 5400            buffer.read(cx).file(),
 5401            cx,
 5402        );
 5403        if !settings.use_on_type_format {
 5404            return None;
 5405        }
 5406
 5407        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5408        // hence we do LSP request & edit on host side only — add formats to host's history.
 5409        let push_to_lsp_host_history = true;
 5410        // If this is not the host, append its history with new edits.
 5411        let push_to_client_history = project.read(cx).is_via_collab();
 5412
 5413        let on_type_formatting = project.update(cx, |project, cx| {
 5414            project.on_type_format(
 5415                buffer.clone(),
 5416                buffer_position,
 5417                input,
 5418                push_to_lsp_host_history,
 5419                cx,
 5420            )
 5421        });
 5422        Some(cx.spawn_in(window, async move |editor, cx| {
 5423            if let Some(transaction) = on_type_formatting.await? {
 5424                if push_to_client_history {
 5425                    buffer
 5426                        .update(cx, |buffer, _| {
 5427                            buffer.push_transaction(transaction, Instant::now());
 5428                            buffer.finalize_last_transaction();
 5429                        })
 5430                        .ok();
 5431                }
 5432                editor.update(cx, |editor, cx| {
 5433                    editor.refresh_document_highlights(cx);
 5434                })?;
 5435            }
 5436            Ok(())
 5437        }))
 5438    }
 5439
 5440    pub fn show_word_completions(
 5441        &mut self,
 5442        _: &ShowWordCompletions,
 5443        window: &mut Window,
 5444        cx: &mut Context<Self>,
 5445    ) {
 5446        self.open_or_update_completions_menu(
 5447            Some(CompletionsMenuSource::Words {
 5448                ignore_threshold: true,
 5449            }),
 5450            None,
 5451            window,
 5452            cx,
 5453        );
 5454    }
 5455
 5456    pub fn show_completions(
 5457        &mut self,
 5458        options: &ShowCompletions,
 5459        window: &mut Window,
 5460        cx: &mut Context<Self>,
 5461    ) {
 5462        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5463    }
 5464
 5465    fn open_or_update_completions_menu(
 5466        &mut self,
 5467        requested_source: Option<CompletionsMenuSource>,
 5468        trigger: Option<&str>,
 5469        window: &mut Window,
 5470        cx: &mut Context<Self>,
 5471    ) {
 5472        if self.pending_rename.is_some() {
 5473            return;
 5474        }
 5475
 5476        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5477
 5478        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5479        // inserted and selected. To handle that case, the start of the selection is used so that
 5480        // the menu starts with all choices.
 5481        let position = self
 5482            .selections
 5483            .newest_anchor()
 5484            .start
 5485            .bias_right(&multibuffer_snapshot);
 5486        if position.diff_base_anchor.is_some() {
 5487            return;
 5488        }
 5489        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5490        let Some(buffer) = buffer_position
 5491            .buffer_id
 5492            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5493        else {
 5494            return;
 5495        };
 5496        let buffer_snapshot = buffer.read(cx).snapshot();
 5497
 5498        let query: Option<Arc<String>> =
 5499            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5500                .map(|query| query.into());
 5501
 5502        drop(multibuffer_snapshot);
 5503
 5504        // Hide the current completions menu when query is empty. Without this, cached
 5505        // completions from before the trigger char may be reused (#32774).
 5506        if query.is_none() {
 5507            let menu_is_open = matches!(
 5508                self.context_menu.borrow().as_ref(),
 5509                Some(CodeContextMenu::Completions(_))
 5510            );
 5511            if menu_is_open {
 5512                self.hide_context_menu(window, cx);
 5513            }
 5514        }
 5515
 5516        let mut ignore_word_threshold = false;
 5517        let provider = match requested_source {
 5518            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5519            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5520                ignore_word_threshold = ignore_threshold;
 5521                None
 5522            }
 5523            Some(CompletionsMenuSource::SnippetChoices) => {
 5524                log::error!("bug: SnippetChoices requested_source is not handled");
 5525                None
 5526            }
 5527        };
 5528
 5529        let sort_completions = provider
 5530            .as_ref()
 5531            .is_some_and(|provider| provider.sort_completions());
 5532
 5533        let filter_completions = provider
 5534            .as_ref()
 5535            .is_none_or(|provider| provider.filter_completions());
 5536
 5537        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5538            if filter_completions {
 5539                menu.filter(query.clone(), provider.clone(), window, cx);
 5540            }
 5541            // When `is_incomplete` is false, no need to re-query completions when the current query
 5542            // is a suffix of the initial query.
 5543            if !menu.is_incomplete {
 5544                // If the new query is a suffix of the old query (typing more characters) and
 5545                // the previous result was complete, the existing completions can be filtered.
 5546                //
 5547                // Note that this is always true for snippet completions.
 5548                let query_matches = match (&menu.initial_query, &query) {
 5549                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5550                    (None, _) => true,
 5551                    _ => false,
 5552                };
 5553                if query_matches {
 5554                    let position_matches = if menu.initial_position == position {
 5555                        true
 5556                    } else {
 5557                        let snapshot = self.buffer.read(cx).read(cx);
 5558                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5559                    };
 5560                    if position_matches {
 5561                        return;
 5562                    }
 5563                }
 5564            }
 5565        };
 5566
 5567        let trigger_kind = match trigger {
 5568            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5569                CompletionTriggerKind::TRIGGER_CHARACTER
 5570            }
 5571            _ => CompletionTriggerKind::INVOKED,
 5572        };
 5573        let completion_context = CompletionContext {
 5574            trigger_character: trigger.and_then(|trigger| {
 5575                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5576                    Some(String::from(trigger))
 5577                } else {
 5578                    None
 5579                }
 5580            }),
 5581            trigger_kind,
 5582        };
 5583
 5584        let Anchor {
 5585            excerpt_id: buffer_excerpt_id,
 5586            text_anchor: buffer_position,
 5587            ..
 5588        } = buffer_position;
 5589
 5590        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5591            buffer_snapshot.surrounding_word(buffer_position, None)
 5592        {
 5593            let word_to_exclude = buffer_snapshot
 5594                .text_for_range(word_range.clone())
 5595                .collect::<String>();
 5596            (
 5597                buffer_snapshot.anchor_before(word_range.start)
 5598                    ..buffer_snapshot.anchor_after(buffer_position),
 5599                Some(word_to_exclude),
 5600            )
 5601        } else {
 5602            (buffer_position..buffer_position, None)
 5603        };
 5604
 5605        let language = buffer_snapshot
 5606            .language_at(buffer_position)
 5607            .map(|language| language.name());
 5608
 5609        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5610            .completions
 5611            .clone();
 5612
 5613        let show_completion_documentation = buffer_snapshot
 5614            .settings_at(buffer_position, cx)
 5615            .show_completion_documentation;
 5616
 5617        // The document can be large, so stay in reasonable bounds when searching for words,
 5618        // otherwise completion pop-up might be slow to appear.
 5619        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5620        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5621        let min_word_search = buffer_snapshot.clip_point(
 5622            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5623            Bias::Left,
 5624        );
 5625        let max_word_search = buffer_snapshot.clip_point(
 5626            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5627            Bias::Right,
 5628        );
 5629        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5630            ..buffer_snapshot.point_to_offset(max_word_search);
 5631
 5632        let skip_digits = query
 5633            .as_ref()
 5634            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5635
 5636        let omit_word_completions = !self.word_completions_enabled
 5637            || (!ignore_word_threshold
 5638                && match &query {
 5639                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5640                    None => completion_settings.words_min_length != 0,
 5641                });
 5642
 5643        let (mut words, provider_responses) = match &provider {
 5644            Some(provider) => {
 5645                let provider_responses = provider.completions(
 5646                    buffer_excerpt_id,
 5647                    &buffer,
 5648                    buffer_position,
 5649                    completion_context,
 5650                    window,
 5651                    cx,
 5652                );
 5653
 5654                let words = match (omit_word_completions, completion_settings.words) {
 5655                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5656                        Task::ready(BTreeMap::default())
 5657                    }
 5658                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5659                        .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
 5668                (words, provider_responses)
 5669            }
 5670            None => {
 5671                let words = if omit_word_completions {
 5672                    Task::ready(BTreeMap::default())
 5673                } else {
 5674                    cx.background_spawn(async move {
 5675                        buffer_snapshot.words_in_range(WordsQuery {
 5676                            fuzzy_contents: None,
 5677                            range: word_search_range,
 5678                            skip_digits,
 5679                        })
 5680                    })
 5681                };
 5682                (words, Task::ready(Ok(Vec::new())))
 5683            }
 5684        };
 5685
 5686        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5687
 5688        let id = post_inc(&mut self.next_completion_id);
 5689        let task = cx.spawn_in(window, async move |editor, cx| {
 5690            let Ok(()) = editor.update(cx, |this, _| {
 5691                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5692            }) else {
 5693                return;
 5694            };
 5695
 5696            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5697            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5698            let mut completions = Vec::new();
 5699            let mut is_incomplete = false;
 5700            let mut display_options: Option<CompletionDisplayOptions> = None;
 5701            if let Some(provider_responses) = provider_responses.await.log_err()
 5702                && !provider_responses.is_empty()
 5703            {
 5704                for response in provider_responses {
 5705                    completions.extend(response.completions);
 5706                    is_incomplete = is_incomplete || response.is_incomplete;
 5707                    match display_options.as_mut() {
 5708                        None => {
 5709                            display_options = Some(response.display_options);
 5710                        }
 5711                        Some(options) => options.merge(&response.display_options),
 5712                    }
 5713                }
 5714                if completion_settings.words == WordsCompletionMode::Fallback {
 5715                    words = Task::ready(BTreeMap::default());
 5716                }
 5717            }
 5718            let display_options = display_options.unwrap_or_default();
 5719
 5720            let mut words = words.await;
 5721            if let Some(word_to_exclude) = &word_to_exclude {
 5722                words.remove(word_to_exclude);
 5723            }
 5724            for lsp_completion in &completions {
 5725                words.remove(&lsp_completion.new_text);
 5726            }
 5727            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5728                replace_range: word_replace_range.clone(),
 5729                new_text: word.clone(),
 5730                label: CodeLabel::plain(word, None),
 5731                icon_path: None,
 5732                documentation: None,
 5733                source: CompletionSource::BufferWord {
 5734                    word_range,
 5735                    resolved: false,
 5736                },
 5737                insert_text_mode: Some(InsertTextMode::AS_IS),
 5738                confirm: None,
 5739            }));
 5740
 5741            let menu = if completions.is_empty() {
 5742                None
 5743            } else {
 5744                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5745                    let languages = editor
 5746                        .workspace
 5747                        .as_ref()
 5748                        .and_then(|(workspace, _)| workspace.upgrade())
 5749                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5750                    let menu = CompletionsMenu::new(
 5751                        id,
 5752                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5753                        sort_completions,
 5754                        show_completion_documentation,
 5755                        position,
 5756                        query.clone(),
 5757                        is_incomplete,
 5758                        buffer.clone(),
 5759                        completions.into(),
 5760                        display_options,
 5761                        snippet_sort_order,
 5762                        languages,
 5763                        language,
 5764                        cx,
 5765                    );
 5766
 5767                    let query = if filter_completions { query } else { None };
 5768                    let matches_task = if let Some(query) = query {
 5769                        menu.do_async_filtering(query, cx)
 5770                    } else {
 5771                        Task::ready(menu.unfiltered_matches())
 5772                    };
 5773                    (menu, matches_task)
 5774                }) else {
 5775                    return;
 5776                };
 5777
 5778                let matches = matches_task.await;
 5779
 5780                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5781                    // Newer menu already set, so exit.
 5782                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5783                        editor.context_menu.borrow().as_ref()
 5784                        && prev_menu.id > id
 5785                    {
 5786                        return;
 5787                    };
 5788
 5789                    // Only valid to take prev_menu because it the new menu is immediately set
 5790                    // below, or the menu is hidden.
 5791                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5792                        editor.context_menu.borrow_mut().take()
 5793                    {
 5794                        let position_matches =
 5795                            if prev_menu.initial_position == menu.initial_position {
 5796                                true
 5797                            } else {
 5798                                let snapshot = editor.buffer.read(cx).read(cx);
 5799                                prev_menu.initial_position.to_offset(&snapshot)
 5800                                    == menu.initial_position.to_offset(&snapshot)
 5801                            };
 5802                        if position_matches {
 5803                            // Preserve markdown cache before `set_filter_results` because it will
 5804                            // try to populate the documentation cache.
 5805                            menu.preserve_markdown_cache(prev_menu);
 5806                        }
 5807                    };
 5808
 5809                    menu.set_filter_results(matches, provider, window, cx);
 5810                }) else {
 5811                    return;
 5812                };
 5813
 5814                menu.visible().then_some(menu)
 5815            };
 5816
 5817            editor
 5818                .update_in(cx, |editor, window, cx| {
 5819                    if editor.focus_handle.is_focused(window)
 5820                        && let Some(menu) = menu
 5821                    {
 5822                        *editor.context_menu.borrow_mut() =
 5823                            Some(CodeContextMenu::Completions(menu));
 5824
 5825                        crate::hover_popover::hide_hover(editor, cx);
 5826                        if editor.show_edit_predictions_in_menu() {
 5827                            editor.update_visible_edit_prediction(window, cx);
 5828                        } else {
 5829                            editor.discard_edit_prediction(false, cx);
 5830                        }
 5831
 5832                        cx.notify();
 5833                        return;
 5834                    }
 5835
 5836                    if editor.completion_tasks.len() <= 1 {
 5837                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5838                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5839                        // If it was already hidden and we don't show edit predictions in the menu,
 5840                        // we should also show the edit prediction when available.
 5841                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5842                            editor.update_visible_edit_prediction(window, cx);
 5843                        }
 5844                    }
 5845                })
 5846                .ok();
 5847        });
 5848
 5849        self.completion_tasks.push((id, task));
 5850    }
 5851
 5852    #[cfg(feature = "test-support")]
 5853    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5854        let menu = self.context_menu.borrow();
 5855        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5856            let completions = menu.completions.borrow();
 5857            Some(completions.to_vec())
 5858        } else {
 5859            None
 5860        }
 5861    }
 5862
 5863    pub fn with_completions_menu_matching_id<R>(
 5864        &self,
 5865        id: CompletionId,
 5866        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5867    ) -> R {
 5868        let mut context_menu = self.context_menu.borrow_mut();
 5869        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5870            return f(None);
 5871        };
 5872        if completions_menu.id != id {
 5873            return f(None);
 5874        }
 5875        f(Some(completions_menu))
 5876    }
 5877
 5878    pub fn confirm_completion(
 5879        &mut self,
 5880        action: &ConfirmCompletion,
 5881        window: &mut Window,
 5882        cx: &mut Context<Self>,
 5883    ) -> Option<Task<Result<()>>> {
 5884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5885        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5886    }
 5887
 5888    pub fn confirm_completion_insert(
 5889        &mut self,
 5890        _: &ConfirmCompletionInsert,
 5891        window: &mut Window,
 5892        cx: &mut Context<Self>,
 5893    ) -> Option<Task<Result<()>>> {
 5894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5895        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5896    }
 5897
 5898    pub fn confirm_completion_replace(
 5899        &mut self,
 5900        _: &ConfirmCompletionReplace,
 5901        window: &mut Window,
 5902        cx: &mut Context<Self>,
 5903    ) -> Option<Task<Result<()>>> {
 5904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5905        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5906    }
 5907
 5908    pub fn compose_completion(
 5909        &mut self,
 5910        action: &ComposeCompletion,
 5911        window: &mut Window,
 5912        cx: &mut Context<Self>,
 5913    ) -> Option<Task<Result<()>>> {
 5914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5915        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5916    }
 5917
 5918    fn do_completion(
 5919        &mut self,
 5920        item_ix: Option<usize>,
 5921        intent: CompletionIntent,
 5922        window: &mut Window,
 5923        cx: &mut Context<Editor>,
 5924    ) -> Option<Task<Result<()>>> {
 5925        use language::ToOffset as _;
 5926
 5927        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5928        else {
 5929            return None;
 5930        };
 5931
 5932        let candidate_id = {
 5933            let entries = completions_menu.entries.borrow();
 5934            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5935            if self.show_edit_predictions_in_menu() {
 5936                self.discard_edit_prediction(true, cx);
 5937            }
 5938            mat.candidate_id
 5939        };
 5940
 5941        let completion = completions_menu
 5942            .completions
 5943            .borrow()
 5944            .get(candidate_id)?
 5945            .clone();
 5946        cx.stop_propagation();
 5947
 5948        let buffer_handle = completions_menu.buffer.clone();
 5949
 5950        let CompletionEdit {
 5951            new_text,
 5952            snippet,
 5953            replace_range,
 5954        } = process_completion_for_edit(
 5955            &completion,
 5956            intent,
 5957            &buffer_handle,
 5958            &completions_menu.initial_position.text_anchor,
 5959            cx,
 5960        );
 5961
 5962        let buffer = buffer_handle.read(cx);
 5963        let snapshot = self.buffer.read(cx).snapshot(cx);
 5964        let newest_anchor = self.selections.newest_anchor();
 5965        let replace_range_multibuffer = {
 5966            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5967            let multibuffer_anchor = snapshot
 5968                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5969                .unwrap()
 5970                ..snapshot
 5971                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5972                    .unwrap();
 5973            multibuffer_anchor.start.to_offset(&snapshot)
 5974                ..multibuffer_anchor.end.to_offset(&snapshot)
 5975        };
 5976        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5977            return None;
 5978        }
 5979
 5980        let old_text = buffer
 5981            .text_for_range(replace_range.clone())
 5982            .collect::<String>();
 5983        let lookbehind = newest_anchor
 5984            .start
 5985            .text_anchor
 5986            .to_offset(buffer)
 5987            .saturating_sub(replace_range.start);
 5988        let lookahead = replace_range
 5989            .end
 5990            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5991        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5992        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5993
 5994        let selections = self.selections.all::<usize>(cx);
 5995        let mut ranges = Vec::new();
 5996        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5997
 5998        for selection in &selections {
 5999            let range = if selection.id == newest_anchor.id {
 6000                replace_range_multibuffer.clone()
 6001            } else {
 6002                let mut range = selection.range();
 6003
 6004                // if prefix is present, don't duplicate it
 6005                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6006                    range.start = range.start.saturating_sub(lookbehind);
 6007
 6008                    // if suffix is also present, mimic the newest cursor and replace it
 6009                    if selection.id != newest_anchor.id
 6010                        && snapshot.contains_str_at(range.end, suffix)
 6011                    {
 6012                        range.end += lookahead;
 6013                    }
 6014                }
 6015                range
 6016            };
 6017
 6018            ranges.push(range.clone());
 6019
 6020            if !self.linked_edit_ranges.is_empty() {
 6021                let start_anchor = snapshot.anchor_before(range.start);
 6022                let end_anchor = snapshot.anchor_after(range.end);
 6023                if let Some(ranges) = self
 6024                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6025                {
 6026                    for (buffer, edits) in ranges {
 6027                        linked_edits
 6028                            .entry(buffer.clone())
 6029                            .or_default()
 6030                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6031                    }
 6032                }
 6033            }
 6034        }
 6035
 6036        let common_prefix_len = old_text
 6037            .chars()
 6038            .zip(new_text.chars())
 6039            .take_while(|(a, b)| a == b)
 6040            .map(|(a, _)| a.len_utf8())
 6041            .sum::<usize>();
 6042
 6043        cx.emit(EditorEvent::InputHandled {
 6044            utf16_range_to_replace: None,
 6045            text: new_text[common_prefix_len..].into(),
 6046        });
 6047
 6048        self.transact(window, cx, |editor, window, cx| {
 6049            if let Some(mut snippet) = snippet {
 6050                snippet.text = new_text.to_string();
 6051                editor
 6052                    .insert_snippet(&ranges, snippet, window, cx)
 6053                    .log_err();
 6054            } else {
 6055                editor.buffer.update(cx, |multi_buffer, cx| {
 6056                    let auto_indent = match completion.insert_text_mode {
 6057                        Some(InsertTextMode::AS_IS) => None,
 6058                        _ => editor.autoindent_mode.clone(),
 6059                    };
 6060                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6061                    multi_buffer.edit(edits, auto_indent, cx);
 6062                });
 6063            }
 6064            for (buffer, edits) in linked_edits {
 6065                buffer.update(cx, |buffer, cx| {
 6066                    let snapshot = buffer.snapshot();
 6067                    let edits = edits
 6068                        .into_iter()
 6069                        .map(|(range, text)| {
 6070                            use text::ToPoint as TP;
 6071                            let end_point = TP::to_point(&range.end, &snapshot);
 6072                            let start_point = TP::to_point(&range.start, &snapshot);
 6073                            (start_point..end_point, text)
 6074                        })
 6075                        .sorted_by_key(|(range, _)| range.start);
 6076                    buffer.edit(edits, None, cx);
 6077                })
 6078            }
 6079
 6080            editor.refresh_edit_prediction(true, false, window, cx);
 6081        });
 6082        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6083
 6084        let show_new_completions_on_confirm = completion
 6085            .confirm
 6086            .as_ref()
 6087            .is_some_and(|confirm| confirm(intent, window, cx));
 6088        if show_new_completions_on_confirm {
 6089            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6090        }
 6091
 6092        let provider = self.completion_provider.as_ref()?;
 6093        drop(completion);
 6094        let apply_edits = provider.apply_additional_edits_for_completion(
 6095            buffer_handle,
 6096            completions_menu.completions.clone(),
 6097            candidate_id,
 6098            true,
 6099            cx,
 6100        );
 6101
 6102        let editor_settings = EditorSettings::get_global(cx);
 6103        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6104            // After the code completion is finished, users often want to know what signatures are needed.
 6105            // so we should automatically call signature_help
 6106            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6107        }
 6108
 6109        Some(cx.foreground_executor().spawn(async move {
 6110            apply_edits.await?;
 6111            Ok(())
 6112        }))
 6113    }
 6114
 6115    pub fn toggle_code_actions(
 6116        &mut self,
 6117        action: &ToggleCodeActions,
 6118        window: &mut Window,
 6119        cx: &mut Context<Self>,
 6120    ) {
 6121        let quick_launch = action.quick_launch;
 6122        let mut context_menu = self.context_menu.borrow_mut();
 6123        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6124            if code_actions.deployed_from == action.deployed_from {
 6125                // Toggle if we're selecting the same one
 6126                *context_menu = None;
 6127                cx.notify();
 6128                return;
 6129            } else {
 6130                // Otherwise, clear it and start a new one
 6131                *context_menu = None;
 6132                cx.notify();
 6133            }
 6134        }
 6135        drop(context_menu);
 6136        let snapshot = self.snapshot(window, cx);
 6137        let deployed_from = action.deployed_from.clone();
 6138        let action = action.clone();
 6139        self.completion_tasks.clear();
 6140        self.discard_edit_prediction(false, cx);
 6141
 6142        let multibuffer_point = match &action.deployed_from {
 6143            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6144                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6145            }
 6146            _ => self.selections.newest::<Point>(cx).head(),
 6147        };
 6148        let Some((buffer, buffer_row)) = snapshot
 6149            .buffer_snapshot
 6150            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6151            .and_then(|(buffer_snapshot, range)| {
 6152                self.buffer()
 6153                    .read(cx)
 6154                    .buffer(buffer_snapshot.remote_id())
 6155                    .map(|buffer| (buffer, range.start.row))
 6156            })
 6157        else {
 6158            return;
 6159        };
 6160        let buffer_id = buffer.read(cx).remote_id();
 6161        let tasks = self
 6162            .tasks
 6163            .get(&(buffer_id, buffer_row))
 6164            .map(|t| Arc::new(t.to_owned()));
 6165
 6166        if !self.focus_handle.is_focused(window) {
 6167            return;
 6168        }
 6169        let project = self.project.clone();
 6170
 6171        let code_actions_task = match deployed_from {
 6172            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6173            _ => self.code_actions(buffer_row, window, cx),
 6174        };
 6175
 6176        let runnable_task = match deployed_from {
 6177            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6178            _ => {
 6179                let mut task_context_task = Task::ready(None);
 6180                if let Some(tasks) = &tasks
 6181                    && let Some(project) = project
 6182                {
 6183                    task_context_task =
 6184                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6185                }
 6186
 6187                cx.spawn_in(window, {
 6188                    let buffer = buffer.clone();
 6189                    async move |editor, cx| {
 6190                        let task_context = task_context_task.await;
 6191
 6192                        let resolved_tasks =
 6193                            tasks
 6194                                .zip(task_context.clone())
 6195                                .map(|(tasks, task_context)| ResolvedTasks {
 6196                                    templates: tasks.resolve(&task_context).collect(),
 6197                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6198                                        multibuffer_point.row,
 6199                                        tasks.column,
 6200                                    )),
 6201                                });
 6202                        let debug_scenarios = editor
 6203                            .update(cx, |editor, cx| {
 6204                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6205                            })?
 6206                            .await;
 6207                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6208                    }
 6209                })
 6210            }
 6211        };
 6212
 6213        cx.spawn_in(window, async move |editor, cx| {
 6214            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6215            let code_actions = code_actions_task.await;
 6216            let spawn_straight_away = quick_launch
 6217                && resolved_tasks
 6218                    .as_ref()
 6219                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6220                && code_actions
 6221                    .as_ref()
 6222                    .is_none_or(|actions| actions.is_empty())
 6223                && debug_scenarios.is_empty();
 6224
 6225            editor.update_in(cx, |editor, window, cx| {
 6226                crate::hover_popover::hide_hover(editor, cx);
 6227                let actions = CodeActionContents::new(
 6228                    resolved_tasks,
 6229                    code_actions,
 6230                    debug_scenarios,
 6231                    task_context.unwrap_or_default(),
 6232                );
 6233
 6234                // Don't show the menu if there are no actions available
 6235                if actions.is_empty() {
 6236                    cx.notify();
 6237                    return Task::ready(Ok(()));
 6238                }
 6239
 6240                *editor.context_menu.borrow_mut() =
 6241                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6242                        buffer,
 6243                        actions,
 6244                        selected_item: Default::default(),
 6245                        scroll_handle: UniformListScrollHandle::default(),
 6246                        deployed_from,
 6247                    }));
 6248                cx.notify();
 6249                if spawn_straight_away
 6250                    && let Some(task) = editor.confirm_code_action(
 6251                        &ConfirmCodeAction { item_ix: Some(0) },
 6252                        window,
 6253                        cx,
 6254                    )
 6255                {
 6256                    return task;
 6257                }
 6258
 6259                Task::ready(Ok(()))
 6260            })
 6261        })
 6262        .detach_and_log_err(cx);
 6263    }
 6264
 6265    fn debug_scenarios(
 6266        &mut self,
 6267        resolved_tasks: &Option<ResolvedTasks>,
 6268        buffer: &Entity<Buffer>,
 6269        cx: &mut App,
 6270    ) -> Task<Vec<task::DebugScenario>> {
 6271        maybe!({
 6272            let project = self.project()?;
 6273            let dap_store = project.read(cx).dap_store();
 6274            let mut scenarios = vec![];
 6275            let resolved_tasks = resolved_tasks.as_ref()?;
 6276            let buffer = buffer.read(cx);
 6277            let language = buffer.language()?;
 6278            let file = buffer.file();
 6279            let debug_adapter = language_settings(language.name().into(), file, cx)
 6280                .debuggers
 6281                .first()
 6282                .map(SharedString::from)
 6283                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6284
 6285            dap_store.update(cx, |dap_store, cx| {
 6286                for (_, task) in &resolved_tasks.templates {
 6287                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6288                        task.original_task().clone(),
 6289                        debug_adapter.clone().into(),
 6290                        task.display_label().to_owned().into(),
 6291                        cx,
 6292                    );
 6293                    scenarios.push(maybe_scenario);
 6294                }
 6295            });
 6296            Some(cx.background_spawn(async move {
 6297                futures::future::join_all(scenarios)
 6298                    .await
 6299                    .into_iter()
 6300                    .flatten()
 6301                    .collect::<Vec<_>>()
 6302            }))
 6303        })
 6304        .unwrap_or_else(|| Task::ready(vec![]))
 6305    }
 6306
 6307    fn code_actions(
 6308        &mut self,
 6309        buffer_row: u32,
 6310        window: &mut Window,
 6311        cx: &mut Context<Self>,
 6312    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6313        let mut task = self.code_actions_task.take();
 6314        cx.spawn_in(window, async move |editor, cx| {
 6315            while let Some(prev_task) = task {
 6316                prev_task.await.log_err();
 6317                task = editor
 6318                    .update(cx, |this, _| this.code_actions_task.take())
 6319                    .ok()?;
 6320            }
 6321
 6322            editor
 6323                .update(cx, |editor, cx| {
 6324                    editor
 6325                        .available_code_actions
 6326                        .clone()
 6327                        .and_then(|(location, code_actions)| {
 6328                            let snapshot = location.buffer.read(cx).snapshot();
 6329                            let point_range = location.range.to_point(&snapshot);
 6330                            let point_range = point_range.start.row..=point_range.end.row;
 6331                            if point_range.contains(&buffer_row) {
 6332                                Some(code_actions)
 6333                            } else {
 6334                                None
 6335                            }
 6336                        })
 6337                })
 6338                .ok()
 6339                .flatten()
 6340        })
 6341    }
 6342
 6343    pub fn confirm_code_action(
 6344        &mut self,
 6345        action: &ConfirmCodeAction,
 6346        window: &mut Window,
 6347        cx: &mut Context<Self>,
 6348    ) -> Option<Task<Result<()>>> {
 6349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6350
 6351        let actions_menu =
 6352            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6353                menu
 6354            } else {
 6355                return None;
 6356            };
 6357
 6358        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6359        let action = actions_menu.actions.get(action_ix)?;
 6360        let title = action.label();
 6361        let buffer = actions_menu.buffer;
 6362        let workspace = self.workspace()?;
 6363
 6364        match action {
 6365            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6366                workspace.update(cx, |workspace, cx| {
 6367                    workspace.schedule_resolved_task(
 6368                        task_source_kind,
 6369                        resolved_task,
 6370                        false,
 6371                        window,
 6372                        cx,
 6373                    );
 6374
 6375                    Some(Task::ready(Ok(())))
 6376                })
 6377            }
 6378            CodeActionsItem::CodeAction {
 6379                excerpt_id,
 6380                action,
 6381                provider,
 6382            } => {
 6383                let apply_code_action =
 6384                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6385                let workspace = workspace.downgrade();
 6386                Some(cx.spawn_in(window, async move |editor, cx| {
 6387                    let project_transaction = apply_code_action.await?;
 6388                    Self::open_project_transaction(
 6389                        &editor,
 6390                        workspace,
 6391                        project_transaction,
 6392                        title,
 6393                        cx,
 6394                    )
 6395                    .await
 6396                }))
 6397            }
 6398            CodeActionsItem::DebugScenario(scenario) => {
 6399                let context = actions_menu.actions.context;
 6400
 6401                workspace.update(cx, |workspace, cx| {
 6402                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6403                    workspace.start_debug_session(
 6404                        scenario,
 6405                        context,
 6406                        Some(buffer),
 6407                        None,
 6408                        window,
 6409                        cx,
 6410                    );
 6411                });
 6412                Some(Task::ready(Ok(())))
 6413            }
 6414        }
 6415    }
 6416
 6417    pub async fn open_project_transaction(
 6418        editor: &WeakEntity<Editor>,
 6419        workspace: WeakEntity<Workspace>,
 6420        transaction: ProjectTransaction,
 6421        title: String,
 6422        cx: &mut AsyncWindowContext,
 6423    ) -> Result<()> {
 6424        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6425        cx.update(|_, cx| {
 6426            entries.sort_unstable_by_key(|(buffer, _)| {
 6427                buffer.read(cx).file().map(|f| f.path().clone())
 6428            });
 6429        })?;
 6430
 6431        // If the project transaction's edits are all contained within this editor, then
 6432        // avoid opening a new editor to display them.
 6433
 6434        if let Some((buffer, transaction)) = entries.first() {
 6435            if entries.len() == 1 {
 6436                let excerpt = editor.update(cx, |editor, cx| {
 6437                    editor
 6438                        .buffer()
 6439                        .read(cx)
 6440                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6441                })?;
 6442                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6443                    && excerpted_buffer == *buffer
 6444                {
 6445                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6446                        let excerpt_range = excerpt_range.to_offset(buffer);
 6447                        buffer
 6448                            .edited_ranges_for_transaction::<usize>(transaction)
 6449                            .all(|range| {
 6450                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6451                            })
 6452                    })?;
 6453
 6454                    if all_edits_within_excerpt {
 6455                        return Ok(());
 6456                    }
 6457                }
 6458            }
 6459        } else {
 6460            return Ok(());
 6461        }
 6462
 6463        let mut ranges_to_highlight = Vec::new();
 6464        let excerpt_buffer = cx.new(|cx| {
 6465            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6466            for (buffer_handle, transaction) in &entries {
 6467                let edited_ranges = buffer_handle
 6468                    .read(cx)
 6469                    .edited_ranges_for_transaction::<Point>(transaction)
 6470                    .collect::<Vec<_>>();
 6471                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6472                    PathKey::for_buffer(buffer_handle, cx),
 6473                    buffer_handle.clone(),
 6474                    edited_ranges,
 6475                    multibuffer_context_lines(cx),
 6476                    cx,
 6477                );
 6478
 6479                ranges_to_highlight.extend(ranges);
 6480            }
 6481            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6482            multibuffer
 6483        })?;
 6484
 6485        workspace.update_in(cx, |workspace, window, cx| {
 6486            let project = workspace.project().clone();
 6487            let editor =
 6488                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6489            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6490            editor.update(cx, |editor, cx| {
 6491                editor.highlight_background::<Self>(
 6492                    &ranges_to_highlight,
 6493                    |theme| theme.colors().editor_highlighted_line_background,
 6494                    cx,
 6495                );
 6496            });
 6497        })?;
 6498
 6499        Ok(())
 6500    }
 6501
 6502    pub fn clear_code_action_providers(&mut self) {
 6503        self.code_action_providers.clear();
 6504        self.available_code_actions.take();
 6505    }
 6506
 6507    pub fn add_code_action_provider(
 6508        &mut self,
 6509        provider: Rc<dyn CodeActionProvider>,
 6510        window: &mut Window,
 6511        cx: &mut Context<Self>,
 6512    ) {
 6513        if self
 6514            .code_action_providers
 6515            .iter()
 6516            .any(|existing_provider| existing_provider.id() == provider.id())
 6517        {
 6518            return;
 6519        }
 6520
 6521        self.code_action_providers.push(provider);
 6522        self.refresh_code_actions(window, cx);
 6523    }
 6524
 6525    pub fn remove_code_action_provider(
 6526        &mut self,
 6527        id: Arc<str>,
 6528        window: &mut Window,
 6529        cx: &mut Context<Self>,
 6530    ) {
 6531        self.code_action_providers
 6532            .retain(|provider| provider.id() != id);
 6533        self.refresh_code_actions(window, cx);
 6534    }
 6535
 6536    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6537        !self.code_action_providers.is_empty()
 6538            && EditorSettings::get_global(cx).toolbar.code_actions
 6539    }
 6540
 6541    pub fn has_available_code_actions(&self) -> bool {
 6542        self.available_code_actions
 6543            .as_ref()
 6544            .is_some_and(|(_, actions)| !actions.is_empty())
 6545    }
 6546
 6547    fn render_inline_code_actions(
 6548        &self,
 6549        icon_size: ui::IconSize,
 6550        display_row: DisplayRow,
 6551        is_active: bool,
 6552        cx: &mut Context<Self>,
 6553    ) -> AnyElement {
 6554        let show_tooltip = !self.context_menu_visible();
 6555        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6556            .icon_size(icon_size)
 6557            .shape(ui::IconButtonShape::Square)
 6558            .icon_color(ui::Color::Hidden)
 6559            .toggle_state(is_active)
 6560            .when(show_tooltip, |this| {
 6561                this.tooltip({
 6562                    let focus_handle = self.focus_handle.clone();
 6563                    move |window, cx| {
 6564                        Tooltip::for_action_in(
 6565                            "Toggle Code Actions",
 6566                            &ToggleCodeActions {
 6567                                deployed_from: None,
 6568                                quick_launch: false,
 6569                            },
 6570                            &focus_handle,
 6571                            window,
 6572                            cx,
 6573                        )
 6574                    }
 6575                })
 6576            })
 6577            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6578                window.focus(&editor.focus_handle(cx));
 6579                editor.toggle_code_actions(
 6580                    &crate::actions::ToggleCodeActions {
 6581                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6582                            display_row,
 6583                        )),
 6584                        quick_launch: false,
 6585                    },
 6586                    window,
 6587                    cx,
 6588                );
 6589            }))
 6590            .into_any_element()
 6591    }
 6592
 6593    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6594        &self.context_menu
 6595    }
 6596
 6597    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6598        let newest_selection = self.selections.newest_anchor().clone();
 6599        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6600        let buffer = self.buffer.read(cx);
 6601        if newest_selection.head().diff_base_anchor.is_some() {
 6602            return None;
 6603        }
 6604        let (start_buffer, start) =
 6605            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6606        let (end_buffer, end) =
 6607            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6608        if start_buffer != end_buffer {
 6609            return None;
 6610        }
 6611
 6612        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6613            cx.background_executor()
 6614                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6615                .await;
 6616
 6617            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6618                let providers = this.code_action_providers.clone();
 6619                let tasks = this
 6620                    .code_action_providers
 6621                    .iter()
 6622                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6623                    .collect::<Vec<_>>();
 6624                (providers, tasks)
 6625            })?;
 6626
 6627            let mut actions = Vec::new();
 6628            for (provider, provider_actions) in
 6629                providers.into_iter().zip(future::join_all(tasks).await)
 6630            {
 6631                if let Some(provider_actions) = provider_actions.log_err() {
 6632                    actions.extend(provider_actions.into_iter().map(|action| {
 6633                        AvailableCodeAction {
 6634                            excerpt_id: newest_selection.start.excerpt_id,
 6635                            action,
 6636                            provider: provider.clone(),
 6637                        }
 6638                    }));
 6639                }
 6640            }
 6641
 6642            this.update(cx, |this, cx| {
 6643                this.available_code_actions = if actions.is_empty() {
 6644                    None
 6645                } else {
 6646                    Some((
 6647                        Location {
 6648                            buffer: start_buffer,
 6649                            range: start..end,
 6650                        },
 6651                        actions.into(),
 6652                    ))
 6653                };
 6654                cx.notify();
 6655            })
 6656        }));
 6657        None
 6658    }
 6659
 6660    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6661        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6662            self.show_git_blame_inline = false;
 6663
 6664            self.show_git_blame_inline_delay_task =
 6665                Some(cx.spawn_in(window, async move |this, cx| {
 6666                    cx.background_executor().timer(delay).await;
 6667
 6668                    this.update(cx, |this, cx| {
 6669                        this.show_git_blame_inline = true;
 6670                        cx.notify();
 6671                    })
 6672                    .log_err();
 6673                }));
 6674        }
 6675    }
 6676
 6677    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6678        let snapshot = self.snapshot(window, cx);
 6679        let cursor = self.selections.newest::<Point>(cx).head();
 6680        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6681        else {
 6682            return;
 6683        };
 6684
 6685        let Some(blame) = self.blame.as_ref() else {
 6686            return;
 6687        };
 6688
 6689        let row_info = RowInfo {
 6690            buffer_id: Some(buffer.remote_id()),
 6691            buffer_row: Some(point.row),
 6692            ..Default::default()
 6693        };
 6694        let Some((buffer, blame_entry)) = blame
 6695            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6696            .flatten()
 6697        else {
 6698            return;
 6699        };
 6700
 6701        let anchor = self.selections.newest_anchor().head();
 6702        let position = self.to_pixel_point(anchor, &snapshot, window);
 6703        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6704            self.show_blame_popover(
 6705                buffer,
 6706                &blame_entry,
 6707                position + last_bounds.origin,
 6708                true,
 6709                cx,
 6710            );
 6711        };
 6712    }
 6713
 6714    fn show_blame_popover(
 6715        &mut self,
 6716        buffer: BufferId,
 6717        blame_entry: &BlameEntry,
 6718        position: gpui::Point<Pixels>,
 6719        ignore_timeout: bool,
 6720        cx: &mut Context<Self>,
 6721    ) {
 6722        if let Some(state) = &mut self.inline_blame_popover {
 6723            state.hide_task.take();
 6724        } else {
 6725            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6726            let blame_entry = blame_entry.clone();
 6727            let show_task = cx.spawn(async move |editor, cx| {
 6728                if !ignore_timeout {
 6729                    cx.background_executor()
 6730                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6731                        .await;
 6732                }
 6733                editor
 6734                    .update(cx, |editor, cx| {
 6735                        editor.inline_blame_popover_show_task.take();
 6736                        let Some(blame) = editor.blame.as_ref() else {
 6737                            return;
 6738                        };
 6739                        let blame = blame.read(cx);
 6740                        let details = blame.details_for_entry(buffer, &blame_entry);
 6741                        let markdown = cx.new(|cx| {
 6742                            Markdown::new(
 6743                                details
 6744                                    .as_ref()
 6745                                    .map(|message| message.message.clone())
 6746                                    .unwrap_or_default(),
 6747                                None,
 6748                                None,
 6749                                cx,
 6750                            )
 6751                        });
 6752                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6753                            position,
 6754                            hide_task: None,
 6755                            popover_bounds: None,
 6756                            popover_state: InlineBlamePopoverState {
 6757                                scroll_handle: ScrollHandle::new(),
 6758                                commit_message: details,
 6759                                markdown,
 6760                            },
 6761                            keyboard_grace: ignore_timeout,
 6762                        });
 6763                        cx.notify();
 6764                    })
 6765                    .ok();
 6766            });
 6767            self.inline_blame_popover_show_task = Some(show_task);
 6768        }
 6769    }
 6770
 6771    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6772        self.inline_blame_popover_show_task.take();
 6773        if let Some(state) = &mut self.inline_blame_popover {
 6774            let hide_task = cx.spawn(async move |editor, cx| {
 6775                cx.background_executor()
 6776                    .timer(std::time::Duration::from_millis(100))
 6777                    .await;
 6778                editor
 6779                    .update(cx, |editor, cx| {
 6780                        editor.inline_blame_popover.take();
 6781                        cx.notify();
 6782                    })
 6783                    .ok();
 6784            });
 6785            state.hide_task = Some(hide_task);
 6786        }
 6787    }
 6788
 6789    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6790        if self.pending_rename.is_some() {
 6791            return None;
 6792        }
 6793
 6794        let provider = self.semantics_provider.clone()?;
 6795        let buffer = self.buffer.read(cx);
 6796        let newest_selection = self.selections.newest_anchor().clone();
 6797        let cursor_position = newest_selection.head();
 6798        let (cursor_buffer, cursor_buffer_position) =
 6799            buffer.text_anchor_for_position(cursor_position, cx)?;
 6800        let (tail_buffer, tail_buffer_position) =
 6801            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6802        if cursor_buffer != tail_buffer {
 6803            return None;
 6804        }
 6805
 6806        let snapshot = cursor_buffer.read(cx).snapshot();
 6807        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6808        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6809        if start_word_range != end_word_range {
 6810            self.document_highlights_task.take();
 6811            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6812            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6813            return None;
 6814        }
 6815
 6816        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6817        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6818            cx.background_executor()
 6819                .timer(Duration::from_millis(debounce))
 6820                .await;
 6821
 6822            let highlights = if let Some(highlights) = cx
 6823                .update(|cx| {
 6824                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6825                })
 6826                .ok()
 6827                .flatten()
 6828            {
 6829                highlights.await.log_err()
 6830            } else {
 6831                None
 6832            };
 6833
 6834            if let Some(highlights) = highlights {
 6835                this.update(cx, |this, cx| {
 6836                    if this.pending_rename.is_some() {
 6837                        return;
 6838                    }
 6839
 6840                    let buffer = this.buffer.read(cx);
 6841                    if buffer
 6842                        .text_anchor_for_position(cursor_position, cx)
 6843                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6844                    {
 6845                        return;
 6846                    }
 6847
 6848                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6849                    let mut write_ranges = Vec::new();
 6850                    let mut read_ranges = Vec::new();
 6851                    for highlight in highlights {
 6852                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6853                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6854                        {
 6855                            let start = highlight
 6856                                .range
 6857                                .start
 6858                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6859                            let end = highlight
 6860                                .range
 6861                                .end
 6862                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6863                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6864                                continue;
 6865                            }
 6866
 6867                            let range = Anchor {
 6868                                buffer_id: Some(buffer_id),
 6869                                excerpt_id,
 6870                                text_anchor: start,
 6871                                diff_base_anchor: None,
 6872                            }..Anchor {
 6873                                buffer_id: Some(buffer_id),
 6874                                excerpt_id,
 6875                                text_anchor: end,
 6876                                diff_base_anchor: None,
 6877                            };
 6878                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6879                                write_ranges.push(range);
 6880                            } else {
 6881                                read_ranges.push(range);
 6882                            }
 6883                        }
 6884                    }
 6885
 6886                    this.highlight_background::<DocumentHighlightRead>(
 6887                        &read_ranges,
 6888                        |theme| theme.colors().editor_document_highlight_read_background,
 6889                        cx,
 6890                    );
 6891                    this.highlight_background::<DocumentHighlightWrite>(
 6892                        &write_ranges,
 6893                        |theme| theme.colors().editor_document_highlight_write_background,
 6894                        cx,
 6895                    );
 6896                    cx.notify();
 6897                })
 6898                .log_err();
 6899            }
 6900        }));
 6901        None
 6902    }
 6903
 6904    fn prepare_highlight_query_from_selection(
 6905        &mut self,
 6906        cx: &mut Context<Editor>,
 6907    ) -> Option<(String, Range<Anchor>)> {
 6908        if matches!(self.mode, EditorMode::SingleLine) {
 6909            return None;
 6910        }
 6911        if !EditorSettings::get_global(cx).selection_highlight {
 6912            return None;
 6913        }
 6914        if self.selections.count() != 1 || self.selections.line_mode() {
 6915            return None;
 6916        }
 6917        let selection = self.selections.newest::<Point>(cx);
 6918        if selection.is_empty() || selection.start.row != selection.end.row {
 6919            return None;
 6920        }
 6921        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6922        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6923        let query = multi_buffer_snapshot
 6924            .text_for_range(selection_anchor_range.clone())
 6925            .collect::<String>();
 6926        if query.trim().is_empty() {
 6927            return None;
 6928        }
 6929        Some((query, selection_anchor_range))
 6930    }
 6931
 6932    fn update_selection_occurrence_highlights(
 6933        &mut self,
 6934        query_text: String,
 6935        query_range: Range<Anchor>,
 6936        multi_buffer_range_to_query: Range<Point>,
 6937        use_debounce: bool,
 6938        window: &mut Window,
 6939        cx: &mut Context<Editor>,
 6940    ) -> Task<()> {
 6941        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6942        cx.spawn_in(window, async move |editor, cx| {
 6943            if use_debounce {
 6944                cx.background_executor()
 6945                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6946                    .await;
 6947            }
 6948            let match_task = cx.background_spawn(async move {
 6949                let buffer_ranges = multi_buffer_snapshot
 6950                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6951                    .into_iter()
 6952                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6953                let mut match_ranges = Vec::new();
 6954                let Ok(regex) = project::search::SearchQuery::text(
 6955                    query_text.clone(),
 6956                    false,
 6957                    false,
 6958                    false,
 6959                    Default::default(),
 6960                    Default::default(),
 6961                    false,
 6962                    None,
 6963                ) else {
 6964                    return Vec::default();
 6965                };
 6966                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6967                    match_ranges.extend(
 6968                        regex
 6969                            .search(buffer_snapshot, Some(search_range.clone()))
 6970                            .await
 6971                            .into_iter()
 6972                            .filter_map(|match_range| {
 6973                                let match_start = buffer_snapshot
 6974                                    .anchor_after(search_range.start + match_range.start);
 6975                                let match_end = buffer_snapshot
 6976                                    .anchor_before(search_range.start + match_range.end);
 6977                                let match_anchor_range = Anchor::range_in_buffer(
 6978                                    excerpt_id,
 6979                                    buffer_snapshot.remote_id(),
 6980                                    match_start..match_end,
 6981                                );
 6982                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6983                            }),
 6984                    );
 6985                }
 6986                match_ranges
 6987            });
 6988            let match_ranges = match_task.await;
 6989            editor
 6990                .update_in(cx, |editor, _, cx| {
 6991                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6992                    if !match_ranges.is_empty() {
 6993                        editor.highlight_background::<SelectedTextHighlight>(
 6994                            &match_ranges,
 6995                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6996                            cx,
 6997                        )
 6998                    }
 6999                })
 7000                .log_err();
 7001        })
 7002    }
 7003
 7004    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7005        struct NewlineFold;
 7006        let type_id = std::any::TypeId::of::<NewlineFold>();
 7007        if !self.mode.is_single_line() {
 7008            return;
 7009        }
 7010        let snapshot = self.snapshot(window, cx);
 7011        if snapshot.buffer_snapshot.max_point().row == 0 {
 7012            return;
 7013        }
 7014        let task = cx.background_spawn(async move {
 7015            let new_newlines = snapshot
 7016                .buffer_chars_at(0)
 7017                .filter_map(|(c, i)| {
 7018                    if c == '\n' {
 7019                        Some(
 7020                            snapshot.buffer_snapshot.anchor_after(i)
 7021                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7022                        )
 7023                    } else {
 7024                        None
 7025                    }
 7026                })
 7027                .collect::<Vec<_>>();
 7028            let existing_newlines = snapshot
 7029                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7030                .filter_map(|fold| {
 7031                    if fold.placeholder.type_tag == Some(type_id) {
 7032                        Some(fold.range.start..fold.range.end)
 7033                    } else {
 7034                        None
 7035                    }
 7036                })
 7037                .collect::<Vec<_>>();
 7038
 7039            (new_newlines, existing_newlines)
 7040        });
 7041        self.folding_newlines = cx.spawn(async move |this, cx| {
 7042            let (new_newlines, existing_newlines) = task.await;
 7043            if new_newlines == existing_newlines {
 7044                return;
 7045            }
 7046            let placeholder = FoldPlaceholder {
 7047                render: Arc::new(move |_, _, cx| {
 7048                    div()
 7049                        .bg(cx.theme().status().hint_background)
 7050                        .border_b_1()
 7051                        .size_full()
 7052                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7053                        .border_color(cx.theme().status().hint)
 7054                        .child("\\n")
 7055                        .into_any()
 7056                }),
 7057                constrain_width: false,
 7058                merge_adjacent: false,
 7059                type_tag: Some(type_id),
 7060            };
 7061            let creases = new_newlines
 7062                .into_iter()
 7063                .map(|range| Crease::simple(range, placeholder.clone()))
 7064                .collect();
 7065            this.update(cx, |this, cx| {
 7066                this.display_map.update(cx, |display_map, cx| {
 7067                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7068                    display_map.fold(creases, cx);
 7069                });
 7070            })
 7071            .ok();
 7072        });
 7073    }
 7074
 7075    fn refresh_selected_text_highlights(
 7076        &mut self,
 7077        on_buffer_edit: bool,
 7078        window: &mut Window,
 7079        cx: &mut Context<Editor>,
 7080    ) {
 7081        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7082        else {
 7083            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7084            self.quick_selection_highlight_task.take();
 7085            self.debounced_selection_highlight_task.take();
 7086            return;
 7087        };
 7088        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7089        if on_buffer_edit
 7090            || self
 7091                .quick_selection_highlight_task
 7092                .as_ref()
 7093                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7094        {
 7095            let multi_buffer_visible_start = self
 7096                .scroll_manager
 7097                .anchor()
 7098                .anchor
 7099                .to_point(&multi_buffer_snapshot);
 7100            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7101                multi_buffer_visible_start
 7102                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7103                Bias::Left,
 7104            );
 7105            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7106            self.quick_selection_highlight_task = Some((
 7107                query_range.clone(),
 7108                self.update_selection_occurrence_highlights(
 7109                    query_text.clone(),
 7110                    query_range.clone(),
 7111                    multi_buffer_visible_range,
 7112                    false,
 7113                    window,
 7114                    cx,
 7115                ),
 7116            ));
 7117        }
 7118        if on_buffer_edit
 7119            || self
 7120                .debounced_selection_highlight_task
 7121                .as_ref()
 7122                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7123        {
 7124            let multi_buffer_start = multi_buffer_snapshot
 7125                .anchor_before(0)
 7126                .to_point(&multi_buffer_snapshot);
 7127            let multi_buffer_end = multi_buffer_snapshot
 7128                .anchor_after(multi_buffer_snapshot.len())
 7129                .to_point(&multi_buffer_snapshot);
 7130            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7131            self.debounced_selection_highlight_task = Some((
 7132                query_range.clone(),
 7133                self.update_selection_occurrence_highlights(
 7134                    query_text,
 7135                    query_range,
 7136                    multi_buffer_full_range,
 7137                    true,
 7138                    window,
 7139                    cx,
 7140                ),
 7141            ));
 7142        }
 7143    }
 7144
 7145    pub fn refresh_edit_prediction(
 7146        &mut self,
 7147        debounce: bool,
 7148        user_requested: bool,
 7149        window: &mut Window,
 7150        cx: &mut Context<Self>,
 7151    ) -> Option<()> {
 7152        if DisableAiSettings::get_global(cx).disable_ai {
 7153            return None;
 7154        }
 7155
 7156        let provider = self.edit_prediction_provider()?;
 7157        let cursor = self.selections.newest_anchor().head();
 7158        let (buffer, cursor_buffer_position) =
 7159            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7160
 7161        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7162            self.discard_edit_prediction(false, cx);
 7163            return None;
 7164        }
 7165
 7166        self.update_visible_edit_prediction(window, cx);
 7167
 7168        if !user_requested
 7169            && (!self.should_show_edit_predictions()
 7170                || !self.is_focused(window)
 7171                || buffer.read(cx).is_empty())
 7172        {
 7173            self.discard_edit_prediction(false, cx);
 7174            return None;
 7175        }
 7176
 7177        provider.refresh(
 7178            self.project.clone(),
 7179            buffer,
 7180            cursor_buffer_position,
 7181            debounce,
 7182            cx,
 7183        );
 7184        Some(())
 7185    }
 7186
 7187    fn show_edit_predictions_in_menu(&self) -> bool {
 7188        match self.edit_prediction_settings {
 7189            EditPredictionSettings::Disabled => false,
 7190            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7191        }
 7192    }
 7193
 7194    pub fn edit_predictions_enabled(&self) -> bool {
 7195        match self.edit_prediction_settings {
 7196            EditPredictionSettings::Disabled => false,
 7197            EditPredictionSettings::Enabled { .. } => true,
 7198        }
 7199    }
 7200
 7201    fn edit_prediction_requires_modifier(&self) -> bool {
 7202        match self.edit_prediction_settings {
 7203            EditPredictionSettings::Disabled => false,
 7204            EditPredictionSettings::Enabled {
 7205                preview_requires_modifier,
 7206                ..
 7207            } => preview_requires_modifier,
 7208        }
 7209    }
 7210
 7211    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7212        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7213            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7214            self.discard_edit_prediction(false, cx);
 7215        } else {
 7216            let selection = self.selections.newest_anchor();
 7217            let cursor = selection.head();
 7218
 7219            if let Some((buffer, cursor_buffer_position)) =
 7220                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7221            {
 7222                self.edit_prediction_settings =
 7223                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7224            }
 7225        }
 7226    }
 7227
 7228    fn edit_prediction_settings_at_position(
 7229        &self,
 7230        buffer: &Entity<Buffer>,
 7231        buffer_position: language::Anchor,
 7232        cx: &App,
 7233    ) -> EditPredictionSettings {
 7234        if !self.mode.is_full()
 7235            || !self.show_edit_predictions_override.unwrap_or(true)
 7236            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7237        {
 7238            return EditPredictionSettings::Disabled;
 7239        }
 7240
 7241        let buffer = buffer.read(cx);
 7242
 7243        let file = buffer.file();
 7244
 7245        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7246            return EditPredictionSettings::Disabled;
 7247        };
 7248
 7249        let by_provider = matches!(
 7250            self.menu_edit_predictions_policy,
 7251            MenuEditPredictionsPolicy::ByProvider
 7252        );
 7253
 7254        let show_in_menu = by_provider
 7255            && self
 7256                .edit_prediction_provider
 7257                .as_ref()
 7258                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7259
 7260        let preview_requires_modifier =
 7261            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7262
 7263        EditPredictionSettings::Enabled {
 7264            show_in_menu,
 7265            preview_requires_modifier,
 7266        }
 7267    }
 7268
 7269    fn should_show_edit_predictions(&self) -> bool {
 7270        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7271    }
 7272
 7273    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7274        matches!(
 7275            self.edit_prediction_preview,
 7276            EditPredictionPreview::Active { .. }
 7277        )
 7278    }
 7279
 7280    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7281        let cursor = self.selections.newest_anchor().head();
 7282        if let Some((buffer, cursor_position)) =
 7283            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7284        {
 7285            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7286        } else {
 7287            false
 7288        }
 7289    }
 7290
 7291    pub fn supports_minimap(&self, cx: &App) -> bool {
 7292        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7293    }
 7294
 7295    fn edit_predictions_enabled_in_buffer(
 7296        &self,
 7297        buffer: &Entity<Buffer>,
 7298        buffer_position: language::Anchor,
 7299        cx: &App,
 7300    ) -> bool {
 7301        maybe!({
 7302            if self.read_only(cx) {
 7303                return Some(false);
 7304            }
 7305            let provider = self.edit_prediction_provider()?;
 7306            if !provider.is_enabled(buffer, buffer_position, cx) {
 7307                return Some(false);
 7308            }
 7309            let buffer = buffer.read(cx);
 7310            let Some(file) = buffer.file() else {
 7311                return Some(true);
 7312            };
 7313            let settings = all_language_settings(Some(file), cx);
 7314            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7315        })
 7316        .unwrap_or(false)
 7317    }
 7318
 7319    fn cycle_edit_prediction(
 7320        &mut self,
 7321        direction: Direction,
 7322        window: &mut Window,
 7323        cx: &mut Context<Self>,
 7324    ) -> Option<()> {
 7325        let provider = self.edit_prediction_provider()?;
 7326        let cursor = self.selections.newest_anchor().head();
 7327        let (buffer, cursor_buffer_position) =
 7328            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7329        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7330            return None;
 7331        }
 7332
 7333        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7334        self.update_visible_edit_prediction(window, cx);
 7335
 7336        Some(())
 7337    }
 7338
 7339    pub fn show_edit_prediction(
 7340        &mut self,
 7341        _: &ShowEditPrediction,
 7342        window: &mut Window,
 7343        cx: &mut Context<Self>,
 7344    ) {
 7345        if !self.has_active_edit_prediction() {
 7346            self.refresh_edit_prediction(false, true, window, cx);
 7347            return;
 7348        }
 7349
 7350        self.update_visible_edit_prediction(window, cx);
 7351    }
 7352
 7353    pub fn display_cursor_names(
 7354        &mut self,
 7355        _: &DisplayCursorNames,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        self.show_cursor_names(window, cx);
 7360    }
 7361
 7362    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7363        self.show_cursor_names = true;
 7364        cx.notify();
 7365        cx.spawn_in(window, async move |this, cx| {
 7366            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7367            this.update(cx, |this, cx| {
 7368                this.show_cursor_names = false;
 7369                cx.notify()
 7370            })
 7371            .ok()
 7372        })
 7373        .detach();
 7374    }
 7375
 7376    pub fn next_edit_prediction(
 7377        &mut self,
 7378        _: &NextEditPrediction,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) {
 7382        if self.has_active_edit_prediction() {
 7383            self.cycle_edit_prediction(Direction::Next, window, cx);
 7384        } else {
 7385            let is_copilot_disabled = self
 7386                .refresh_edit_prediction(false, true, window, cx)
 7387                .is_none();
 7388            if is_copilot_disabled {
 7389                cx.propagate();
 7390            }
 7391        }
 7392    }
 7393
 7394    pub fn previous_edit_prediction(
 7395        &mut self,
 7396        _: &PreviousEditPrediction,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        if self.has_active_edit_prediction() {
 7401            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7402        } else {
 7403            let is_copilot_disabled = self
 7404                .refresh_edit_prediction(false, true, window, cx)
 7405                .is_none();
 7406            if is_copilot_disabled {
 7407                cx.propagate();
 7408            }
 7409        }
 7410    }
 7411
 7412    pub fn accept_edit_prediction(
 7413        &mut self,
 7414        _: &AcceptEditPrediction,
 7415        window: &mut Window,
 7416        cx: &mut Context<Self>,
 7417    ) {
 7418        if self.show_edit_predictions_in_menu() {
 7419            self.hide_context_menu(window, cx);
 7420        }
 7421
 7422        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7423            return;
 7424        };
 7425
 7426        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7427
 7428        match &active_edit_prediction.completion {
 7429            EditPrediction::Move { target, .. } => {
 7430                let target = *target;
 7431
 7432                if let Some(position_map) = &self.last_position_map {
 7433                    if position_map
 7434                        .visible_row_range
 7435                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7436                        || !self.edit_prediction_requires_modifier()
 7437                    {
 7438                        self.unfold_ranges(&[target..target], true, false, cx);
 7439                        // Note that this is also done in vim's handler of the Tab action.
 7440                        self.change_selections(
 7441                            SelectionEffects::scroll(Autoscroll::newest()),
 7442                            window,
 7443                            cx,
 7444                            |selections| {
 7445                                selections.select_anchor_ranges([target..target]);
 7446                            },
 7447                        );
 7448                        self.clear_row_highlights::<EditPredictionPreview>();
 7449
 7450                        self.edit_prediction_preview
 7451                            .set_previous_scroll_position(None);
 7452                    } else {
 7453                        self.edit_prediction_preview
 7454                            .set_previous_scroll_position(Some(
 7455                                position_map.snapshot.scroll_anchor,
 7456                            ));
 7457
 7458                        self.highlight_rows::<EditPredictionPreview>(
 7459                            target..target,
 7460                            cx.theme().colors().editor_highlighted_line_background,
 7461                            RowHighlightOptions {
 7462                                autoscroll: true,
 7463                                ..Default::default()
 7464                            },
 7465                            cx,
 7466                        );
 7467                        self.request_autoscroll(Autoscroll::fit(), cx);
 7468                    }
 7469                }
 7470            }
 7471            EditPrediction::Edit { edits, .. } => {
 7472                if let Some(provider) = self.edit_prediction_provider() {
 7473                    provider.accept(cx);
 7474                }
 7475
 7476                // Store the transaction ID and selections before applying the edit
 7477                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7478
 7479                let snapshot = self.buffer.read(cx).snapshot(cx);
 7480                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7481
 7482                self.buffer.update(cx, |buffer, cx| {
 7483                    buffer.edit(edits.iter().cloned(), None, cx)
 7484                });
 7485
 7486                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7487                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7488                });
 7489
 7490                let selections = self.selections.disjoint_anchors_arc();
 7491                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7492                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7493                    if has_new_transaction {
 7494                        self.selection_history
 7495                            .insert_transaction(transaction_id_now, selections);
 7496                    }
 7497                }
 7498
 7499                self.update_visible_edit_prediction(window, cx);
 7500                if self.active_edit_prediction.is_none() {
 7501                    self.refresh_edit_prediction(true, true, window, cx);
 7502                }
 7503
 7504                cx.notify();
 7505            }
 7506        }
 7507
 7508        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7509    }
 7510
 7511    pub fn accept_partial_edit_prediction(
 7512        &mut self,
 7513        _: &AcceptPartialEditPrediction,
 7514        window: &mut Window,
 7515        cx: &mut Context<Self>,
 7516    ) {
 7517        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7518            return;
 7519        };
 7520        if self.selections.count() != 1 {
 7521            return;
 7522        }
 7523
 7524        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7525
 7526        match &active_edit_prediction.completion {
 7527            EditPrediction::Move { target, .. } => {
 7528                let target = *target;
 7529                self.change_selections(
 7530                    SelectionEffects::scroll(Autoscroll::newest()),
 7531                    window,
 7532                    cx,
 7533                    |selections| {
 7534                        selections.select_anchor_ranges([target..target]);
 7535                    },
 7536                );
 7537            }
 7538            EditPrediction::Edit { edits, .. } => {
 7539                // Find an insertion that starts at the cursor position.
 7540                let snapshot = self.buffer.read(cx).snapshot(cx);
 7541                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7542                let insertion = edits.iter().find_map(|(range, text)| {
 7543                    let range = range.to_offset(&snapshot);
 7544                    if range.is_empty() && range.start == cursor_offset {
 7545                        Some(text)
 7546                    } else {
 7547                        None
 7548                    }
 7549                });
 7550
 7551                if let Some(text) = insertion {
 7552                    let mut partial_completion = text
 7553                        .chars()
 7554                        .by_ref()
 7555                        .take_while(|c| c.is_alphabetic())
 7556                        .collect::<String>();
 7557                    if partial_completion.is_empty() {
 7558                        partial_completion = text
 7559                            .chars()
 7560                            .by_ref()
 7561                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7562                            .collect::<String>();
 7563                    }
 7564
 7565                    cx.emit(EditorEvent::InputHandled {
 7566                        utf16_range_to_replace: None,
 7567                        text: partial_completion.clone().into(),
 7568                    });
 7569
 7570                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7571
 7572                    self.refresh_edit_prediction(true, true, window, cx);
 7573                    cx.notify();
 7574                } else {
 7575                    self.accept_edit_prediction(&Default::default(), window, cx);
 7576                }
 7577            }
 7578        }
 7579    }
 7580
 7581    fn discard_edit_prediction(
 7582        &mut self,
 7583        should_report_edit_prediction_event: bool,
 7584        cx: &mut Context<Self>,
 7585    ) -> bool {
 7586        if should_report_edit_prediction_event {
 7587            let completion_id = self
 7588                .active_edit_prediction
 7589                .as_ref()
 7590                .and_then(|active_completion| active_completion.completion_id.clone());
 7591
 7592            self.report_edit_prediction_event(completion_id, false, cx);
 7593        }
 7594
 7595        if let Some(provider) = self.edit_prediction_provider() {
 7596            provider.discard(cx);
 7597        }
 7598
 7599        self.take_active_edit_prediction(cx)
 7600    }
 7601
 7602    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7603        let Some(provider) = self.edit_prediction_provider() else {
 7604            return;
 7605        };
 7606
 7607        let Some((_, buffer, _)) = self
 7608            .buffer
 7609            .read(cx)
 7610            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7611        else {
 7612            return;
 7613        };
 7614
 7615        let extension = buffer
 7616            .read(cx)
 7617            .file()
 7618            .and_then(|file| Some(file.path().extension()?.to_string()));
 7619
 7620        let event_type = match accepted {
 7621            true => "Edit Prediction Accepted",
 7622            false => "Edit Prediction Discarded",
 7623        };
 7624        telemetry::event!(
 7625            event_type,
 7626            provider = provider.name(),
 7627            prediction_id = id,
 7628            suggestion_accepted = accepted,
 7629            file_extension = extension,
 7630        );
 7631    }
 7632
 7633    pub fn has_active_edit_prediction(&self) -> bool {
 7634        self.active_edit_prediction.is_some()
 7635    }
 7636
 7637    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7638        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7639            return false;
 7640        };
 7641
 7642        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7643        self.clear_highlights::<EditPredictionHighlight>(cx);
 7644        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7645        true
 7646    }
 7647
 7648    /// Returns true when we're displaying the edit prediction popover below the cursor
 7649    /// like we are not previewing and the LSP autocomplete menu is visible
 7650    /// or we are in `when_holding_modifier` mode.
 7651    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7652        if self.edit_prediction_preview_is_active()
 7653            || !self.show_edit_predictions_in_menu()
 7654            || !self.edit_predictions_enabled()
 7655        {
 7656            return false;
 7657        }
 7658
 7659        if self.has_visible_completions_menu() {
 7660            return true;
 7661        }
 7662
 7663        has_completion && self.edit_prediction_requires_modifier()
 7664    }
 7665
 7666    fn handle_modifiers_changed(
 7667        &mut self,
 7668        modifiers: Modifiers,
 7669        position_map: &PositionMap,
 7670        window: &mut Window,
 7671        cx: &mut Context<Self>,
 7672    ) {
 7673        if self.show_edit_predictions_in_menu() {
 7674            self.update_edit_prediction_preview(&modifiers, window, cx);
 7675        }
 7676
 7677        self.update_selection_mode(&modifiers, position_map, window, cx);
 7678
 7679        let mouse_position = window.mouse_position();
 7680        if !position_map.text_hitbox.is_hovered(window) {
 7681            return;
 7682        }
 7683
 7684        self.update_hovered_link(
 7685            position_map.point_for_position(mouse_position),
 7686            &position_map.snapshot,
 7687            modifiers,
 7688            window,
 7689            cx,
 7690        )
 7691    }
 7692
 7693    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7694        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7695        if invert {
 7696            match multi_cursor_setting {
 7697                MultiCursorModifier::Alt => modifiers.alt,
 7698                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7699            }
 7700        } else {
 7701            match multi_cursor_setting {
 7702                MultiCursorModifier::Alt => modifiers.secondary(),
 7703                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7704            }
 7705        }
 7706    }
 7707
 7708    fn columnar_selection_mode(
 7709        modifiers: &Modifiers,
 7710        cx: &mut Context<Self>,
 7711    ) -> Option<ColumnarMode> {
 7712        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7713            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7714                Some(ColumnarMode::FromMouse)
 7715            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7716                Some(ColumnarMode::FromSelection)
 7717            } else {
 7718                None
 7719            }
 7720        } else {
 7721            None
 7722        }
 7723    }
 7724
 7725    fn update_selection_mode(
 7726        &mut self,
 7727        modifiers: &Modifiers,
 7728        position_map: &PositionMap,
 7729        window: &mut Window,
 7730        cx: &mut Context<Self>,
 7731    ) {
 7732        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7733            return;
 7734        };
 7735        if self.selections.pending_anchor().is_none() {
 7736            return;
 7737        }
 7738
 7739        let mouse_position = window.mouse_position();
 7740        let point_for_position = position_map.point_for_position(mouse_position);
 7741        let position = point_for_position.previous_valid;
 7742
 7743        self.select(
 7744            SelectPhase::BeginColumnar {
 7745                position,
 7746                reset: false,
 7747                mode,
 7748                goal_column: point_for_position.exact_unclipped.column(),
 7749            },
 7750            window,
 7751            cx,
 7752        );
 7753    }
 7754
 7755    fn update_edit_prediction_preview(
 7756        &mut self,
 7757        modifiers: &Modifiers,
 7758        window: &mut Window,
 7759        cx: &mut Context<Self>,
 7760    ) {
 7761        let mut modifiers_held = false;
 7762        if let Some(accept_keystroke) = self
 7763            .accept_edit_prediction_keybind(false, window, cx)
 7764            .keystroke()
 7765        {
 7766            modifiers_held = modifiers_held
 7767                || (accept_keystroke.modifiers() == modifiers
 7768                    && accept_keystroke.modifiers().modified());
 7769        };
 7770        if let Some(accept_partial_keystroke) = self
 7771            .accept_edit_prediction_keybind(true, window, cx)
 7772            .keystroke()
 7773        {
 7774            modifiers_held = modifiers_held
 7775                || (accept_partial_keystroke.modifiers() == modifiers
 7776                    && accept_partial_keystroke.modifiers().modified());
 7777        }
 7778
 7779        if modifiers_held {
 7780            if matches!(
 7781                self.edit_prediction_preview,
 7782                EditPredictionPreview::Inactive { .. }
 7783            ) {
 7784                self.edit_prediction_preview = EditPredictionPreview::Active {
 7785                    previous_scroll_position: None,
 7786                    since: Instant::now(),
 7787                };
 7788
 7789                self.update_visible_edit_prediction(window, cx);
 7790                cx.notify();
 7791            }
 7792        } else if let EditPredictionPreview::Active {
 7793            previous_scroll_position,
 7794            since,
 7795        } = self.edit_prediction_preview
 7796        {
 7797            if let (Some(previous_scroll_position), Some(position_map)) =
 7798                (previous_scroll_position, self.last_position_map.as_ref())
 7799            {
 7800                self.set_scroll_position(
 7801                    previous_scroll_position
 7802                        .scroll_position(&position_map.snapshot.display_snapshot),
 7803                    window,
 7804                    cx,
 7805                );
 7806            }
 7807
 7808            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7809                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7810            };
 7811            self.clear_row_highlights::<EditPredictionPreview>();
 7812            self.update_visible_edit_prediction(window, cx);
 7813            cx.notify();
 7814        }
 7815    }
 7816
 7817    fn update_visible_edit_prediction(
 7818        &mut self,
 7819        _window: &mut Window,
 7820        cx: &mut Context<Self>,
 7821    ) -> Option<()> {
 7822        if DisableAiSettings::get_global(cx).disable_ai {
 7823            return None;
 7824        }
 7825
 7826        if self.ime_transaction.is_some() {
 7827            self.discard_edit_prediction(false, cx);
 7828            return None;
 7829        }
 7830
 7831        let selection = self.selections.newest_anchor();
 7832        let cursor = selection.head();
 7833        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7834        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7835        let excerpt_id = cursor.excerpt_id;
 7836
 7837        let show_in_menu = self.show_edit_predictions_in_menu();
 7838        let completions_menu_has_precedence = !show_in_menu
 7839            && (self.context_menu.borrow().is_some()
 7840                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7841
 7842        if completions_menu_has_precedence
 7843            || !offset_selection.is_empty()
 7844            || self
 7845                .active_edit_prediction
 7846                .as_ref()
 7847                .is_some_and(|completion| {
 7848                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7849                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7850                    !invalidation_range.contains(&offset_selection.head())
 7851                })
 7852        {
 7853            self.discard_edit_prediction(false, cx);
 7854            return None;
 7855        }
 7856
 7857        self.take_active_edit_prediction(cx);
 7858        let Some(provider) = self.edit_prediction_provider() else {
 7859            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7860            return None;
 7861        };
 7862
 7863        let (buffer, cursor_buffer_position) =
 7864            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7865
 7866        self.edit_prediction_settings =
 7867            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7868
 7869        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7870
 7871        if self.edit_prediction_indent_conflict {
 7872            let cursor_point = cursor.to_point(&multibuffer);
 7873
 7874            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7875
 7876            if let Some((_, indent)) = indents.iter().next()
 7877                && indent.len == cursor_point.column
 7878            {
 7879                self.edit_prediction_indent_conflict = false;
 7880            }
 7881        }
 7882
 7883        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7884        let edits = edit_prediction
 7885            .edits
 7886            .into_iter()
 7887            .flat_map(|(range, new_text)| {
 7888                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7889                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7890                Some((start..end, new_text))
 7891            })
 7892            .collect::<Vec<_>>();
 7893        if edits.is_empty() {
 7894            return None;
 7895        }
 7896
 7897        let first_edit_start = edits.first().unwrap().0.start;
 7898        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7899        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7900
 7901        let last_edit_end = edits.last().unwrap().0.end;
 7902        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7903        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7904
 7905        let cursor_row = cursor.to_point(&multibuffer).row;
 7906
 7907        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7908
 7909        let mut inlay_ids = Vec::new();
 7910        let invalidation_row_range;
 7911        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7912            Some(cursor_row..edit_end_row)
 7913        } else if cursor_row > edit_end_row {
 7914            Some(edit_start_row..cursor_row)
 7915        } else {
 7916            None
 7917        };
 7918        let supports_jump = self
 7919            .edit_prediction_provider
 7920            .as_ref()
 7921            .map(|provider| provider.provider.supports_jump_to_edit())
 7922            .unwrap_or(true);
 7923
 7924        let is_move = supports_jump
 7925            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7926        let completion = if is_move {
 7927            invalidation_row_range =
 7928                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7929            let target = first_edit_start;
 7930            EditPrediction::Move { target, snapshot }
 7931        } else {
 7932            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7933                && !self.edit_predictions_hidden_for_vim_mode;
 7934
 7935            if show_completions_in_buffer {
 7936                if edits
 7937                    .iter()
 7938                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7939                {
 7940                    let mut inlays = Vec::new();
 7941                    for (range, new_text) in &edits {
 7942                        let inlay = Inlay::edit_prediction(
 7943                            post_inc(&mut self.next_inlay_id),
 7944                            range.start,
 7945                            new_text.as_str(),
 7946                        );
 7947                        inlay_ids.push(inlay.id);
 7948                        inlays.push(inlay);
 7949                    }
 7950
 7951                    self.splice_inlays(&[], inlays, cx);
 7952                } else {
 7953                    let background_color = cx.theme().status().deleted_background;
 7954                    self.highlight_text::<EditPredictionHighlight>(
 7955                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7956                        HighlightStyle {
 7957                            background_color: Some(background_color),
 7958                            ..Default::default()
 7959                        },
 7960                        cx,
 7961                    );
 7962                }
 7963            }
 7964
 7965            invalidation_row_range = edit_start_row..edit_end_row;
 7966
 7967            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7968                if provider.show_tab_accept_marker() {
 7969                    EditDisplayMode::TabAccept
 7970                } else {
 7971                    EditDisplayMode::Inline
 7972                }
 7973            } else {
 7974                EditDisplayMode::DiffPopover
 7975            };
 7976
 7977            EditPrediction::Edit {
 7978                edits,
 7979                edit_preview: edit_prediction.edit_preview,
 7980                display_mode,
 7981                snapshot,
 7982            }
 7983        };
 7984
 7985        let invalidation_range = multibuffer
 7986            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7987            ..multibuffer.anchor_after(Point::new(
 7988                invalidation_row_range.end,
 7989                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7990            ));
 7991
 7992        self.stale_edit_prediction_in_menu = None;
 7993        self.active_edit_prediction = Some(EditPredictionState {
 7994            inlay_ids,
 7995            completion,
 7996            completion_id: edit_prediction.id,
 7997            invalidation_range,
 7998        });
 7999
 8000        cx.notify();
 8001
 8002        Some(())
 8003    }
 8004
 8005    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8006        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8007    }
 8008
 8009    fn clear_tasks(&mut self) {
 8010        self.tasks.clear()
 8011    }
 8012
 8013    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8014        if self.tasks.insert(key, value).is_some() {
 8015            // This case should hopefully be rare, but just in case...
 8016            log::error!(
 8017                "multiple different run targets found on a single line, only the last target will be rendered"
 8018            )
 8019        }
 8020    }
 8021
 8022    /// Get all display points of breakpoints that will be rendered within editor
 8023    ///
 8024    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8025    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8026    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8027    fn active_breakpoints(
 8028        &self,
 8029        range: Range<DisplayRow>,
 8030        window: &mut Window,
 8031        cx: &mut Context<Self>,
 8032    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8033        let mut breakpoint_display_points = HashMap::default();
 8034
 8035        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8036            return breakpoint_display_points;
 8037        };
 8038
 8039        let snapshot = self.snapshot(window, cx);
 8040
 8041        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8042        let Some(project) = self.project() else {
 8043            return breakpoint_display_points;
 8044        };
 8045
 8046        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8047            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8048
 8049        for (buffer_snapshot, range, excerpt_id) in
 8050            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8051        {
 8052            let Some(buffer) = project
 8053                .read(cx)
 8054                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8055            else {
 8056                continue;
 8057            };
 8058            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8059                &buffer,
 8060                Some(
 8061                    buffer_snapshot.anchor_before(range.start)
 8062                        ..buffer_snapshot.anchor_after(range.end),
 8063                ),
 8064                buffer_snapshot,
 8065                cx,
 8066            );
 8067            for (breakpoint, state) in breakpoints {
 8068                let multi_buffer_anchor =
 8069                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8070                let position = multi_buffer_anchor
 8071                    .to_point(multi_buffer_snapshot)
 8072                    .to_display_point(&snapshot);
 8073
 8074                breakpoint_display_points.insert(
 8075                    position.row(),
 8076                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8077                );
 8078            }
 8079        }
 8080
 8081        breakpoint_display_points
 8082    }
 8083
 8084    fn breakpoint_context_menu(
 8085        &self,
 8086        anchor: Anchor,
 8087        window: &mut Window,
 8088        cx: &mut Context<Self>,
 8089    ) -> Entity<ui::ContextMenu> {
 8090        let weak_editor = cx.weak_entity();
 8091        let focus_handle = self.focus_handle(cx);
 8092
 8093        let row = self
 8094            .buffer
 8095            .read(cx)
 8096            .snapshot(cx)
 8097            .summary_for_anchor::<Point>(&anchor)
 8098            .row;
 8099
 8100        let breakpoint = self
 8101            .breakpoint_at_row(row, window, cx)
 8102            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8103
 8104        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8105            "Edit Log Breakpoint"
 8106        } else {
 8107            "Set Log Breakpoint"
 8108        };
 8109
 8110        let condition_breakpoint_msg = if breakpoint
 8111            .as_ref()
 8112            .is_some_and(|bp| bp.1.condition.is_some())
 8113        {
 8114            "Edit Condition Breakpoint"
 8115        } else {
 8116            "Set Condition Breakpoint"
 8117        };
 8118
 8119        let hit_condition_breakpoint_msg = if breakpoint
 8120            .as_ref()
 8121            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8122        {
 8123            "Edit Hit Condition Breakpoint"
 8124        } else {
 8125            "Set Hit Condition Breakpoint"
 8126        };
 8127
 8128        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8129            "Unset Breakpoint"
 8130        } else {
 8131            "Set Breakpoint"
 8132        };
 8133
 8134        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8135
 8136        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8137            BreakpointState::Enabled => Some("Disable"),
 8138            BreakpointState::Disabled => Some("Enable"),
 8139        });
 8140
 8141        let (anchor, breakpoint) =
 8142            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8143
 8144        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8145            menu.on_blur_subscription(Subscription::new(|| {}))
 8146                .context(focus_handle)
 8147                .when(run_to_cursor, |this| {
 8148                    let weak_editor = weak_editor.clone();
 8149                    this.entry("Run to cursor", None, move |window, cx| {
 8150                        weak_editor
 8151                            .update(cx, |editor, cx| {
 8152                                editor.change_selections(
 8153                                    SelectionEffects::no_scroll(),
 8154                                    window,
 8155                                    cx,
 8156                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8157                                );
 8158                            })
 8159                            .ok();
 8160
 8161                        window.dispatch_action(Box::new(RunToCursor), cx);
 8162                    })
 8163                    .separator()
 8164                })
 8165                .when_some(toggle_state_msg, |this, msg| {
 8166                    this.entry(msg, None, {
 8167                        let weak_editor = weak_editor.clone();
 8168                        let breakpoint = breakpoint.clone();
 8169                        move |_window, cx| {
 8170                            weak_editor
 8171                                .update(cx, |this, cx| {
 8172                                    this.edit_breakpoint_at_anchor(
 8173                                        anchor,
 8174                                        breakpoint.as_ref().clone(),
 8175                                        BreakpointEditAction::InvertState,
 8176                                        cx,
 8177                                    );
 8178                                })
 8179                                .log_err();
 8180                        }
 8181                    })
 8182                })
 8183                .entry(set_breakpoint_msg, None, {
 8184                    let weak_editor = weak_editor.clone();
 8185                    let breakpoint = breakpoint.clone();
 8186                    move |_window, cx| {
 8187                        weak_editor
 8188                            .update(cx, |this, cx| {
 8189                                this.edit_breakpoint_at_anchor(
 8190                                    anchor,
 8191                                    breakpoint.as_ref().clone(),
 8192                                    BreakpointEditAction::Toggle,
 8193                                    cx,
 8194                                );
 8195                            })
 8196                            .log_err();
 8197                    }
 8198                })
 8199                .entry(log_breakpoint_msg, None, {
 8200                    let breakpoint = breakpoint.clone();
 8201                    let weak_editor = weak_editor.clone();
 8202                    move |window, cx| {
 8203                        weak_editor
 8204                            .update(cx, |this, cx| {
 8205                                this.add_edit_breakpoint_block(
 8206                                    anchor,
 8207                                    breakpoint.as_ref(),
 8208                                    BreakpointPromptEditAction::Log,
 8209                                    window,
 8210                                    cx,
 8211                                );
 8212                            })
 8213                            .log_err();
 8214                    }
 8215                })
 8216                .entry(condition_breakpoint_msg, None, {
 8217                    let breakpoint = breakpoint.clone();
 8218                    let weak_editor = weak_editor.clone();
 8219                    move |window, cx| {
 8220                        weak_editor
 8221                            .update(cx, |this, cx| {
 8222                                this.add_edit_breakpoint_block(
 8223                                    anchor,
 8224                                    breakpoint.as_ref(),
 8225                                    BreakpointPromptEditAction::Condition,
 8226                                    window,
 8227                                    cx,
 8228                                );
 8229                            })
 8230                            .log_err();
 8231                    }
 8232                })
 8233                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8234                    weak_editor
 8235                        .update(cx, |this, cx| {
 8236                            this.add_edit_breakpoint_block(
 8237                                anchor,
 8238                                breakpoint.as_ref(),
 8239                                BreakpointPromptEditAction::HitCondition,
 8240                                window,
 8241                                cx,
 8242                            );
 8243                        })
 8244                        .log_err();
 8245                })
 8246        })
 8247    }
 8248
 8249    fn render_breakpoint(
 8250        &self,
 8251        position: Anchor,
 8252        row: DisplayRow,
 8253        breakpoint: &Breakpoint,
 8254        state: Option<BreakpointSessionState>,
 8255        cx: &mut Context<Self>,
 8256    ) -> IconButton {
 8257        let is_rejected = state.is_some_and(|s| !s.verified);
 8258        // Is it a breakpoint that shows up when hovering over gutter?
 8259        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8260            (false, false),
 8261            |PhantomBreakpointIndicator {
 8262                 is_active,
 8263                 display_row,
 8264                 collides_with_existing_breakpoint,
 8265             }| {
 8266                (
 8267                    is_active && display_row == row,
 8268                    collides_with_existing_breakpoint,
 8269                )
 8270            },
 8271        );
 8272
 8273        let (color, icon) = {
 8274            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8275                (false, false) => ui::IconName::DebugBreakpoint,
 8276                (true, false) => ui::IconName::DebugLogBreakpoint,
 8277                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8278                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8279            };
 8280
 8281            let color = if is_phantom {
 8282                Color::Hint
 8283            } else if is_rejected {
 8284                Color::Disabled
 8285            } else {
 8286                Color::Debugger
 8287            };
 8288
 8289            (color, icon)
 8290        };
 8291
 8292        let breakpoint = Arc::from(breakpoint.clone());
 8293
 8294        let alt_as_text = gpui::Keystroke {
 8295            modifiers: Modifiers::secondary_key(),
 8296            ..Default::default()
 8297        };
 8298        let primary_action_text = if breakpoint.is_disabled() {
 8299            "Enable breakpoint"
 8300        } else if is_phantom && !collides_with_existing {
 8301            "Set breakpoint"
 8302        } else {
 8303            "Unset breakpoint"
 8304        };
 8305        let focus_handle = self.focus_handle.clone();
 8306
 8307        let meta = if is_rejected {
 8308            SharedString::from("No executable code is associated with this line.")
 8309        } else if collides_with_existing && !breakpoint.is_disabled() {
 8310            SharedString::from(format!(
 8311                "{alt_as_text}-click to disable,\nright-click for more options."
 8312            ))
 8313        } else {
 8314            SharedString::from("Right-click for more options.")
 8315        };
 8316        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8317            .icon_size(IconSize::XSmall)
 8318            .size(ui::ButtonSize::None)
 8319            .when(is_rejected, |this| {
 8320                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8321            })
 8322            .icon_color(color)
 8323            .style(ButtonStyle::Transparent)
 8324            .on_click(cx.listener({
 8325                move |editor, event: &ClickEvent, window, cx| {
 8326                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8327                        BreakpointEditAction::InvertState
 8328                    } else {
 8329                        BreakpointEditAction::Toggle
 8330                    };
 8331
 8332                    window.focus(&editor.focus_handle(cx));
 8333                    editor.edit_breakpoint_at_anchor(
 8334                        position,
 8335                        breakpoint.as_ref().clone(),
 8336                        edit_action,
 8337                        cx,
 8338                    );
 8339                }
 8340            }))
 8341            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8342                editor.set_breakpoint_context_menu(
 8343                    row,
 8344                    Some(position),
 8345                    event.position(),
 8346                    window,
 8347                    cx,
 8348                );
 8349            }))
 8350            .tooltip(move |window, cx| {
 8351                Tooltip::with_meta_in(
 8352                    primary_action_text,
 8353                    Some(&ToggleBreakpoint),
 8354                    meta.clone(),
 8355                    &focus_handle,
 8356                    window,
 8357                    cx,
 8358                )
 8359            })
 8360    }
 8361
 8362    fn build_tasks_context(
 8363        project: &Entity<Project>,
 8364        buffer: &Entity<Buffer>,
 8365        buffer_row: u32,
 8366        tasks: &Arc<RunnableTasks>,
 8367        cx: &mut Context<Self>,
 8368    ) -> Task<Option<task::TaskContext>> {
 8369        let position = Point::new(buffer_row, tasks.column);
 8370        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8371        let location = Location {
 8372            buffer: buffer.clone(),
 8373            range: range_start..range_start,
 8374        };
 8375        // Fill in the environmental variables from the tree-sitter captures
 8376        let mut captured_task_variables = TaskVariables::default();
 8377        for (capture_name, value) in tasks.extra_variables.clone() {
 8378            captured_task_variables.insert(
 8379                task::VariableName::Custom(capture_name.into()),
 8380                value.clone(),
 8381            );
 8382        }
 8383        project.update(cx, |project, cx| {
 8384            project.task_store().update(cx, |task_store, cx| {
 8385                task_store.task_context_for_location(captured_task_variables, location, cx)
 8386            })
 8387        })
 8388    }
 8389
 8390    pub fn spawn_nearest_task(
 8391        &mut self,
 8392        action: &SpawnNearestTask,
 8393        window: &mut Window,
 8394        cx: &mut Context<Self>,
 8395    ) {
 8396        let Some((workspace, _)) = self.workspace.clone() else {
 8397            return;
 8398        };
 8399        let Some(project) = self.project.clone() else {
 8400            return;
 8401        };
 8402
 8403        // Try to find a closest, enclosing node using tree-sitter that has a task
 8404        let Some((buffer, buffer_row, tasks)) = self
 8405            .find_enclosing_node_task(cx)
 8406            // Or find the task that's closest in row-distance.
 8407            .or_else(|| self.find_closest_task(cx))
 8408        else {
 8409            return;
 8410        };
 8411
 8412        let reveal_strategy = action.reveal;
 8413        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8414        cx.spawn_in(window, async move |_, cx| {
 8415            let context = task_context.await?;
 8416            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8417
 8418            let resolved = &mut resolved_task.resolved;
 8419            resolved.reveal = reveal_strategy;
 8420
 8421            workspace
 8422                .update_in(cx, |workspace, window, cx| {
 8423                    workspace.schedule_resolved_task(
 8424                        task_source_kind,
 8425                        resolved_task,
 8426                        false,
 8427                        window,
 8428                        cx,
 8429                    );
 8430                })
 8431                .ok()
 8432        })
 8433        .detach();
 8434    }
 8435
 8436    fn find_closest_task(
 8437        &mut self,
 8438        cx: &mut Context<Self>,
 8439    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8440        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8441
 8442        let ((buffer_id, row), tasks) = self
 8443            .tasks
 8444            .iter()
 8445            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8446
 8447        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8448        let tasks = Arc::new(tasks.to_owned());
 8449        Some((buffer, *row, tasks))
 8450    }
 8451
 8452    fn find_enclosing_node_task(
 8453        &mut self,
 8454        cx: &mut Context<Self>,
 8455    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8456        let snapshot = self.buffer.read(cx).snapshot(cx);
 8457        let offset = self.selections.newest::<usize>(cx).head();
 8458        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8459        let buffer_id = excerpt.buffer().remote_id();
 8460
 8461        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8462        let mut cursor = layer.node().walk();
 8463
 8464        while cursor.goto_first_child_for_byte(offset).is_some() {
 8465            if cursor.node().end_byte() == offset {
 8466                cursor.goto_next_sibling();
 8467            }
 8468        }
 8469
 8470        // Ascend to the smallest ancestor that contains the range and has a task.
 8471        loop {
 8472            let node = cursor.node();
 8473            let node_range = node.byte_range();
 8474            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8475
 8476            // Check if this node contains our offset
 8477            if node_range.start <= offset && node_range.end >= offset {
 8478                // If it contains offset, check for task
 8479                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8480                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8481                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8482                }
 8483            }
 8484
 8485            if !cursor.goto_parent() {
 8486                break;
 8487            }
 8488        }
 8489        None
 8490    }
 8491
 8492    fn render_run_indicator(
 8493        &self,
 8494        _style: &EditorStyle,
 8495        is_active: bool,
 8496        row: DisplayRow,
 8497        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8498        cx: &mut Context<Self>,
 8499    ) -> IconButton {
 8500        let color = Color::Muted;
 8501        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8502
 8503        IconButton::new(
 8504            ("run_indicator", row.0 as usize),
 8505            ui::IconName::PlayOutlined,
 8506        )
 8507        .shape(ui::IconButtonShape::Square)
 8508        .icon_size(IconSize::XSmall)
 8509        .icon_color(color)
 8510        .toggle_state(is_active)
 8511        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8512            let quick_launch = match e {
 8513                ClickEvent::Keyboard(_) => true,
 8514                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8515            };
 8516
 8517            window.focus(&editor.focus_handle(cx));
 8518            editor.toggle_code_actions(
 8519                &ToggleCodeActions {
 8520                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8521                    quick_launch,
 8522                },
 8523                window,
 8524                cx,
 8525            );
 8526        }))
 8527        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8528            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8529        }))
 8530    }
 8531
 8532    pub fn context_menu_visible(&self) -> bool {
 8533        !self.edit_prediction_preview_is_active()
 8534            && self
 8535                .context_menu
 8536                .borrow()
 8537                .as_ref()
 8538                .is_some_and(|menu| menu.visible())
 8539    }
 8540
 8541    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8542        self.context_menu
 8543            .borrow()
 8544            .as_ref()
 8545            .map(|menu| menu.origin())
 8546    }
 8547
 8548    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8549        self.context_menu_options = Some(options);
 8550    }
 8551
 8552    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8553    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8554
 8555    fn render_edit_prediction_popover(
 8556        &mut self,
 8557        text_bounds: &Bounds<Pixels>,
 8558        content_origin: gpui::Point<Pixels>,
 8559        right_margin: Pixels,
 8560        editor_snapshot: &EditorSnapshot,
 8561        visible_row_range: Range<DisplayRow>,
 8562        scroll_top: f32,
 8563        scroll_bottom: f32,
 8564        line_layouts: &[LineWithInvisibles],
 8565        line_height: Pixels,
 8566        scroll_pixel_position: gpui::Point<Pixels>,
 8567        newest_selection_head: Option<DisplayPoint>,
 8568        editor_width: Pixels,
 8569        style: &EditorStyle,
 8570        window: &mut Window,
 8571        cx: &mut App,
 8572    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8573        if self.mode().is_minimap() {
 8574            return None;
 8575        }
 8576        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8577
 8578        if self.edit_prediction_visible_in_cursor_popover(true) {
 8579            return None;
 8580        }
 8581
 8582        match &active_edit_prediction.completion {
 8583            EditPrediction::Move { target, .. } => {
 8584                let target_display_point = target.to_display_point(editor_snapshot);
 8585
 8586                if self.edit_prediction_requires_modifier() {
 8587                    if !self.edit_prediction_preview_is_active() {
 8588                        return None;
 8589                    }
 8590
 8591                    self.render_edit_prediction_modifier_jump_popover(
 8592                        text_bounds,
 8593                        content_origin,
 8594                        visible_row_range,
 8595                        line_layouts,
 8596                        line_height,
 8597                        scroll_pixel_position,
 8598                        newest_selection_head,
 8599                        target_display_point,
 8600                        window,
 8601                        cx,
 8602                    )
 8603                } else {
 8604                    self.render_edit_prediction_eager_jump_popover(
 8605                        text_bounds,
 8606                        content_origin,
 8607                        editor_snapshot,
 8608                        visible_row_range,
 8609                        scroll_top,
 8610                        scroll_bottom,
 8611                        line_height,
 8612                        scroll_pixel_position,
 8613                        target_display_point,
 8614                        editor_width,
 8615                        window,
 8616                        cx,
 8617                    )
 8618                }
 8619            }
 8620            EditPrediction::Edit {
 8621                display_mode: EditDisplayMode::Inline,
 8622                ..
 8623            } => None,
 8624            EditPrediction::Edit {
 8625                display_mode: EditDisplayMode::TabAccept,
 8626                edits,
 8627                ..
 8628            } => {
 8629                let range = &edits.first()?.0;
 8630                let target_display_point = range.end.to_display_point(editor_snapshot);
 8631
 8632                self.render_edit_prediction_end_of_line_popover(
 8633                    "Accept",
 8634                    editor_snapshot,
 8635                    visible_row_range,
 8636                    target_display_point,
 8637                    line_height,
 8638                    scroll_pixel_position,
 8639                    content_origin,
 8640                    editor_width,
 8641                    window,
 8642                    cx,
 8643                )
 8644            }
 8645            EditPrediction::Edit {
 8646                edits,
 8647                edit_preview,
 8648                display_mode: EditDisplayMode::DiffPopover,
 8649                snapshot,
 8650            } => self.render_edit_prediction_diff_popover(
 8651                text_bounds,
 8652                content_origin,
 8653                right_margin,
 8654                editor_snapshot,
 8655                visible_row_range,
 8656                line_layouts,
 8657                line_height,
 8658                scroll_pixel_position,
 8659                newest_selection_head,
 8660                editor_width,
 8661                style,
 8662                edits,
 8663                edit_preview,
 8664                snapshot,
 8665                window,
 8666                cx,
 8667            ),
 8668        }
 8669    }
 8670
 8671    fn render_edit_prediction_modifier_jump_popover(
 8672        &mut self,
 8673        text_bounds: &Bounds<Pixels>,
 8674        content_origin: gpui::Point<Pixels>,
 8675        visible_row_range: Range<DisplayRow>,
 8676        line_layouts: &[LineWithInvisibles],
 8677        line_height: Pixels,
 8678        scroll_pixel_position: gpui::Point<Pixels>,
 8679        newest_selection_head: Option<DisplayPoint>,
 8680        target_display_point: DisplayPoint,
 8681        window: &mut Window,
 8682        cx: &mut App,
 8683    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8684        let scrolled_content_origin =
 8685            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8686
 8687        const SCROLL_PADDING_Y: Pixels = px(12.);
 8688
 8689        if target_display_point.row() < visible_row_range.start {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |_| SCROLL_PADDING_Y,
 8692                IconName::ArrowUp,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        } else if target_display_point.row() >= visible_row_range.end {
 8701            return self.render_edit_prediction_scroll_popover(
 8702                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8703                IconName::ArrowDown,
 8704                visible_row_range,
 8705                line_layouts,
 8706                newest_selection_head,
 8707                scrolled_content_origin,
 8708                window,
 8709                cx,
 8710            );
 8711        }
 8712
 8713        const POLE_WIDTH: Pixels = px(2.);
 8714
 8715        let line_layout =
 8716            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8717        let target_column = target_display_point.column() as usize;
 8718
 8719        let target_x = line_layout.x_for_index(target_column);
 8720        let target_y =
 8721            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8722
 8723        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8724
 8725        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8726        border_color.l += 0.001;
 8727
 8728        let mut element = v_flex()
 8729            .items_end()
 8730            .when(flag_on_right, |el| el.items_start())
 8731            .child(if flag_on_right {
 8732                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8733                    .rounded_bl(px(0.))
 8734                    .rounded_tl(px(0.))
 8735                    .border_l_2()
 8736                    .border_color(border_color)
 8737            } else {
 8738                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8739                    .rounded_br(px(0.))
 8740                    .rounded_tr(px(0.))
 8741                    .border_r_2()
 8742                    .border_color(border_color)
 8743            })
 8744            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8745            .into_any();
 8746
 8747        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8748
 8749        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8750            - point(
 8751                if flag_on_right {
 8752                    POLE_WIDTH
 8753                } else {
 8754                    size.width - POLE_WIDTH
 8755                },
 8756                size.height - line_height,
 8757            );
 8758
 8759        origin.x = origin.x.max(content_origin.x);
 8760
 8761        element.prepaint_at(origin, window, cx);
 8762
 8763        Some((element, origin))
 8764    }
 8765
 8766    fn render_edit_prediction_scroll_popover(
 8767        &mut self,
 8768        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8769        scroll_icon: IconName,
 8770        visible_row_range: Range<DisplayRow>,
 8771        line_layouts: &[LineWithInvisibles],
 8772        newest_selection_head: Option<DisplayPoint>,
 8773        scrolled_content_origin: gpui::Point<Pixels>,
 8774        window: &mut Window,
 8775        cx: &mut App,
 8776    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8777        let mut element = self
 8778            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8779            .into_any();
 8780
 8781        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8782
 8783        let cursor = newest_selection_head?;
 8784        let cursor_row_layout =
 8785            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8786        let cursor_column = cursor.column() as usize;
 8787
 8788        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8789
 8790        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8791
 8792        element.prepaint_at(origin, window, cx);
 8793        Some((element, origin))
 8794    }
 8795
 8796    fn render_edit_prediction_eager_jump_popover(
 8797        &mut self,
 8798        text_bounds: &Bounds<Pixels>,
 8799        content_origin: gpui::Point<Pixels>,
 8800        editor_snapshot: &EditorSnapshot,
 8801        visible_row_range: Range<DisplayRow>,
 8802        scroll_top: f32,
 8803        scroll_bottom: f32,
 8804        line_height: Pixels,
 8805        scroll_pixel_position: gpui::Point<Pixels>,
 8806        target_display_point: DisplayPoint,
 8807        editor_width: Pixels,
 8808        window: &mut Window,
 8809        cx: &mut App,
 8810    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8811        if target_display_point.row().as_f32() < scroll_top {
 8812            let mut element = self
 8813                .render_edit_prediction_line_popover(
 8814                    "Jump to Edit",
 8815                    Some(IconName::ArrowUp),
 8816                    window,
 8817                    cx,
 8818                )?
 8819                .into_any();
 8820
 8821            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8822            let offset = point(
 8823                (text_bounds.size.width - size.width) / 2.,
 8824                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8825            );
 8826
 8827            let origin = text_bounds.origin + offset;
 8828            element.prepaint_at(origin, window, cx);
 8829            Some((element, origin))
 8830        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8831            let mut element = self
 8832                .render_edit_prediction_line_popover(
 8833                    "Jump to Edit",
 8834                    Some(IconName::ArrowDown),
 8835                    window,
 8836                    cx,
 8837                )?
 8838                .into_any();
 8839
 8840            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8841            let offset = point(
 8842                (text_bounds.size.width - size.width) / 2.,
 8843                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8844            );
 8845
 8846            let origin = text_bounds.origin + offset;
 8847            element.prepaint_at(origin, window, cx);
 8848            Some((element, origin))
 8849        } else {
 8850            self.render_edit_prediction_end_of_line_popover(
 8851                "Jump to Edit",
 8852                editor_snapshot,
 8853                visible_row_range,
 8854                target_display_point,
 8855                line_height,
 8856                scroll_pixel_position,
 8857                content_origin,
 8858                editor_width,
 8859                window,
 8860                cx,
 8861            )
 8862        }
 8863    }
 8864
 8865    fn render_edit_prediction_end_of_line_popover(
 8866        self: &mut Editor,
 8867        label: &'static str,
 8868        editor_snapshot: &EditorSnapshot,
 8869        visible_row_range: Range<DisplayRow>,
 8870        target_display_point: DisplayPoint,
 8871        line_height: Pixels,
 8872        scroll_pixel_position: gpui::Point<Pixels>,
 8873        content_origin: gpui::Point<Pixels>,
 8874        editor_width: Pixels,
 8875        window: &mut Window,
 8876        cx: &mut App,
 8877    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8878        let target_line_end = DisplayPoint::new(
 8879            target_display_point.row(),
 8880            editor_snapshot.line_len(target_display_point.row()),
 8881        );
 8882
 8883        let mut element = self
 8884            .render_edit_prediction_line_popover(label, None, window, cx)?
 8885            .into_any();
 8886
 8887        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8888
 8889        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8890
 8891        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8892        let mut origin = start_point
 8893            + line_origin
 8894            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8895        origin.x = origin.x.max(content_origin.x);
 8896
 8897        let max_x = content_origin.x + editor_width - size.width;
 8898
 8899        if origin.x > max_x {
 8900            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8901
 8902            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8903                origin.y += offset;
 8904                IconName::ArrowUp
 8905            } else {
 8906                origin.y -= offset;
 8907                IconName::ArrowDown
 8908            };
 8909
 8910            element = self
 8911                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8912                .into_any();
 8913
 8914            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8915
 8916            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8917        }
 8918
 8919        element.prepaint_at(origin, window, cx);
 8920        Some((element, origin))
 8921    }
 8922
 8923    fn render_edit_prediction_diff_popover(
 8924        self: &Editor,
 8925        text_bounds: &Bounds<Pixels>,
 8926        content_origin: gpui::Point<Pixels>,
 8927        right_margin: Pixels,
 8928        editor_snapshot: &EditorSnapshot,
 8929        visible_row_range: Range<DisplayRow>,
 8930        line_layouts: &[LineWithInvisibles],
 8931        line_height: Pixels,
 8932        scroll_pixel_position: gpui::Point<Pixels>,
 8933        newest_selection_head: Option<DisplayPoint>,
 8934        editor_width: Pixels,
 8935        style: &EditorStyle,
 8936        edits: &Vec<(Range<Anchor>, String)>,
 8937        edit_preview: &Option<language::EditPreview>,
 8938        snapshot: &language::BufferSnapshot,
 8939        window: &mut Window,
 8940        cx: &mut App,
 8941    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8942        let edit_start = edits
 8943            .first()
 8944            .unwrap()
 8945            .0
 8946            .start
 8947            .to_display_point(editor_snapshot);
 8948        let edit_end = edits
 8949            .last()
 8950            .unwrap()
 8951            .0
 8952            .end
 8953            .to_display_point(editor_snapshot);
 8954
 8955        let is_visible = visible_row_range.contains(&edit_start.row())
 8956            || visible_row_range.contains(&edit_end.row());
 8957        if !is_visible {
 8958            return None;
 8959        }
 8960
 8961        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8962            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8963        } else {
 8964            // Fallback for providers without edit_preview
 8965            crate::edit_prediction_fallback_text(edits, cx)
 8966        };
 8967
 8968        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8969        let line_count = highlighted_edits.text.lines().count();
 8970
 8971        const BORDER_WIDTH: Pixels = px(1.);
 8972
 8973        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8974        let has_keybind = keybind.is_some();
 8975
 8976        let mut element = h_flex()
 8977            .items_start()
 8978            .child(
 8979                h_flex()
 8980                    .bg(cx.theme().colors().editor_background)
 8981                    .border(BORDER_WIDTH)
 8982                    .shadow_xs()
 8983                    .border_color(cx.theme().colors().border)
 8984                    .rounded_l_lg()
 8985                    .when(line_count > 1, |el| el.rounded_br_lg())
 8986                    .pr_1()
 8987                    .child(styled_text),
 8988            )
 8989            .child(
 8990                h_flex()
 8991                    .h(line_height + BORDER_WIDTH * 2.)
 8992                    .px_1p5()
 8993                    .gap_1()
 8994                    // Workaround: For some reason, there's a gap if we don't do this
 8995                    .ml(-BORDER_WIDTH)
 8996                    .shadow(vec![gpui::BoxShadow {
 8997                        color: gpui::black().opacity(0.05),
 8998                        offset: point(px(1.), px(1.)),
 8999                        blur_radius: px(2.),
 9000                        spread_radius: px(0.),
 9001                    }])
 9002                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9003                    .border(BORDER_WIDTH)
 9004                    .border_color(cx.theme().colors().border)
 9005                    .rounded_r_lg()
 9006                    .id("edit_prediction_diff_popover_keybind")
 9007                    .when(!has_keybind, |el| {
 9008                        let status_colors = cx.theme().status();
 9009
 9010                        el.bg(status_colors.error_background)
 9011                            .border_color(status_colors.error.opacity(0.6))
 9012                            .child(Icon::new(IconName::Info).color(Color::Error))
 9013                            .cursor_default()
 9014                            .hoverable_tooltip(move |_window, cx| {
 9015                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9016                            })
 9017                    })
 9018                    .children(keybind),
 9019            )
 9020            .into_any();
 9021
 9022        let longest_row =
 9023            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9024        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9025            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9026        } else {
 9027            layout_line(
 9028                longest_row,
 9029                editor_snapshot,
 9030                style,
 9031                editor_width,
 9032                |_| false,
 9033                window,
 9034                cx,
 9035            )
 9036            .width
 9037        };
 9038
 9039        let viewport_bounds =
 9040            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9041                right: -right_margin,
 9042                ..Default::default()
 9043            });
 9044
 9045        let x_after_longest =
 9046            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9047                - scroll_pixel_position.x;
 9048
 9049        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9050
 9051        // Fully visible if it can be displayed within the window (allow overlapping other
 9052        // panes). However, this is only allowed if the popover starts within text_bounds.
 9053        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9054            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9055
 9056        let mut origin = if can_position_to_the_right {
 9057            point(
 9058                x_after_longest,
 9059                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9060                    - scroll_pixel_position.y,
 9061            )
 9062        } else {
 9063            let cursor_row = newest_selection_head.map(|head| head.row());
 9064            let above_edit = edit_start
 9065                .row()
 9066                .0
 9067                .checked_sub(line_count as u32)
 9068                .map(DisplayRow);
 9069            let below_edit = Some(edit_end.row() + 1);
 9070            let above_cursor =
 9071                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9072            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9073
 9074            // Place the edit popover adjacent to the edit if there is a location
 9075            // available that is onscreen and does not obscure the cursor. Otherwise,
 9076            // place it adjacent to the cursor.
 9077            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9078                .into_iter()
 9079                .flatten()
 9080                .find(|&start_row| {
 9081                    let end_row = start_row + line_count as u32;
 9082                    visible_row_range.contains(&start_row)
 9083                        && visible_row_range.contains(&end_row)
 9084                        && cursor_row
 9085                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9086                })?;
 9087
 9088            content_origin
 9089                + point(
 9090                    -scroll_pixel_position.x,
 9091                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9092                )
 9093        };
 9094
 9095        origin.x -= BORDER_WIDTH;
 9096
 9097        window.defer_draw(element, origin, 1);
 9098
 9099        // Do not return an element, since it will already be drawn due to defer_draw.
 9100        None
 9101    }
 9102
 9103    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9104        px(30.)
 9105    }
 9106
 9107    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9108        if self.read_only(cx) {
 9109            cx.theme().players().read_only()
 9110        } else {
 9111            self.style.as_ref().unwrap().local_player
 9112        }
 9113    }
 9114
 9115    fn render_edit_prediction_accept_keybind(
 9116        &self,
 9117        window: &mut Window,
 9118        cx: &App,
 9119    ) -> Option<AnyElement> {
 9120        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9121        let accept_keystroke = accept_binding.keystroke()?;
 9122
 9123        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9124
 9125        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9126            Color::Accent
 9127        } else {
 9128            Color::Muted
 9129        };
 9130
 9131        h_flex()
 9132            .px_0p5()
 9133            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9134            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9135            .text_size(TextSize::XSmall.rems(cx))
 9136            .child(h_flex().children(ui::render_modifiers(
 9137                accept_keystroke.modifiers(),
 9138                PlatformStyle::platform(),
 9139                Some(modifiers_color),
 9140                Some(IconSize::XSmall.rems().into()),
 9141                true,
 9142            )))
 9143            .when(is_platform_style_mac, |parent| {
 9144                parent.child(accept_keystroke.key().to_string())
 9145            })
 9146            .when(!is_platform_style_mac, |parent| {
 9147                parent.child(
 9148                    Key::new(
 9149                        util::capitalize(accept_keystroke.key()),
 9150                        Some(Color::Default),
 9151                    )
 9152                    .size(Some(IconSize::XSmall.rems().into())),
 9153                )
 9154            })
 9155            .into_any()
 9156            .into()
 9157    }
 9158
 9159    fn render_edit_prediction_line_popover(
 9160        &self,
 9161        label: impl Into<SharedString>,
 9162        icon: Option<IconName>,
 9163        window: &mut Window,
 9164        cx: &App,
 9165    ) -> Option<Stateful<Div>> {
 9166        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9167
 9168        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9169        let has_keybind = keybind.is_some();
 9170
 9171        let result = h_flex()
 9172            .id("ep-line-popover")
 9173            .py_0p5()
 9174            .pl_1()
 9175            .pr(padding_right)
 9176            .gap_1()
 9177            .rounded_md()
 9178            .border_1()
 9179            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9180            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9181            .shadow_xs()
 9182            .when(!has_keybind, |el| {
 9183                let status_colors = cx.theme().status();
 9184
 9185                el.bg(status_colors.error_background)
 9186                    .border_color(status_colors.error.opacity(0.6))
 9187                    .pl_2()
 9188                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9189                    .cursor_default()
 9190                    .hoverable_tooltip(move |_window, cx| {
 9191                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9192                    })
 9193            })
 9194            .children(keybind)
 9195            .child(
 9196                Label::new(label)
 9197                    .size(LabelSize::Small)
 9198                    .when(!has_keybind, |el| {
 9199                        el.color(cx.theme().status().error.into()).strikethrough()
 9200                    }),
 9201            )
 9202            .when(!has_keybind, |el| {
 9203                el.child(
 9204                    h_flex().ml_1().child(
 9205                        Icon::new(IconName::Info)
 9206                            .size(IconSize::Small)
 9207                            .color(cx.theme().status().error.into()),
 9208                    ),
 9209                )
 9210            })
 9211            .when_some(icon, |element, icon| {
 9212                element.child(
 9213                    div()
 9214                        .mt(px(1.5))
 9215                        .child(Icon::new(icon).size(IconSize::Small)),
 9216                )
 9217            });
 9218
 9219        Some(result)
 9220    }
 9221
 9222    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9223        let accent_color = cx.theme().colors().text_accent;
 9224        let editor_bg_color = cx.theme().colors().editor_background;
 9225        editor_bg_color.blend(accent_color.opacity(0.1))
 9226    }
 9227
 9228    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9229        let accent_color = cx.theme().colors().text_accent;
 9230        let editor_bg_color = cx.theme().colors().editor_background;
 9231        editor_bg_color.blend(accent_color.opacity(0.6))
 9232    }
 9233    fn get_prediction_provider_icon_name(
 9234        provider: &Option<RegisteredEditPredictionProvider>,
 9235    ) -> IconName {
 9236        match provider {
 9237            Some(provider) => match provider.provider.name() {
 9238                "copilot" => IconName::Copilot,
 9239                "supermaven" => IconName::Supermaven,
 9240                _ => IconName::ZedPredict,
 9241            },
 9242            None => IconName::ZedPredict,
 9243        }
 9244    }
 9245
 9246    fn render_edit_prediction_cursor_popover(
 9247        &self,
 9248        min_width: Pixels,
 9249        max_width: Pixels,
 9250        cursor_point: Point,
 9251        style: &EditorStyle,
 9252        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9253        _window: &Window,
 9254        cx: &mut Context<Editor>,
 9255    ) -> Option<AnyElement> {
 9256        let provider = self.edit_prediction_provider.as_ref()?;
 9257        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9258
 9259        let is_refreshing = provider.provider.is_refreshing(cx);
 9260
 9261        fn pending_completion_container(icon: IconName) -> Div {
 9262            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9263        }
 9264
 9265        let completion = match &self.active_edit_prediction {
 9266            Some(prediction) => {
 9267                if !self.has_visible_completions_menu() {
 9268                    const RADIUS: Pixels = px(6.);
 9269                    const BORDER_WIDTH: Pixels = px(1.);
 9270
 9271                    return Some(
 9272                        h_flex()
 9273                            .elevation_2(cx)
 9274                            .border(BORDER_WIDTH)
 9275                            .border_color(cx.theme().colors().border)
 9276                            .when(accept_keystroke.is_none(), |el| {
 9277                                el.border_color(cx.theme().status().error)
 9278                            })
 9279                            .rounded(RADIUS)
 9280                            .rounded_tl(px(0.))
 9281                            .overflow_hidden()
 9282                            .child(div().px_1p5().child(match &prediction.completion {
 9283                                EditPrediction::Move { target, snapshot } => {
 9284                                    use text::ToPoint as _;
 9285                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9286                                    {
 9287                                        Icon::new(IconName::ZedPredictDown)
 9288                                    } else {
 9289                                        Icon::new(IconName::ZedPredictUp)
 9290                                    }
 9291                                }
 9292                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9293                            }))
 9294                            .child(
 9295                                h_flex()
 9296                                    .gap_1()
 9297                                    .py_1()
 9298                                    .px_2()
 9299                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9300                                    .border_l_1()
 9301                                    .border_color(cx.theme().colors().border)
 9302                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9303                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9304                                        el.child(
 9305                                            Label::new("Hold")
 9306                                                .size(LabelSize::Small)
 9307                                                .when(accept_keystroke.is_none(), |el| {
 9308                                                    el.strikethrough()
 9309                                                })
 9310                                                .line_height_style(LineHeightStyle::UiLabel),
 9311                                        )
 9312                                    })
 9313                                    .id("edit_prediction_cursor_popover_keybind")
 9314                                    .when(accept_keystroke.is_none(), |el| {
 9315                                        let status_colors = cx.theme().status();
 9316
 9317                                        el.bg(status_colors.error_background)
 9318                                            .border_color(status_colors.error.opacity(0.6))
 9319                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9320                                            .cursor_default()
 9321                                            .hoverable_tooltip(move |_window, cx| {
 9322                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9323                                                    .into()
 9324                                            })
 9325                                    })
 9326                                    .when_some(
 9327                                        accept_keystroke.as_ref(),
 9328                                        |el, accept_keystroke| {
 9329                                            el.child(h_flex().children(ui::render_modifiers(
 9330                                                accept_keystroke.modifiers(),
 9331                                                PlatformStyle::platform(),
 9332                                                Some(Color::Default),
 9333                                                Some(IconSize::XSmall.rems().into()),
 9334                                                false,
 9335                                            )))
 9336                                        },
 9337                                    ),
 9338                            )
 9339                            .into_any(),
 9340                    );
 9341                }
 9342
 9343                self.render_edit_prediction_cursor_popover_preview(
 9344                    prediction,
 9345                    cursor_point,
 9346                    style,
 9347                    cx,
 9348                )?
 9349            }
 9350
 9351            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9352                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9353                    stale_completion,
 9354                    cursor_point,
 9355                    style,
 9356                    cx,
 9357                )?,
 9358
 9359                None => pending_completion_container(provider_icon)
 9360                    .child(Label::new("...").size(LabelSize::Small)),
 9361            },
 9362
 9363            None => pending_completion_container(provider_icon)
 9364                .child(Label::new("...").size(LabelSize::Small)),
 9365        };
 9366
 9367        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9368            completion
 9369                .with_animation(
 9370                    "loading-completion",
 9371                    Animation::new(Duration::from_secs(2))
 9372                        .repeat()
 9373                        .with_easing(pulsating_between(0.4, 0.8)),
 9374                    |label, delta| label.opacity(delta),
 9375                )
 9376                .into_any_element()
 9377        } else {
 9378            completion.into_any_element()
 9379        };
 9380
 9381        let has_completion = self.active_edit_prediction.is_some();
 9382
 9383        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9384        Some(
 9385            h_flex()
 9386                .min_w(min_width)
 9387                .max_w(max_width)
 9388                .flex_1()
 9389                .elevation_2(cx)
 9390                .border_color(cx.theme().colors().border)
 9391                .child(
 9392                    div()
 9393                        .flex_1()
 9394                        .py_1()
 9395                        .px_2()
 9396                        .overflow_hidden()
 9397                        .child(completion),
 9398                )
 9399                .when_some(accept_keystroke, |el, accept_keystroke| {
 9400                    if !accept_keystroke.modifiers().modified() {
 9401                        return el;
 9402                    }
 9403
 9404                    el.child(
 9405                        h_flex()
 9406                            .h_full()
 9407                            .border_l_1()
 9408                            .rounded_r_lg()
 9409                            .border_color(cx.theme().colors().border)
 9410                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9411                            .gap_1()
 9412                            .py_1()
 9413                            .px_2()
 9414                            .child(
 9415                                h_flex()
 9416                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9417                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9418                                    .child(h_flex().children(ui::render_modifiers(
 9419                                        accept_keystroke.modifiers(),
 9420                                        PlatformStyle::platform(),
 9421                                        Some(if !has_completion {
 9422                                            Color::Muted
 9423                                        } else {
 9424                                            Color::Default
 9425                                        }),
 9426                                        None,
 9427                                        false,
 9428                                    ))),
 9429                            )
 9430                            .child(Label::new("Preview").into_any_element())
 9431                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9432                    )
 9433                })
 9434                .into_any(),
 9435        )
 9436    }
 9437
 9438    fn render_edit_prediction_cursor_popover_preview(
 9439        &self,
 9440        completion: &EditPredictionState,
 9441        cursor_point: Point,
 9442        style: &EditorStyle,
 9443        cx: &mut Context<Editor>,
 9444    ) -> Option<Div> {
 9445        use text::ToPoint as _;
 9446
 9447        fn render_relative_row_jump(
 9448            prefix: impl Into<String>,
 9449            current_row: u32,
 9450            target_row: u32,
 9451        ) -> Div {
 9452            let (row_diff, arrow) = if target_row < current_row {
 9453                (current_row - target_row, IconName::ArrowUp)
 9454            } else {
 9455                (target_row - current_row, IconName::ArrowDown)
 9456            };
 9457
 9458            h_flex()
 9459                .child(
 9460                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9461                        .color(Color::Muted)
 9462                        .size(LabelSize::Small),
 9463                )
 9464                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9465        }
 9466
 9467        let supports_jump = self
 9468            .edit_prediction_provider
 9469            .as_ref()
 9470            .map(|provider| provider.provider.supports_jump_to_edit())
 9471            .unwrap_or(true);
 9472
 9473        match &completion.completion {
 9474            EditPrediction::Move {
 9475                target, snapshot, ..
 9476            } => {
 9477                if !supports_jump {
 9478                    return None;
 9479                }
 9480
 9481                Some(
 9482                    h_flex()
 9483                        .px_2()
 9484                        .gap_2()
 9485                        .flex_1()
 9486                        .child(
 9487                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9488                                Icon::new(IconName::ZedPredictDown)
 9489                            } else {
 9490                                Icon::new(IconName::ZedPredictUp)
 9491                            },
 9492                        )
 9493                        .child(Label::new("Jump to Edit")),
 9494                )
 9495            }
 9496
 9497            EditPrediction::Edit {
 9498                edits,
 9499                edit_preview,
 9500                snapshot,
 9501                display_mode: _,
 9502            } => {
 9503                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9504
 9505                let (highlighted_edits, has_more_lines) =
 9506                    if let Some(edit_preview) = edit_preview.as_ref() {
 9507                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9508                            .first_line_preview()
 9509                    } else {
 9510                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9511                    };
 9512
 9513                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9514                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9515
 9516                let preview = h_flex()
 9517                    .gap_1()
 9518                    .min_w_16()
 9519                    .child(styled_text)
 9520                    .when(has_more_lines, |parent| parent.child(""));
 9521
 9522                let left = if supports_jump && first_edit_row != cursor_point.row {
 9523                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9524                        .into_any_element()
 9525                } else {
 9526                    let icon_name =
 9527                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9528                    Icon::new(icon_name).into_any_element()
 9529                };
 9530
 9531                Some(
 9532                    h_flex()
 9533                        .h_full()
 9534                        .flex_1()
 9535                        .gap_2()
 9536                        .pr_1()
 9537                        .overflow_x_hidden()
 9538                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9539                        .child(left)
 9540                        .child(preview),
 9541                )
 9542            }
 9543        }
 9544    }
 9545
 9546    pub fn render_context_menu(
 9547        &self,
 9548        style: &EditorStyle,
 9549        max_height_in_lines: u32,
 9550        window: &mut Window,
 9551        cx: &mut Context<Editor>,
 9552    ) -> Option<AnyElement> {
 9553        let menu = self.context_menu.borrow();
 9554        let menu = menu.as_ref()?;
 9555        if !menu.visible() {
 9556            return None;
 9557        };
 9558        Some(menu.render(style, max_height_in_lines, window, cx))
 9559    }
 9560
 9561    fn render_context_menu_aside(
 9562        &mut self,
 9563        max_size: Size<Pixels>,
 9564        window: &mut Window,
 9565        cx: &mut Context<Editor>,
 9566    ) -> Option<AnyElement> {
 9567        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9568            if menu.visible() {
 9569                menu.render_aside(max_size, window, cx)
 9570            } else {
 9571                None
 9572            }
 9573        })
 9574    }
 9575
 9576    fn hide_context_menu(
 9577        &mut self,
 9578        window: &mut Window,
 9579        cx: &mut Context<Self>,
 9580    ) -> Option<CodeContextMenu> {
 9581        cx.notify();
 9582        self.completion_tasks.clear();
 9583        let context_menu = self.context_menu.borrow_mut().take();
 9584        self.stale_edit_prediction_in_menu.take();
 9585        self.update_visible_edit_prediction(window, cx);
 9586        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9587            && let Some(completion_provider) = &self.completion_provider
 9588        {
 9589            completion_provider.selection_changed(None, window, cx);
 9590        }
 9591        context_menu
 9592    }
 9593
 9594    fn show_snippet_choices(
 9595        &mut self,
 9596        choices: &Vec<String>,
 9597        selection: Range<Anchor>,
 9598        cx: &mut Context<Self>,
 9599    ) {
 9600        let Some((_, buffer, _)) = self
 9601            .buffer()
 9602            .read(cx)
 9603            .excerpt_containing(selection.start, cx)
 9604        else {
 9605            return;
 9606        };
 9607        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9608        else {
 9609            return;
 9610        };
 9611        if buffer != end_buffer {
 9612            log::error!("expected anchor range to have matching buffer IDs");
 9613            return;
 9614        }
 9615
 9616        let id = post_inc(&mut self.next_completion_id);
 9617        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9618        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9619            CompletionsMenu::new_snippet_choices(
 9620                id,
 9621                true,
 9622                choices,
 9623                selection,
 9624                buffer,
 9625                snippet_sort_order,
 9626            ),
 9627        ));
 9628    }
 9629
 9630    pub fn insert_snippet(
 9631        &mut self,
 9632        insertion_ranges: &[Range<usize>],
 9633        snippet: Snippet,
 9634        window: &mut Window,
 9635        cx: &mut Context<Self>,
 9636    ) -> Result<()> {
 9637        struct Tabstop<T> {
 9638            is_end_tabstop: bool,
 9639            ranges: Vec<Range<T>>,
 9640            choices: Option<Vec<String>>,
 9641        }
 9642
 9643        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9644            let snippet_text: Arc<str> = snippet.text.clone().into();
 9645            let edits = insertion_ranges
 9646                .iter()
 9647                .cloned()
 9648                .map(|range| (range, snippet_text.clone()));
 9649            let autoindent_mode = AutoindentMode::Block {
 9650                original_indent_columns: Vec::new(),
 9651            };
 9652            buffer.edit(edits, Some(autoindent_mode), cx);
 9653
 9654            let snapshot = &*buffer.read(cx);
 9655            let snippet = &snippet;
 9656            snippet
 9657                .tabstops
 9658                .iter()
 9659                .map(|tabstop| {
 9660                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9661                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9662                    });
 9663                    let mut tabstop_ranges = tabstop
 9664                        .ranges
 9665                        .iter()
 9666                        .flat_map(|tabstop_range| {
 9667                            let mut delta = 0_isize;
 9668                            insertion_ranges.iter().map(move |insertion_range| {
 9669                                let insertion_start = insertion_range.start as isize + delta;
 9670                                delta +=
 9671                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9672
 9673                                let start = ((insertion_start + tabstop_range.start) as usize)
 9674                                    .min(snapshot.len());
 9675                                let end = ((insertion_start + tabstop_range.end) as usize)
 9676                                    .min(snapshot.len());
 9677                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9678                            })
 9679                        })
 9680                        .collect::<Vec<_>>();
 9681                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9682
 9683                    Tabstop {
 9684                        is_end_tabstop,
 9685                        ranges: tabstop_ranges,
 9686                        choices: tabstop.choices.clone(),
 9687                    }
 9688                })
 9689                .collect::<Vec<_>>()
 9690        });
 9691        if let Some(tabstop) = tabstops.first() {
 9692            self.change_selections(Default::default(), window, cx, |s| {
 9693                // Reverse order so that the first range is the newest created selection.
 9694                // Completions will use it and autoscroll will prioritize it.
 9695                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9696            });
 9697
 9698            if let Some(choices) = &tabstop.choices
 9699                && let Some(selection) = tabstop.ranges.first()
 9700            {
 9701                self.show_snippet_choices(choices, selection.clone(), cx)
 9702            }
 9703
 9704            // If we're already at the last tabstop and it's at the end of the snippet,
 9705            // we're done, we don't need to keep the state around.
 9706            if !tabstop.is_end_tabstop {
 9707                let choices = tabstops
 9708                    .iter()
 9709                    .map(|tabstop| tabstop.choices.clone())
 9710                    .collect();
 9711
 9712                let ranges = tabstops
 9713                    .into_iter()
 9714                    .map(|tabstop| tabstop.ranges)
 9715                    .collect::<Vec<_>>();
 9716
 9717                self.snippet_stack.push(SnippetState {
 9718                    active_index: 0,
 9719                    ranges,
 9720                    choices,
 9721                });
 9722            }
 9723
 9724            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9725            if self.autoclose_regions.is_empty() {
 9726                let snapshot = self.buffer.read(cx).snapshot(cx);
 9727                let mut all_selections = self.selections.all::<Point>(cx);
 9728                for selection in &mut all_selections {
 9729                    let selection_head = selection.head();
 9730                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9731                        continue;
 9732                    };
 9733
 9734                    let mut bracket_pair = None;
 9735                    let max_lookup_length = scope
 9736                        .brackets()
 9737                        .map(|(pair, _)| {
 9738                            pair.start
 9739                                .as_str()
 9740                                .chars()
 9741                                .count()
 9742                                .max(pair.end.as_str().chars().count())
 9743                        })
 9744                        .max();
 9745                    if let Some(max_lookup_length) = max_lookup_length {
 9746                        let next_text = snapshot
 9747                            .chars_at(selection_head)
 9748                            .take(max_lookup_length)
 9749                            .collect::<String>();
 9750                        let prev_text = snapshot
 9751                            .reversed_chars_at(selection_head)
 9752                            .take(max_lookup_length)
 9753                            .collect::<String>();
 9754
 9755                        for (pair, enabled) in scope.brackets() {
 9756                            if enabled
 9757                                && pair.close
 9758                                && prev_text.starts_with(pair.start.as_str())
 9759                                && next_text.starts_with(pair.end.as_str())
 9760                            {
 9761                                bracket_pair = Some(pair.clone());
 9762                                break;
 9763                            }
 9764                        }
 9765                    }
 9766
 9767                    if let Some(pair) = bracket_pair {
 9768                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9769                        let autoclose_enabled =
 9770                            self.use_autoclose && snapshot_settings.use_autoclose;
 9771                        if autoclose_enabled {
 9772                            let start = snapshot.anchor_after(selection_head);
 9773                            let end = snapshot.anchor_after(selection_head);
 9774                            self.autoclose_regions.push(AutocloseRegion {
 9775                                selection_id: selection.id,
 9776                                range: start..end,
 9777                                pair,
 9778                            });
 9779                        }
 9780                    }
 9781                }
 9782            }
 9783        }
 9784        Ok(())
 9785    }
 9786
 9787    pub fn move_to_next_snippet_tabstop(
 9788        &mut self,
 9789        window: &mut Window,
 9790        cx: &mut Context<Self>,
 9791    ) -> bool {
 9792        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9793    }
 9794
 9795    pub fn move_to_prev_snippet_tabstop(
 9796        &mut self,
 9797        window: &mut Window,
 9798        cx: &mut Context<Self>,
 9799    ) -> bool {
 9800        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9801    }
 9802
 9803    pub fn move_to_snippet_tabstop(
 9804        &mut self,
 9805        bias: Bias,
 9806        window: &mut Window,
 9807        cx: &mut Context<Self>,
 9808    ) -> bool {
 9809        if let Some(mut snippet) = self.snippet_stack.pop() {
 9810            match bias {
 9811                Bias::Left => {
 9812                    if snippet.active_index > 0 {
 9813                        snippet.active_index -= 1;
 9814                    } else {
 9815                        self.snippet_stack.push(snippet);
 9816                        return false;
 9817                    }
 9818                }
 9819                Bias::Right => {
 9820                    if snippet.active_index + 1 < snippet.ranges.len() {
 9821                        snippet.active_index += 1;
 9822                    } else {
 9823                        self.snippet_stack.push(snippet);
 9824                        return false;
 9825                    }
 9826                }
 9827            }
 9828            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9829                self.change_selections(Default::default(), window, cx, |s| {
 9830                    // Reverse order so that the first range is the newest created selection.
 9831                    // Completions will use it and autoscroll will prioritize it.
 9832                    s.select_ranges(current_ranges.iter().rev().cloned())
 9833                });
 9834
 9835                if let Some(choices) = &snippet.choices[snippet.active_index]
 9836                    && let Some(selection) = current_ranges.first()
 9837                {
 9838                    self.show_snippet_choices(choices, selection.clone(), cx);
 9839                }
 9840
 9841                // If snippet state is not at the last tabstop, push it back on the stack
 9842                if snippet.active_index + 1 < snippet.ranges.len() {
 9843                    self.snippet_stack.push(snippet);
 9844                }
 9845                return true;
 9846            }
 9847        }
 9848
 9849        false
 9850    }
 9851
 9852    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_all(&SelectAll, window, cx);
 9855            this.insert("", window, cx);
 9856        });
 9857    }
 9858
 9859    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9860        if self.read_only(cx) {
 9861            return;
 9862        }
 9863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9864        self.transact(window, cx, |this, window, cx| {
 9865            this.select_autoclose_pair(window, cx);
 9866            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9867            if !this.linked_edit_ranges.is_empty() {
 9868                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9869                let snapshot = this.buffer.read(cx).snapshot(cx);
 9870
 9871                for selection in selections.iter() {
 9872                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9873                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9874                    if selection_start.buffer_id != selection_end.buffer_id {
 9875                        continue;
 9876                    }
 9877                    if let Some(ranges) =
 9878                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9879                    {
 9880                        for (buffer, entries) in ranges {
 9881                            linked_ranges.entry(buffer).or_default().extend(entries);
 9882                        }
 9883                    }
 9884                }
 9885            }
 9886
 9887            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9888            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9889            for selection in &mut selections {
 9890                if selection.is_empty() {
 9891                    let old_head = selection.head();
 9892                    let mut new_head =
 9893                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9894                            .to_point(&display_map);
 9895                    if let Some((buffer, line_buffer_range)) = display_map
 9896                        .buffer_snapshot
 9897                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9898                    {
 9899                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9900                        let indent_len = match indent_size.kind {
 9901                            IndentKind::Space => {
 9902                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9903                            }
 9904                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9905                        };
 9906                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9907                            let indent_len = indent_len.get();
 9908                            new_head = cmp::min(
 9909                                new_head,
 9910                                MultiBufferPoint::new(
 9911                                    old_head.row,
 9912                                    ((old_head.column - 1) / indent_len) * indent_len,
 9913                                ),
 9914                            );
 9915                        }
 9916                    }
 9917
 9918                    selection.set_head(new_head, SelectionGoal::None);
 9919                }
 9920            }
 9921
 9922            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9923            this.insert("", window, cx);
 9924            let empty_str: Arc<str> = Arc::from("");
 9925            for (buffer, edits) in linked_ranges {
 9926                let snapshot = buffer.read(cx).snapshot();
 9927                use text::ToPoint as TP;
 9928
 9929                let edits = edits
 9930                    .into_iter()
 9931                    .map(|range| {
 9932                        let end_point = TP::to_point(&range.end, &snapshot);
 9933                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9934
 9935                        if end_point == start_point {
 9936                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9937                                .saturating_sub(1);
 9938                            start_point =
 9939                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9940                        };
 9941
 9942                        (start_point..end_point, empty_str.clone())
 9943                    })
 9944                    .sorted_by_key(|(range, _)| range.start)
 9945                    .collect::<Vec<_>>();
 9946                buffer.update(cx, |this, cx| {
 9947                    this.edit(edits, None, cx);
 9948                })
 9949            }
 9950            this.refresh_edit_prediction(true, false, window, cx);
 9951            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9952        });
 9953    }
 9954
 9955    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9956        if self.read_only(cx) {
 9957            return;
 9958        }
 9959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9960        self.transact(window, cx, |this, window, cx| {
 9961            this.change_selections(Default::default(), window, cx, |s| {
 9962                s.move_with(|map, selection| {
 9963                    if selection.is_empty() {
 9964                        let cursor = movement::right(map, selection.head());
 9965                        selection.end = cursor;
 9966                        selection.reversed = true;
 9967                        selection.goal = SelectionGoal::None;
 9968                    }
 9969                })
 9970            });
 9971            this.insert("", window, cx);
 9972            this.refresh_edit_prediction(true, false, window, cx);
 9973        });
 9974    }
 9975
 9976    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9977        if self.mode.is_single_line() {
 9978            cx.propagate();
 9979            return;
 9980        }
 9981
 9982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9983        if self.move_to_prev_snippet_tabstop(window, cx) {
 9984            return;
 9985        }
 9986        self.outdent(&Outdent, window, cx);
 9987    }
 9988
 9989    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9990        if self.mode.is_single_line() {
 9991            cx.propagate();
 9992            return;
 9993        }
 9994
 9995        if self.move_to_next_snippet_tabstop(window, cx) {
 9996            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9997            return;
 9998        }
 9999        if self.read_only(cx) {
10000            return;
10001        }
10002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10003        let mut selections = self.selections.all_adjusted(cx);
10004        let buffer = self.buffer.read(cx);
10005        let snapshot = buffer.snapshot(cx);
10006        let rows_iter = selections.iter().map(|s| s.head().row);
10007        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10008
10009        let has_some_cursor_in_whitespace = selections
10010            .iter()
10011            .filter(|selection| selection.is_empty())
10012            .any(|selection| {
10013                let cursor = selection.head();
10014                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10015                cursor.column < current_indent.len
10016            });
10017
10018        let mut edits = Vec::new();
10019        let mut prev_edited_row = 0;
10020        let mut row_delta = 0;
10021        for selection in &mut selections {
10022            if selection.start.row != prev_edited_row {
10023                row_delta = 0;
10024            }
10025            prev_edited_row = selection.end.row;
10026
10027            // If the selection is non-empty, then increase the indentation of the selected lines.
10028            if !selection.is_empty() {
10029                row_delta =
10030                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10031                continue;
10032            }
10033
10034            let cursor = selection.head();
10035            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10036            if let Some(suggested_indent) =
10037                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10038            {
10039                // Don't do anything if already at suggested indent
10040                // and there is any other cursor which is not
10041                if has_some_cursor_in_whitespace
10042                    && cursor.column == current_indent.len
10043                    && current_indent.len == suggested_indent.len
10044                {
10045                    continue;
10046                }
10047
10048                // Adjust line and move cursor to suggested indent
10049                // if cursor is not at suggested indent
10050                if cursor.column < suggested_indent.len
10051                    && cursor.column <= current_indent.len
10052                    && current_indent.len <= suggested_indent.len
10053                {
10054                    selection.start = Point::new(cursor.row, suggested_indent.len);
10055                    selection.end = selection.start;
10056                    if row_delta == 0 {
10057                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10058                            cursor.row,
10059                            current_indent,
10060                            suggested_indent,
10061                        ));
10062                        row_delta = suggested_indent.len - current_indent.len;
10063                    }
10064                    continue;
10065                }
10066
10067                // If current indent is more than suggested indent
10068                // only move cursor to current indent and skip indent
10069                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10070                    selection.start = Point::new(cursor.row, current_indent.len);
10071                    selection.end = selection.start;
10072                    continue;
10073                }
10074            }
10075
10076            // Otherwise, insert a hard or soft tab.
10077            let settings = buffer.language_settings_at(cursor, cx);
10078            let tab_size = if settings.hard_tabs {
10079                IndentSize::tab()
10080            } else {
10081                let tab_size = settings.tab_size.get();
10082                let indent_remainder = snapshot
10083                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10084                    .flat_map(str::chars)
10085                    .fold(row_delta % tab_size, |counter: u32, c| {
10086                        if c == '\t' {
10087                            0
10088                        } else {
10089                            (counter + 1) % tab_size
10090                        }
10091                    });
10092
10093                let chars_to_next_tab_stop = tab_size - indent_remainder;
10094                IndentSize::spaces(chars_to_next_tab_stop)
10095            };
10096            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10097            selection.end = selection.start;
10098            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10099            row_delta += tab_size.len;
10100        }
10101
10102        self.transact(window, cx, |this, window, cx| {
10103            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10104            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10105            this.refresh_edit_prediction(true, false, window, cx);
10106        });
10107    }
10108
10109    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10110        if self.read_only(cx) {
10111            return;
10112        }
10113        if self.mode.is_single_line() {
10114            cx.propagate();
10115            return;
10116        }
10117
10118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10119        let mut selections = self.selections.all::<Point>(cx);
10120        let mut prev_edited_row = 0;
10121        let mut row_delta = 0;
10122        let mut edits = Vec::new();
10123        let buffer = self.buffer.read(cx);
10124        let snapshot = buffer.snapshot(cx);
10125        for selection in &mut selections {
10126            if selection.start.row != prev_edited_row {
10127                row_delta = 0;
10128            }
10129            prev_edited_row = selection.end.row;
10130
10131            row_delta =
10132                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10133        }
10134
10135        self.transact(window, cx, |this, window, cx| {
10136            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10137            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10138        });
10139    }
10140
10141    fn indent_selection(
10142        buffer: &MultiBuffer,
10143        snapshot: &MultiBufferSnapshot,
10144        selection: &mut Selection<Point>,
10145        edits: &mut Vec<(Range<Point>, String)>,
10146        delta_for_start_row: u32,
10147        cx: &App,
10148    ) -> u32 {
10149        let settings = buffer.language_settings_at(selection.start, cx);
10150        let tab_size = settings.tab_size.get();
10151        let indent_kind = if settings.hard_tabs {
10152            IndentKind::Tab
10153        } else {
10154            IndentKind::Space
10155        };
10156        let mut start_row = selection.start.row;
10157        let mut end_row = selection.end.row + 1;
10158
10159        // If a selection ends at the beginning of a line, don't indent
10160        // that last line.
10161        if selection.end.column == 0 && selection.end.row > selection.start.row {
10162            end_row -= 1;
10163        }
10164
10165        // Avoid re-indenting a row that has already been indented by a
10166        // previous selection, but still update this selection's column
10167        // to reflect that indentation.
10168        if delta_for_start_row > 0 {
10169            start_row += 1;
10170            selection.start.column += delta_for_start_row;
10171            if selection.end.row == selection.start.row {
10172                selection.end.column += delta_for_start_row;
10173            }
10174        }
10175
10176        let mut delta_for_end_row = 0;
10177        let has_multiple_rows = start_row + 1 != end_row;
10178        for row in start_row..end_row {
10179            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10180            let indent_delta = match (current_indent.kind, indent_kind) {
10181                (IndentKind::Space, IndentKind::Space) => {
10182                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10183                    IndentSize::spaces(columns_to_next_tab_stop)
10184                }
10185                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10186                (_, IndentKind::Tab) => IndentSize::tab(),
10187            };
10188
10189            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10190                0
10191            } else {
10192                selection.start.column
10193            };
10194            let row_start = Point::new(row, start);
10195            edits.push((
10196                row_start..row_start,
10197                indent_delta.chars().collect::<String>(),
10198            ));
10199
10200            // Update this selection's endpoints to reflect the indentation.
10201            if row == selection.start.row {
10202                selection.start.column += indent_delta.len;
10203            }
10204            if row == selection.end.row {
10205                selection.end.column += indent_delta.len;
10206                delta_for_end_row = indent_delta.len;
10207            }
10208        }
10209
10210        if selection.start.row == selection.end.row {
10211            delta_for_start_row + delta_for_end_row
10212        } else {
10213            delta_for_end_row
10214        }
10215    }
10216
10217    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10218        if self.read_only(cx) {
10219            return;
10220        }
10221        if self.mode.is_single_line() {
10222            cx.propagate();
10223            return;
10224        }
10225
10226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10228        let selections = self.selections.all::<Point>(cx);
10229        let mut deletion_ranges = Vec::new();
10230        let mut last_outdent = None;
10231        {
10232            let buffer = self.buffer.read(cx);
10233            let snapshot = buffer.snapshot(cx);
10234            for selection in &selections {
10235                let settings = buffer.language_settings_at(selection.start, cx);
10236                let tab_size = settings.tab_size.get();
10237                let mut rows = selection.spanned_rows(false, &display_map);
10238
10239                // Avoid re-outdenting a row that has already been outdented by a
10240                // previous selection.
10241                if let Some(last_row) = last_outdent
10242                    && last_row == rows.start
10243                {
10244                    rows.start = rows.start.next_row();
10245                }
10246                let has_multiple_rows = rows.len() > 1;
10247                for row in rows.iter_rows() {
10248                    let indent_size = snapshot.indent_size_for_line(row);
10249                    if indent_size.len > 0 {
10250                        let deletion_len = match indent_size.kind {
10251                            IndentKind::Space => {
10252                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10253                                if columns_to_prev_tab_stop == 0 {
10254                                    tab_size
10255                                } else {
10256                                    columns_to_prev_tab_stop
10257                                }
10258                            }
10259                            IndentKind::Tab => 1,
10260                        };
10261                        let start = if has_multiple_rows
10262                            || deletion_len > selection.start.column
10263                            || indent_size.len < selection.start.column
10264                        {
10265                            0
10266                        } else {
10267                            selection.start.column - deletion_len
10268                        };
10269                        deletion_ranges.push(
10270                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10271                        );
10272                        last_outdent = Some(row);
10273                    }
10274                }
10275            }
10276        }
10277
10278        self.transact(window, cx, |this, window, cx| {
10279            this.buffer.update(cx, |buffer, cx| {
10280                let empty_str: Arc<str> = Arc::default();
10281                buffer.edit(
10282                    deletion_ranges
10283                        .into_iter()
10284                        .map(|range| (range, empty_str.clone())),
10285                    None,
10286                    cx,
10287                );
10288            });
10289            let selections = this.selections.all::<usize>(cx);
10290            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10291        });
10292    }
10293
10294    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10295        if self.read_only(cx) {
10296            return;
10297        }
10298        if self.mode.is_single_line() {
10299            cx.propagate();
10300            return;
10301        }
10302
10303        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10304        let selections = self
10305            .selections
10306            .all::<usize>(cx)
10307            .into_iter()
10308            .map(|s| s.range());
10309
10310        self.transact(window, cx, |this, window, cx| {
10311            this.buffer.update(cx, |buffer, cx| {
10312                buffer.autoindent_ranges(selections, cx);
10313            });
10314            let selections = this.selections.all::<usize>(cx);
10315            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10316        });
10317    }
10318
10319    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10321        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10322        let selections = self.selections.all::<Point>(cx);
10323
10324        let mut new_cursors = Vec::new();
10325        let mut edit_ranges = Vec::new();
10326        let mut selections = selections.iter().peekable();
10327        while let Some(selection) = selections.next() {
10328            let mut rows = selection.spanned_rows(false, &display_map);
10329            let goal_display_column = selection.head().to_display_point(&display_map).column();
10330
10331            // Accumulate contiguous regions of rows that we want to delete.
10332            while let Some(next_selection) = selections.peek() {
10333                let next_rows = next_selection.spanned_rows(false, &display_map);
10334                if next_rows.start <= rows.end {
10335                    rows.end = next_rows.end;
10336                    selections.next().unwrap();
10337                } else {
10338                    break;
10339                }
10340            }
10341
10342            let buffer = &display_map.buffer_snapshot;
10343            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10344            let edit_end;
10345            let cursor_buffer_row;
10346            if buffer.max_point().row >= rows.end.0 {
10347                // If there's a line after the range, delete the \n from the end of the row range
10348                // and position the cursor on the next line.
10349                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10350                cursor_buffer_row = rows.end;
10351            } else {
10352                // If there isn't a line after the range, delete the \n from the line before the
10353                // start of the row range and position the cursor there.
10354                edit_start = edit_start.saturating_sub(1);
10355                edit_end = buffer.len();
10356                cursor_buffer_row = rows.start.previous_row();
10357            }
10358
10359            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10360            *cursor.column_mut() =
10361                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10362
10363            new_cursors.push((
10364                selection.id,
10365                buffer.anchor_after(cursor.to_point(&display_map)),
10366            ));
10367            edit_ranges.push(edit_start..edit_end);
10368        }
10369
10370        self.transact(window, cx, |this, window, cx| {
10371            let buffer = this.buffer.update(cx, |buffer, cx| {
10372                let empty_str: Arc<str> = Arc::default();
10373                buffer.edit(
10374                    edit_ranges
10375                        .into_iter()
10376                        .map(|range| (range, empty_str.clone())),
10377                    None,
10378                    cx,
10379                );
10380                buffer.snapshot(cx)
10381            });
10382            let new_selections = new_cursors
10383                .into_iter()
10384                .map(|(id, cursor)| {
10385                    let cursor = cursor.to_point(&buffer);
10386                    Selection {
10387                        id,
10388                        start: cursor,
10389                        end: cursor,
10390                        reversed: false,
10391                        goal: SelectionGoal::None,
10392                    }
10393                })
10394                .collect();
10395
10396            this.change_selections(Default::default(), window, cx, |s| {
10397                s.select(new_selections);
10398            });
10399        });
10400    }
10401
10402    pub fn join_lines_impl(
10403        &mut self,
10404        insert_whitespace: bool,
10405        window: &mut Window,
10406        cx: &mut Context<Self>,
10407    ) {
10408        if self.read_only(cx) {
10409            return;
10410        }
10411        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10412        for selection in self.selections.all::<Point>(cx) {
10413            let start = MultiBufferRow(selection.start.row);
10414            // Treat single line selections as if they include the next line. Otherwise this action
10415            // would do nothing for single line selections individual cursors.
10416            let end = if selection.start.row == selection.end.row {
10417                MultiBufferRow(selection.start.row + 1)
10418            } else {
10419                MultiBufferRow(selection.end.row)
10420            };
10421
10422            if let Some(last_row_range) = row_ranges.last_mut()
10423                && start <= last_row_range.end
10424            {
10425                last_row_range.end = end;
10426                continue;
10427            }
10428            row_ranges.push(start..end);
10429        }
10430
10431        let snapshot = self.buffer.read(cx).snapshot(cx);
10432        let mut cursor_positions = Vec::new();
10433        for row_range in &row_ranges {
10434            let anchor = snapshot.anchor_before(Point::new(
10435                row_range.end.previous_row().0,
10436                snapshot.line_len(row_range.end.previous_row()),
10437            ));
10438            cursor_positions.push(anchor..anchor);
10439        }
10440
10441        self.transact(window, cx, |this, window, cx| {
10442            for row_range in row_ranges.into_iter().rev() {
10443                for row in row_range.iter_rows().rev() {
10444                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10445                    let next_line_row = row.next_row();
10446                    let indent = snapshot.indent_size_for_line(next_line_row);
10447                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10448
10449                    let replace =
10450                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10451                            " "
10452                        } else {
10453                            ""
10454                        };
10455
10456                    this.buffer.update(cx, |buffer, cx| {
10457                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10458                    });
10459                }
10460            }
10461
10462            this.change_selections(Default::default(), window, cx, |s| {
10463                s.select_anchor_ranges(cursor_positions)
10464            });
10465        });
10466    }
10467
10468    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10470        self.join_lines_impl(true, window, cx);
10471    }
10472
10473    pub fn sort_lines_case_sensitive(
10474        &mut self,
10475        _: &SortLinesCaseSensitive,
10476        window: &mut Window,
10477        cx: &mut Context<Self>,
10478    ) {
10479        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10480    }
10481
10482    pub fn sort_lines_by_length(
10483        &mut self,
10484        _: &SortLinesByLength,
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.chars().count())
10490        })
10491    }
10492
10493    pub fn sort_lines_case_insensitive(
10494        &mut self,
10495        _: &SortLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            lines.sort_by_key(|line| line.to_lowercase())
10501        })
10502    }
10503
10504    pub fn unique_lines_case_insensitive(
10505        &mut self,
10506        _: &UniqueLinesCaseInsensitive,
10507        window: &mut Window,
10508        cx: &mut Context<Self>,
10509    ) {
10510        self.manipulate_immutable_lines(window, cx, |lines| {
10511            let mut seen = HashSet::default();
10512            lines.retain(|line| seen.insert(line.to_lowercase()));
10513        })
10514    }
10515
10516    pub fn unique_lines_case_sensitive(
10517        &mut self,
10518        _: &UniqueLinesCaseSensitive,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        self.manipulate_immutable_lines(window, cx, |lines| {
10523            let mut seen = HashSet::default();
10524            lines.retain(|line| seen.insert(*line));
10525        })
10526    }
10527
10528    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10529        let snapshot = self.buffer.read(cx).snapshot(cx);
10530        for selection in self.selections.disjoint_anchors_arc().iter() {
10531            if snapshot
10532                .language_at(selection.start)
10533                .and_then(|lang| lang.config().wrap_characters.as_ref())
10534                .is_some()
10535            {
10536                return true;
10537            }
10538        }
10539        false
10540    }
10541
10542    fn wrap_selections_in_tag(
10543        &mut self,
10544        _: &WrapSelectionsInTag,
10545        window: &mut Window,
10546        cx: &mut Context<Self>,
10547    ) {
10548        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10549
10550        let snapshot = self.buffer.read(cx).snapshot(cx);
10551
10552        let mut edits = Vec::new();
10553        let mut boundaries = Vec::new();
10554
10555        for selection in self.selections.all::<Point>(cx).iter() {
10556            let Some(wrap_config) = snapshot
10557                .language_at(selection.start)
10558                .and_then(|lang| lang.config().wrap_characters.clone())
10559            else {
10560                continue;
10561            };
10562
10563            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10564            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10565
10566            let start_before = snapshot.anchor_before(selection.start);
10567            let end_after = snapshot.anchor_after(selection.end);
10568
10569            edits.push((start_before..start_before, open_tag));
10570            edits.push((end_after..end_after, close_tag));
10571
10572            boundaries.push((
10573                start_before,
10574                end_after,
10575                wrap_config.start_prefix.len(),
10576                wrap_config.end_suffix.len(),
10577            ));
10578        }
10579
10580        if edits.is_empty() {
10581            return;
10582        }
10583
10584        self.transact(window, cx, |this, window, cx| {
10585            let buffer = this.buffer.update(cx, |buffer, cx| {
10586                buffer.edit(edits, None, cx);
10587                buffer.snapshot(cx)
10588            });
10589
10590            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10591            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10592                boundaries.into_iter()
10593            {
10594                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10595                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10596                new_selections.push(open_offset..open_offset);
10597                new_selections.push(close_offset..close_offset);
10598            }
10599
10600            this.change_selections(Default::default(), window, cx, |s| {
10601                s.select_ranges(new_selections);
10602            });
10603
10604            this.request_autoscroll(Autoscroll::fit(), cx);
10605        });
10606    }
10607
10608    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10609        let Some(project) = self.project.clone() else {
10610            return;
10611        };
10612        self.reload(project, window, cx)
10613            .detach_and_notify_err(window, cx);
10614    }
10615
10616    pub fn restore_file(
10617        &mut self,
10618        _: &::git::RestoreFile,
10619        window: &mut Window,
10620        cx: &mut Context<Self>,
10621    ) {
10622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10623        let mut buffer_ids = HashSet::default();
10624        let snapshot = self.buffer().read(cx).snapshot(cx);
10625        for selection in self.selections.all::<usize>(cx) {
10626            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10627        }
10628
10629        let buffer = self.buffer().read(cx);
10630        let ranges = buffer_ids
10631            .into_iter()
10632            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10633            .collect::<Vec<_>>();
10634
10635        self.restore_hunks_in_ranges(ranges, window, cx);
10636    }
10637
10638    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10640        let selections = self
10641            .selections
10642            .all(cx)
10643            .into_iter()
10644            .map(|s| s.range())
10645            .collect();
10646        self.restore_hunks_in_ranges(selections, window, cx);
10647    }
10648
10649    pub fn restore_hunks_in_ranges(
10650        &mut self,
10651        ranges: Vec<Range<Point>>,
10652        window: &mut Window,
10653        cx: &mut Context<Editor>,
10654    ) {
10655        let mut revert_changes = HashMap::default();
10656        let chunk_by = self
10657            .snapshot(window, cx)
10658            .hunks_for_ranges(ranges)
10659            .into_iter()
10660            .chunk_by(|hunk| hunk.buffer_id);
10661        for (buffer_id, hunks) in &chunk_by {
10662            let hunks = hunks.collect::<Vec<_>>();
10663            for hunk in &hunks {
10664                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10665            }
10666            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10667        }
10668        drop(chunk_by);
10669        if !revert_changes.is_empty() {
10670            self.transact(window, cx, |editor, window, cx| {
10671                editor.restore(revert_changes, window, cx);
10672            });
10673        }
10674    }
10675
10676    pub fn open_active_item_in_terminal(
10677        &mut self,
10678        _: &OpenInTerminal,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10683            let project_path = buffer.read(cx).project_path(cx)?;
10684            let project = self.project()?.read(cx);
10685            let entry = project.entry_for_path(&project_path, cx)?;
10686            let parent = match &entry.canonical_path {
10687                Some(canonical_path) => canonical_path.to_path_buf(),
10688                None => project.absolute_path(&project_path, cx)?,
10689            }
10690            .parent()?
10691            .to_path_buf();
10692            Some(parent)
10693        }) {
10694            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10695        }
10696    }
10697
10698    fn set_breakpoint_context_menu(
10699        &mut self,
10700        display_row: DisplayRow,
10701        position: Option<Anchor>,
10702        clicked_point: gpui::Point<Pixels>,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        let source = self
10707            .buffer
10708            .read(cx)
10709            .snapshot(cx)
10710            .anchor_before(Point::new(display_row.0, 0u32));
10711
10712        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10713
10714        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10715            self,
10716            source,
10717            clicked_point,
10718            context_menu,
10719            window,
10720            cx,
10721        );
10722    }
10723
10724    fn add_edit_breakpoint_block(
10725        &mut self,
10726        anchor: Anchor,
10727        breakpoint: &Breakpoint,
10728        edit_action: BreakpointPromptEditAction,
10729        window: &mut Window,
10730        cx: &mut Context<Self>,
10731    ) {
10732        let weak_editor = cx.weak_entity();
10733        let bp_prompt = cx.new(|cx| {
10734            BreakpointPromptEditor::new(
10735                weak_editor,
10736                anchor,
10737                breakpoint.clone(),
10738                edit_action,
10739                window,
10740                cx,
10741            )
10742        });
10743
10744        let height = bp_prompt.update(cx, |this, cx| {
10745            this.prompt
10746                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10747        });
10748        let cloned_prompt = bp_prompt.clone();
10749        let blocks = vec![BlockProperties {
10750            style: BlockStyle::Sticky,
10751            placement: BlockPlacement::Above(anchor),
10752            height: Some(height),
10753            render: Arc::new(move |cx| {
10754                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10755                cloned_prompt.clone().into_any_element()
10756            }),
10757            priority: 0,
10758        }];
10759
10760        let focus_handle = bp_prompt.focus_handle(cx);
10761        window.focus(&focus_handle);
10762
10763        let block_ids = self.insert_blocks(blocks, None, cx);
10764        bp_prompt.update(cx, |prompt, _| {
10765            prompt.add_block_ids(block_ids);
10766        });
10767    }
10768
10769    pub(crate) fn breakpoint_at_row(
10770        &self,
10771        row: u32,
10772        window: &mut Window,
10773        cx: &mut Context<Self>,
10774    ) -> Option<(Anchor, Breakpoint)> {
10775        let snapshot = self.snapshot(window, cx);
10776        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10777
10778        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10779    }
10780
10781    pub(crate) fn breakpoint_at_anchor(
10782        &self,
10783        breakpoint_position: Anchor,
10784        snapshot: &EditorSnapshot,
10785        cx: &mut Context<Self>,
10786    ) -> Option<(Anchor, Breakpoint)> {
10787        let buffer = self
10788            .buffer
10789            .read(cx)
10790            .buffer_for_anchor(breakpoint_position, cx)?;
10791
10792        let enclosing_excerpt = breakpoint_position.excerpt_id;
10793        let buffer_snapshot = buffer.read(cx).snapshot();
10794
10795        let row = buffer_snapshot
10796            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10797            .row;
10798
10799        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10800        let anchor_end = snapshot
10801            .buffer_snapshot
10802            .anchor_after(Point::new(row, line_len));
10803
10804        self.breakpoint_store
10805            .as_ref()?
10806            .read_with(cx, |breakpoint_store, cx| {
10807                breakpoint_store
10808                    .breakpoints(
10809                        &buffer,
10810                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10811                        &buffer_snapshot,
10812                        cx,
10813                    )
10814                    .next()
10815                    .and_then(|(bp, _)| {
10816                        let breakpoint_row = buffer_snapshot
10817                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10818                            .row;
10819
10820                        if breakpoint_row == row {
10821                            snapshot
10822                                .buffer_snapshot
10823                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10824                                .map(|position| (position, bp.bp.clone()))
10825                        } else {
10826                            None
10827                        }
10828                    })
10829            })
10830    }
10831
10832    pub fn edit_log_breakpoint(
10833        &mut self,
10834        _: &EditLogBreakpoint,
10835        window: &mut Window,
10836        cx: &mut Context<Self>,
10837    ) {
10838        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10839            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10840                message: None,
10841                state: BreakpointState::Enabled,
10842                condition: None,
10843                hit_condition: None,
10844            });
10845
10846            self.add_edit_breakpoint_block(
10847                anchor,
10848                &breakpoint,
10849                BreakpointPromptEditAction::Log,
10850                window,
10851                cx,
10852            );
10853        }
10854    }
10855
10856    fn breakpoints_at_cursors(
10857        &self,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10861        let snapshot = self.snapshot(window, cx);
10862        let cursors = self
10863            .selections
10864            .disjoint_anchors_arc()
10865            .iter()
10866            .map(|selection| {
10867                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10868
10869                let breakpoint_position = self
10870                    .breakpoint_at_row(cursor_position.row, window, cx)
10871                    .map(|bp| bp.0)
10872                    .unwrap_or_else(|| {
10873                        snapshot
10874                            .display_snapshot
10875                            .buffer_snapshot
10876                            .anchor_after(Point::new(cursor_position.row, 0))
10877                    });
10878
10879                let breakpoint = self
10880                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10881                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10882
10883                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10884            })
10885            // 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.
10886            .collect::<HashMap<Anchor, _>>();
10887
10888        cursors.into_iter().collect()
10889    }
10890
10891    pub fn enable_breakpoint(
10892        &mut self,
10893        _: &crate::actions::EnableBreakpoint,
10894        window: &mut Window,
10895        cx: &mut Context<Self>,
10896    ) {
10897        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10898            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10899                continue;
10900            };
10901            self.edit_breakpoint_at_anchor(
10902                anchor,
10903                breakpoint,
10904                BreakpointEditAction::InvertState,
10905                cx,
10906            );
10907        }
10908    }
10909
10910    pub fn disable_breakpoint(
10911        &mut self,
10912        _: &crate::actions::DisableBreakpoint,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10917            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10918                continue;
10919            };
10920            self.edit_breakpoint_at_anchor(
10921                anchor,
10922                breakpoint,
10923                BreakpointEditAction::InvertState,
10924                cx,
10925            );
10926        }
10927    }
10928
10929    pub fn toggle_breakpoint(
10930        &mut self,
10931        _: &crate::actions::ToggleBreakpoint,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) {
10935        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10936            if let Some(breakpoint) = breakpoint {
10937                self.edit_breakpoint_at_anchor(
10938                    anchor,
10939                    breakpoint,
10940                    BreakpointEditAction::Toggle,
10941                    cx,
10942                );
10943            } else {
10944                self.edit_breakpoint_at_anchor(
10945                    anchor,
10946                    Breakpoint::new_standard(),
10947                    BreakpointEditAction::Toggle,
10948                    cx,
10949                );
10950            }
10951        }
10952    }
10953
10954    pub fn edit_breakpoint_at_anchor(
10955        &mut self,
10956        breakpoint_position: Anchor,
10957        breakpoint: Breakpoint,
10958        edit_action: BreakpointEditAction,
10959        cx: &mut Context<Self>,
10960    ) {
10961        let Some(breakpoint_store) = &self.breakpoint_store else {
10962            return;
10963        };
10964
10965        let Some(buffer) = self
10966            .buffer
10967            .read(cx)
10968            .buffer_for_anchor(breakpoint_position, cx)
10969        else {
10970            return;
10971        };
10972
10973        breakpoint_store.update(cx, |breakpoint_store, cx| {
10974            breakpoint_store.toggle_breakpoint(
10975                buffer,
10976                BreakpointWithPosition {
10977                    position: breakpoint_position.text_anchor,
10978                    bp: breakpoint,
10979                },
10980                edit_action,
10981                cx,
10982            );
10983        });
10984
10985        cx.notify();
10986    }
10987
10988    #[cfg(any(test, feature = "test-support"))]
10989    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10990        self.breakpoint_store.clone()
10991    }
10992
10993    pub fn prepare_restore_change(
10994        &self,
10995        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10996        hunk: &MultiBufferDiffHunk,
10997        cx: &mut App,
10998    ) -> Option<()> {
10999        if hunk.is_created_file() {
11000            return None;
11001        }
11002        let buffer = self.buffer.read(cx);
11003        let diff = buffer.diff_for(hunk.buffer_id)?;
11004        let buffer = buffer.buffer(hunk.buffer_id)?;
11005        let buffer = buffer.read(cx);
11006        let original_text = diff
11007            .read(cx)
11008            .base_text()
11009            .as_rope()
11010            .slice(hunk.diff_base_byte_range.clone());
11011        let buffer_snapshot = buffer.snapshot();
11012        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11013        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11014            probe
11015                .0
11016                .start
11017                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11018                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11019        }) {
11020            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11021            Some(())
11022        } else {
11023            None
11024        }
11025    }
11026
11027    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11028        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11029    }
11030
11031    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11032        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11033    }
11034
11035    fn manipulate_lines<M>(
11036        &mut self,
11037        window: &mut Window,
11038        cx: &mut Context<Self>,
11039        mut manipulate: M,
11040    ) where
11041        M: FnMut(&str) -> LineManipulationResult,
11042    {
11043        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11044
11045        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11046        let buffer = self.buffer.read(cx).snapshot(cx);
11047
11048        let mut edits = Vec::new();
11049
11050        let selections = self.selections.all::<Point>(cx);
11051        let mut selections = selections.iter().peekable();
11052        let mut contiguous_row_selections = Vec::new();
11053        let mut new_selections = Vec::new();
11054        let mut added_lines = 0;
11055        let mut removed_lines = 0;
11056
11057        while let Some(selection) = selections.next() {
11058            let (start_row, end_row) = consume_contiguous_rows(
11059                &mut contiguous_row_selections,
11060                selection,
11061                &display_map,
11062                &mut selections,
11063            );
11064
11065            let start_point = Point::new(start_row.0, 0);
11066            let end_point = Point::new(
11067                end_row.previous_row().0,
11068                buffer.line_len(end_row.previous_row()),
11069            );
11070            let text = buffer
11071                .text_for_range(start_point..end_point)
11072                .collect::<String>();
11073
11074            let LineManipulationResult {
11075                new_text,
11076                line_count_before,
11077                line_count_after,
11078            } = manipulate(&text);
11079
11080            edits.push((start_point..end_point, new_text));
11081
11082            // Selections must change based on added and removed line count
11083            let start_row =
11084                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11085            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11086            new_selections.push(Selection {
11087                id: selection.id,
11088                start: start_row,
11089                end: end_row,
11090                goal: SelectionGoal::None,
11091                reversed: selection.reversed,
11092            });
11093
11094            if line_count_after > line_count_before {
11095                added_lines += line_count_after - line_count_before;
11096            } else if line_count_before > line_count_after {
11097                removed_lines += line_count_before - line_count_after;
11098            }
11099        }
11100
11101        self.transact(window, cx, |this, window, cx| {
11102            let buffer = this.buffer.update(cx, |buffer, cx| {
11103                buffer.edit(edits, None, cx);
11104                buffer.snapshot(cx)
11105            });
11106
11107            // Recalculate offsets on newly edited buffer
11108            let new_selections = new_selections
11109                .iter()
11110                .map(|s| {
11111                    let start_point = Point::new(s.start.0, 0);
11112                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11113                    Selection {
11114                        id: s.id,
11115                        start: buffer.point_to_offset(start_point),
11116                        end: buffer.point_to_offset(end_point),
11117                        goal: s.goal,
11118                        reversed: s.reversed,
11119                    }
11120                })
11121                .collect();
11122
11123            this.change_selections(Default::default(), window, cx, |s| {
11124                s.select(new_selections);
11125            });
11126
11127            this.request_autoscroll(Autoscroll::fit(), cx);
11128        });
11129    }
11130
11131    fn manipulate_immutable_lines<Fn>(
11132        &mut self,
11133        window: &mut Window,
11134        cx: &mut Context<Self>,
11135        mut callback: Fn,
11136    ) where
11137        Fn: FnMut(&mut Vec<&str>),
11138    {
11139        self.manipulate_lines(window, cx, |text| {
11140            let mut lines: Vec<&str> = text.split('\n').collect();
11141            let line_count_before = lines.len();
11142
11143            callback(&mut lines);
11144
11145            LineManipulationResult {
11146                new_text: lines.join("\n"),
11147                line_count_before,
11148                line_count_after: lines.len(),
11149            }
11150        });
11151    }
11152
11153    fn manipulate_mutable_lines<Fn>(
11154        &mut self,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157        mut callback: Fn,
11158    ) where
11159        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11160    {
11161        self.manipulate_lines(window, cx, |text| {
11162            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11163            let line_count_before = lines.len();
11164
11165            callback(&mut lines);
11166
11167            LineManipulationResult {
11168                new_text: lines.join("\n"),
11169                line_count_before,
11170                line_count_after: lines.len(),
11171            }
11172        });
11173    }
11174
11175    pub fn convert_indentation_to_spaces(
11176        &mut self,
11177        _: &ConvertIndentationToSpaces,
11178        window: &mut Window,
11179        cx: &mut Context<Self>,
11180    ) {
11181        let settings = self.buffer.read(cx).language_settings(cx);
11182        let tab_size = settings.tab_size.get() as usize;
11183
11184        self.manipulate_mutable_lines(window, cx, |lines| {
11185            // Allocates a reasonably sized scratch buffer once for the whole loop
11186            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11187            // Avoids recomputing spaces that could be inserted many times
11188            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11189                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11190                .collect();
11191
11192            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11193                let mut chars = line.as_ref().chars();
11194                let mut col = 0;
11195                let mut changed = false;
11196
11197                for ch in chars.by_ref() {
11198                    match ch {
11199                        ' ' => {
11200                            reindented_line.push(' ');
11201                            col += 1;
11202                        }
11203                        '\t' => {
11204                            // \t are converted to spaces depending on the current column
11205                            let spaces_len = tab_size - (col % tab_size);
11206                            reindented_line.extend(&space_cache[spaces_len - 1]);
11207                            col += spaces_len;
11208                            changed = true;
11209                        }
11210                        _ => {
11211                            // If we dont append before break, the character is consumed
11212                            reindented_line.push(ch);
11213                            break;
11214                        }
11215                    }
11216                }
11217
11218                if !changed {
11219                    reindented_line.clear();
11220                    continue;
11221                }
11222                // Append the rest of the line and replace old reference with new one
11223                reindented_line.extend(chars);
11224                *line = Cow::Owned(reindented_line.clone());
11225                reindented_line.clear();
11226            }
11227        });
11228    }
11229
11230    pub fn convert_indentation_to_tabs(
11231        &mut self,
11232        _: &ConvertIndentationToTabs,
11233        window: &mut Window,
11234        cx: &mut Context<Self>,
11235    ) {
11236        let settings = self.buffer.read(cx).language_settings(cx);
11237        let tab_size = settings.tab_size.get() as usize;
11238
11239        self.manipulate_mutable_lines(window, cx, |lines| {
11240            // Allocates a reasonably sized buffer once for the whole loop
11241            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11242            // Avoids recomputing spaces that could be inserted many times
11243            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11244                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11245                .collect();
11246
11247            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11248                let mut chars = line.chars();
11249                let mut spaces_count = 0;
11250                let mut first_non_indent_char = None;
11251                let mut changed = false;
11252
11253                for ch in chars.by_ref() {
11254                    match ch {
11255                        ' ' => {
11256                            // Keep track of spaces. Append \t when we reach tab_size
11257                            spaces_count += 1;
11258                            changed = true;
11259                            if spaces_count == tab_size {
11260                                reindented_line.push('\t');
11261                                spaces_count = 0;
11262                            }
11263                        }
11264                        '\t' => {
11265                            reindented_line.push('\t');
11266                            spaces_count = 0;
11267                        }
11268                        _ => {
11269                            // Dont append it yet, we might have remaining spaces
11270                            first_non_indent_char = Some(ch);
11271                            break;
11272                        }
11273                    }
11274                }
11275
11276                if !changed {
11277                    reindented_line.clear();
11278                    continue;
11279                }
11280                // Remaining spaces that didn't make a full tab stop
11281                if spaces_count > 0 {
11282                    reindented_line.extend(&space_cache[spaces_count - 1]);
11283                }
11284                // If we consume an extra character that was not indentation, add it back
11285                if let Some(extra_char) = first_non_indent_char {
11286                    reindented_line.push(extra_char);
11287                }
11288                // Append the rest of the line and replace old reference with new one
11289                reindented_line.extend(chars);
11290                *line = Cow::Owned(reindented_line.clone());
11291                reindented_line.clear();
11292            }
11293        });
11294    }
11295
11296    pub fn convert_to_upper_case(
11297        &mut self,
11298        _: &ConvertToUpperCase,
11299        window: &mut Window,
11300        cx: &mut Context<Self>,
11301    ) {
11302        self.manipulate_text(window, cx, |text| text.to_uppercase())
11303    }
11304
11305    pub fn convert_to_lower_case(
11306        &mut self,
11307        _: &ConvertToLowerCase,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        self.manipulate_text(window, cx, |text| text.to_lowercase())
11312    }
11313
11314    pub fn convert_to_title_case(
11315        &mut self,
11316        _: &ConvertToTitleCase,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319    ) {
11320        self.manipulate_text(window, cx, |text| {
11321            text.split('\n')
11322                .map(|line| line.to_case(Case::Title))
11323                .join("\n")
11324        })
11325    }
11326
11327    pub fn convert_to_snake_case(
11328        &mut self,
11329        _: &ConvertToSnakeCase,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) {
11333        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11334    }
11335
11336    pub fn convert_to_kebab_case(
11337        &mut self,
11338        _: &ConvertToKebabCase,
11339        window: &mut Window,
11340        cx: &mut Context<Self>,
11341    ) {
11342        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11343    }
11344
11345    pub fn convert_to_upper_camel_case(
11346        &mut self,
11347        _: &ConvertToUpperCamelCase,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) {
11351        self.manipulate_text(window, cx, |text| {
11352            text.split('\n')
11353                .map(|line| line.to_case(Case::UpperCamel))
11354                .join("\n")
11355        })
11356    }
11357
11358    pub fn convert_to_lower_camel_case(
11359        &mut self,
11360        _: &ConvertToLowerCamelCase,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11365    }
11366
11367    pub fn convert_to_opposite_case(
11368        &mut self,
11369        _: &ConvertToOppositeCase,
11370        window: &mut Window,
11371        cx: &mut Context<Self>,
11372    ) {
11373        self.manipulate_text(window, cx, |text| {
11374            text.chars()
11375                .fold(String::with_capacity(text.len()), |mut t, c| {
11376                    if c.is_uppercase() {
11377                        t.extend(c.to_lowercase());
11378                    } else {
11379                        t.extend(c.to_uppercase());
11380                    }
11381                    t
11382                })
11383        })
11384    }
11385
11386    pub fn convert_to_sentence_case(
11387        &mut self,
11388        _: &ConvertToSentenceCase,
11389        window: &mut Window,
11390        cx: &mut Context<Self>,
11391    ) {
11392        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11393    }
11394
11395    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11396        self.manipulate_text(window, cx, |text| {
11397            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11398            if has_upper_case_characters {
11399                text.to_lowercase()
11400            } else {
11401                text.to_uppercase()
11402            }
11403        })
11404    }
11405
11406    pub fn convert_to_rot13(
11407        &mut self,
11408        _: &ConvertToRot13,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        self.manipulate_text(window, cx, |text| {
11413            text.chars()
11414                .map(|c| match c {
11415                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11416                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11417                    _ => c,
11418                })
11419                .collect()
11420        })
11421    }
11422
11423    pub fn convert_to_rot47(
11424        &mut self,
11425        _: &ConvertToRot47,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        self.manipulate_text(window, cx, |text| {
11430            text.chars()
11431                .map(|c| {
11432                    let code_point = c as u32;
11433                    if code_point >= 33 && code_point <= 126 {
11434                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11435                    }
11436                    c
11437                })
11438                .collect()
11439        })
11440    }
11441
11442    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11443    where
11444        Fn: FnMut(&str) -> String,
11445    {
11446        let buffer = self.buffer.read(cx).snapshot(cx);
11447
11448        let mut new_selections = Vec::new();
11449        let mut edits = Vec::new();
11450        let mut selection_adjustment = 0i32;
11451
11452        for selection in self.selections.all_adjusted(cx) {
11453            let selection_is_empty = selection.is_empty();
11454
11455            let (start, end) = if selection_is_empty {
11456                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11457                (word_range.start, word_range.end)
11458            } else {
11459                (
11460                    buffer.point_to_offset(selection.start),
11461                    buffer.point_to_offset(selection.end),
11462                )
11463            };
11464
11465            let text = buffer.text_for_range(start..end).collect::<String>();
11466            let old_length = text.len() as i32;
11467            let text = callback(&text);
11468
11469            new_selections.push(Selection {
11470                start: (start as i32 - selection_adjustment) as usize,
11471                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11472                goal: SelectionGoal::None,
11473                id: selection.id,
11474                reversed: selection.reversed,
11475            });
11476
11477            selection_adjustment += old_length - text.len() as i32;
11478
11479            edits.push((start..end, text));
11480        }
11481
11482        self.transact(window, cx, |this, window, cx| {
11483            this.buffer.update(cx, |buffer, cx| {
11484                buffer.edit(edits, None, cx);
11485            });
11486
11487            this.change_selections(Default::default(), window, cx, |s| {
11488                s.select(new_selections);
11489            });
11490
11491            this.request_autoscroll(Autoscroll::fit(), cx);
11492        });
11493    }
11494
11495    pub fn move_selection_on_drop(
11496        &mut self,
11497        selection: &Selection<Anchor>,
11498        target: DisplayPoint,
11499        is_cut: bool,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11504        let buffer = &display_map.buffer_snapshot;
11505        let mut edits = Vec::new();
11506        let insert_point = display_map
11507            .clip_point(target, Bias::Left)
11508            .to_point(&display_map);
11509        let text = buffer
11510            .text_for_range(selection.start..selection.end)
11511            .collect::<String>();
11512        if is_cut {
11513            edits.push(((selection.start..selection.end), String::new()));
11514        }
11515        let insert_anchor = buffer.anchor_before(insert_point);
11516        edits.push(((insert_anchor..insert_anchor), text));
11517        let last_edit_start = insert_anchor.bias_left(buffer);
11518        let last_edit_end = insert_anchor.bias_right(buffer);
11519        self.transact(window, cx, |this, window, cx| {
11520            this.buffer.update(cx, |buffer, cx| {
11521                buffer.edit(edits, None, cx);
11522            });
11523            this.change_selections(Default::default(), window, cx, |s| {
11524                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11525            });
11526        });
11527    }
11528
11529    pub fn clear_selection_drag_state(&mut self) {
11530        self.selection_drag_state = SelectionDragState::None;
11531    }
11532
11533    pub fn duplicate(
11534        &mut self,
11535        upwards: bool,
11536        whole_lines: bool,
11537        window: &mut Window,
11538        cx: &mut Context<Self>,
11539    ) {
11540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11541
11542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11543        let buffer = &display_map.buffer_snapshot;
11544        let selections = self.selections.all::<Point>(cx);
11545
11546        let mut edits = Vec::new();
11547        let mut selections_iter = selections.iter().peekable();
11548        while let Some(selection) = selections_iter.next() {
11549            let mut rows = selection.spanned_rows(false, &display_map);
11550            // duplicate line-wise
11551            if whole_lines || selection.start == selection.end {
11552                // Avoid duplicating the same lines twice.
11553                while let Some(next_selection) = selections_iter.peek() {
11554                    let next_rows = next_selection.spanned_rows(false, &display_map);
11555                    if next_rows.start < rows.end {
11556                        rows.end = next_rows.end;
11557                        selections_iter.next().unwrap();
11558                    } else {
11559                        break;
11560                    }
11561                }
11562
11563                // Copy the text from the selected row region and splice it either at the start
11564                // or end of the region.
11565                let start = Point::new(rows.start.0, 0);
11566                let end = Point::new(
11567                    rows.end.previous_row().0,
11568                    buffer.line_len(rows.end.previous_row()),
11569                );
11570                let text = buffer
11571                    .text_for_range(start..end)
11572                    .chain(Some("\n"))
11573                    .collect::<String>();
11574                let insert_location = if upwards {
11575                    Point::new(rows.end.0, 0)
11576                } else {
11577                    start
11578                };
11579                edits.push((insert_location..insert_location, text));
11580            } else {
11581                // duplicate character-wise
11582                let start = selection.start;
11583                let end = selection.end;
11584                let text = buffer.text_for_range(start..end).collect::<String>();
11585                edits.push((selection.end..selection.end, text));
11586            }
11587        }
11588
11589        self.transact(window, cx, |this, _, cx| {
11590            this.buffer.update(cx, |buffer, cx| {
11591                buffer.edit(edits, None, cx);
11592            });
11593
11594            this.request_autoscroll(Autoscroll::fit(), cx);
11595        });
11596    }
11597
11598    pub fn duplicate_line_up(
11599        &mut self,
11600        _: &DuplicateLineUp,
11601        window: &mut Window,
11602        cx: &mut Context<Self>,
11603    ) {
11604        self.duplicate(true, true, window, cx);
11605    }
11606
11607    pub fn duplicate_line_down(
11608        &mut self,
11609        _: &DuplicateLineDown,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        self.duplicate(false, true, window, cx);
11614    }
11615
11616    pub fn duplicate_selection(
11617        &mut self,
11618        _: &DuplicateSelection,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        self.duplicate(false, false, window, cx);
11623    }
11624
11625    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11627        if self.mode.is_single_line() {
11628            cx.propagate();
11629            return;
11630        }
11631
11632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11633        let buffer = self.buffer.read(cx).snapshot(cx);
11634
11635        let mut edits = Vec::new();
11636        let mut unfold_ranges = Vec::new();
11637        let mut refold_creases = Vec::new();
11638
11639        let selections = self.selections.all::<Point>(cx);
11640        let mut selections = selections.iter().peekable();
11641        let mut contiguous_row_selections = Vec::new();
11642        let mut new_selections = Vec::new();
11643
11644        while let Some(selection) = selections.next() {
11645            // Find all the selections that span a contiguous row range
11646            let (start_row, end_row) = consume_contiguous_rows(
11647                &mut contiguous_row_selections,
11648                selection,
11649                &display_map,
11650                &mut selections,
11651            );
11652
11653            // Move the text spanned by the row range to be before the line preceding the row range
11654            if start_row.0 > 0 {
11655                let range_to_move = Point::new(
11656                    start_row.previous_row().0,
11657                    buffer.line_len(start_row.previous_row()),
11658                )
11659                    ..Point::new(
11660                        end_row.previous_row().0,
11661                        buffer.line_len(end_row.previous_row()),
11662                    );
11663                let insertion_point = display_map
11664                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11665                    .0;
11666
11667                // Don't move lines across excerpts
11668                if buffer
11669                    .excerpt_containing(insertion_point..range_to_move.end)
11670                    .is_some()
11671                {
11672                    let text = buffer
11673                        .text_for_range(range_to_move.clone())
11674                        .flat_map(|s| s.chars())
11675                        .skip(1)
11676                        .chain(['\n'])
11677                        .collect::<String>();
11678
11679                    edits.push((
11680                        buffer.anchor_after(range_to_move.start)
11681                            ..buffer.anchor_before(range_to_move.end),
11682                        String::new(),
11683                    ));
11684                    let insertion_anchor = buffer.anchor_after(insertion_point);
11685                    edits.push((insertion_anchor..insertion_anchor, text));
11686
11687                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11688
11689                    // Move selections up
11690                    new_selections.extend(contiguous_row_selections.drain(..).map(
11691                        |mut selection| {
11692                            selection.start.row -= row_delta;
11693                            selection.end.row -= row_delta;
11694                            selection
11695                        },
11696                    ));
11697
11698                    // Move folds up
11699                    unfold_ranges.push(range_to_move.clone());
11700                    for fold in display_map.folds_in_range(
11701                        buffer.anchor_before(range_to_move.start)
11702                            ..buffer.anchor_after(range_to_move.end),
11703                    ) {
11704                        let mut start = fold.range.start.to_point(&buffer);
11705                        let mut end = fold.range.end.to_point(&buffer);
11706                        start.row -= row_delta;
11707                        end.row -= row_delta;
11708                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11709                    }
11710                }
11711            }
11712
11713            // If we didn't move line(s), preserve the existing selections
11714            new_selections.append(&mut contiguous_row_selections);
11715        }
11716
11717        self.transact(window, cx, |this, window, cx| {
11718            this.unfold_ranges(&unfold_ranges, true, true, cx);
11719            this.buffer.update(cx, |buffer, cx| {
11720                for (range, text) in edits {
11721                    buffer.edit([(range, text)], None, cx);
11722                }
11723            });
11724            this.fold_creases(refold_creases, true, window, cx);
11725            this.change_selections(Default::default(), window, cx, |s| {
11726                s.select(new_selections);
11727            })
11728        });
11729    }
11730
11731    pub fn move_line_down(
11732        &mut self,
11733        _: &MoveLineDown,
11734        window: &mut Window,
11735        cx: &mut Context<Self>,
11736    ) {
11737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11738        if self.mode.is_single_line() {
11739            cx.propagate();
11740            return;
11741        }
11742
11743        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11744        let buffer = self.buffer.read(cx).snapshot(cx);
11745
11746        let mut edits = Vec::new();
11747        let mut unfold_ranges = Vec::new();
11748        let mut refold_creases = Vec::new();
11749
11750        let selections = self.selections.all::<Point>(cx);
11751        let mut selections = selections.iter().peekable();
11752        let mut contiguous_row_selections = Vec::new();
11753        let mut new_selections = Vec::new();
11754
11755        while let Some(selection) = selections.next() {
11756            // Find all the selections that span a contiguous row range
11757            let (start_row, end_row) = consume_contiguous_rows(
11758                &mut contiguous_row_selections,
11759                selection,
11760                &display_map,
11761                &mut selections,
11762            );
11763
11764            // Move the text spanned by the row range to be after the last line of the row range
11765            if end_row.0 <= buffer.max_point().row {
11766                let range_to_move =
11767                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11768                let insertion_point = display_map
11769                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11770                    .0;
11771
11772                // Don't move lines across excerpt boundaries
11773                if buffer
11774                    .excerpt_containing(range_to_move.start..insertion_point)
11775                    .is_some()
11776                {
11777                    let mut text = String::from("\n");
11778                    text.extend(buffer.text_for_range(range_to_move.clone()));
11779                    text.pop(); // Drop trailing newline
11780                    edits.push((
11781                        buffer.anchor_after(range_to_move.start)
11782                            ..buffer.anchor_before(range_to_move.end),
11783                        String::new(),
11784                    ));
11785                    let insertion_anchor = buffer.anchor_after(insertion_point);
11786                    edits.push((insertion_anchor..insertion_anchor, text));
11787
11788                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11789
11790                    // Move selections down
11791                    new_selections.extend(contiguous_row_selections.drain(..).map(
11792                        |mut selection| {
11793                            selection.start.row += row_delta;
11794                            selection.end.row += row_delta;
11795                            selection
11796                        },
11797                    ));
11798
11799                    // Move folds down
11800                    unfold_ranges.push(range_to_move.clone());
11801                    for fold in display_map.folds_in_range(
11802                        buffer.anchor_before(range_to_move.start)
11803                            ..buffer.anchor_after(range_to_move.end),
11804                    ) {
11805                        let mut start = fold.range.start.to_point(&buffer);
11806                        let mut end = fold.range.end.to_point(&buffer);
11807                        start.row += row_delta;
11808                        end.row += row_delta;
11809                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11810                    }
11811                }
11812            }
11813
11814            // If we didn't move line(s), preserve the existing selections
11815            new_selections.append(&mut contiguous_row_selections);
11816        }
11817
11818        self.transact(window, cx, |this, window, cx| {
11819            this.unfold_ranges(&unfold_ranges, true, true, cx);
11820            this.buffer.update(cx, |buffer, cx| {
11821                for (range, text) in edits {
11822                    buffer.edit([(range, text)], None, cx);
11823                }
11824            });
11825            this.fold_creases(refold_creases, true, window, cx);
11826            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11827        });
11828    }
11829
11830    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11832        let text_layout_details = &self.text_layout_details(window);
11833        self.transact(window, cx, |this, window, cx| {
11834            let edits = this.change_selections(Default::default(), window, cx, |s| {
11835                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11836                s.move_with(|display_map, selection| {
11837                    if !selection.is_empty() {
11838                        return;
11839                    }
11840
11841                    let mut head = selection.head();
11842                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11843                    if head.column() == display_map.line_len(head.row()) {
11844                        transpose_offset = display_map
11845                            .buffer_snapshot
11846                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11847                    }
11848
11849                    if transpose_offset == 0 {
11850                        return;
11851                    }
11852
11853                    *head.column_mut() += 1;
11854                    head = display_map.clip_point(head, Bias::Right);
11855                    let goal = SelectionGoal::HorizontalPosition(
11856                        display_map
11857                            .x_for_display_point(head, text_layout_details)
11858                            .into(),
11859                    );
11860                    selection.collapse_to(head, goal);
11861
11862                    let transpose_start = display_map
11863                        .buffer_snapshot
11864                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11865                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11866                        let transpose_end = display_map
11867                            .buffer_snapshot
11868                            .clip_offset(transpose_offset + 1, Bias::Right);
11869                        if let Some(ch) =
11870                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11871                        {
11872                            edits.push((transpose_start..transpose_offset, String::new()));
11873                            edits.push((transpose_end..transpose_end, ch.to_string()));
11874                        }
11875                    }
11876                });
11877                edits
11878            });
11879            this.buffer
11880                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11881            let selections = this.selections.all::<usize>(cx);
11882            this.change_selections(Default::default(), window, cx, |s| {
11883                s.select(selections);
11884            });
11885        });
11886    }
11887
11888    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11890        if self.mode.is_single_line() {
11891            cx.propagate();
11892            return;
11893        }
11894
11895        self.rewrap_impl(RewrapOptions::default(), cx)
11896    }
11897
11898    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11899        let buffer = self.buffer.read(cx).snapshot(cx);
11900        let selections = self.selections.all::<Point>(cx);
11901
11902        #[derive(Clone, Debug, PartialEq)]
11903        enum CommentFormat {
11904            /// single line comment, with prefix for line
11905            Line(String),
11906            /// single line within a block comment, with prefix for line
11907            BlockLine(String),
11908            /// a single line of a block comment that includes the initial delimiter
11909            BlockCommentWithStart(BlockCommentConfig),
11910            /// a single line of a block comment that includes the ending delimiter
11911            BlockCommentWithEnd(BlockCommentConfig),
11912        }
11913
11914        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11915        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11916            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11917                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11918                .peekable();
11919
11920            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11921                row
11922            } else {
11923                return Vec::new();
11924            };
11925
11926            let language_settings = buffer.language_settings_at(selection.head(), cx);
11927            let language_scope = buffer.language_scope_at(selection.head());
11928
11929            let indent_and_prefix_for_row =
11930                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11931                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11932                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11933                        &language_scope
11934                    {
11935                        let indent_end = Point::new(row, indent.len);
11936                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11937                        let line_text_after_indent = buffer
11938                            .text_for_range(indent_end..line_end)
11939                            .collect::<String>();
11940
11941                        let is_within_comment_override = buffer
11942                            .language_scope_at(indent_end)
11943                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11944                        let comment_delimiters = if is_within_comment_override {
11945                            // we are within a comment syntax node, but we don't
11946                            // yet know what kind of comment: block, doc or line
11947                            match (
11948                                language_scope.documentation_comment(),
11949                                language_scope.block_comment(),
11950                            ) {
11951                                (Some(config), _) | (_, Some(config))
11952                                    if buffer.contains_str_at(indent_end, &config.start) =>
11953                                {
11954                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11955                                }
11956                                (Some(config), _) | (_, Some(config))
11957                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11958                                {
11959                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11960                                }
11961                                (Some(config), _) | (_, Some(config))
11962                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11963                                {
11964                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11965                                }
11966                                (_, _) => language_scope
11967                                    .line_comment_prefixes()
11968                                    .iter()
11969                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11970                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11971                            }
11972                        } else {
11973                            // we not in an overridden comment node, but we may
11974                            // be within a non-overridden line comment node
11975                            language_scope
11976                                .line_comment_prefixes()
11977                                .iter()
11978                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11979                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11980                        };
11981
11982                        let rewrap_prefix = language_scope
11983                            .rewrap_prefixes()
11984                            .iter()
11985                            .find_map(|prefix_regex| {
11986                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11987                                    if mat.start() == 0 {
11988                                        Some(mat.as_str().to_string())
11989                                    } else {
11990                                        None
11991                                    }
11992                                })
11993                            })
11994                            .flatten();
11995                        (comment_delimiters, rewrap_prefix)
11996                    } else {
11997                        (None, None)
11998                    };
11999                    (indent, comment_prefix, rewrap_prefix)
12000                };
12001
12002            let mut ranges = Vec::new();
12003            let from_empty_selection = selection.is_empty();
12004
12005            let mut current_range_start = first_row;
12006            let mut prev_row = first_row;
12007            let (
12008                mut current_range_indent,
12009                mut current_range_comment_delimiters,
12010                mut current_range_rewrap_prefix,
12011            ) = indent_and_prefix_for_row(first_row);
12012
12013            for row in non_blank_rows_iter.skip(1) {
12014                let has_paragraph_break = row > prev_row + 1;
12015
12016                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12017                    indent_and_prefix_for_row(row);
12018
12019                let has_indent_change = row_indent != current_range_indent;
12020                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12021
12022                let has_boundary_change = has_comment_change
12023                    || row_rewrap_prefix.is_some()
12024                    || (has_indent_change && current_range_comment_delimiters.is_some());
12025
12026                if has_paragraph_break || has_boundary_change {
12027                    ranges.push((
12028                        language_settings.clone(),
12029                        Point::new(current_range_start, 0)
12030                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12031                        current_range_indent,
12032                        current_range_comment_delimiters.clone(),
12033                        current_range_rewrap_prefix.clone(),
12034                        from_empty_selection,
12035                    ));
12036                    current_range_start = row;
12037                    current_range_indent = row_indent;
12038                    current_range_comment_delimiters = row_comment_delimiters;
12039                    current_range_rewrap_prefix = row_rewrap_prefix;
12040                }
12041                prev_row = row;
12042            }
12043
12044            ranges.push((
12045                language_settings.clone(),
12046                Point::new(current_range_start, 0)
12047                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12048                current_range_indent,
12049                current_range_comment_delimiters,
12050                current_range_rewrap_prefix,
12051                from_empty_selection,
12052            ));
12053
12054            ranges
12055        });
12056
12057        let mut edits = Vec::new();
12058        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12059
12060        for (
12061            language_settings,
12062            wrap_range,
12063            mut indent_size,
12064            comment_prefix,
12065            rewrap_prefix,
12066            from_empty_selection,
12067        ) in wrap_ranges
12068        {
12069            let mut start_row = wrap_range.start.row;
12070            let mut end_row = wrap_range.end.row;
12071
12072            // Skip selections that overlap with a range that has already been rewrapped.
12073            let selection_range = start_row..end_row;
12074            if rewrapped_row_ranges
12075                .iter()
12076                .any(|range| range.overlaps(&selection_range))
12077            {
12078                continue;
12079            }
12080
12081            let tab_size = language_settings.tab_size;
12082
12083            let (line_prefix, inside_comment) = match &comment_prefix {
12084                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12085                    (Some(prefix.as_str()), true)
12086                }
12087                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12088                    (Some(prefix.as_ref()), true)
12089                }
12090                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12091                    start: _,
12092                    end: _,
12093                    prefix,
12094                    tab_size,
12095                })) => {
12096                    indent_size.len += tab_size;
12097                    (Some(prefix.as_ref()), true)
12098                }
12099                None => (None, false),
12100            };
12101            let indent_prefix = indent_size.chars().collect::<String>();
12102            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12103
12104            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12105                RewrapBehavior::InComments => inside_comment,
12106                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12107                RewrapBehavior::Anywhere => true,
12108            };
12109
12110            let should_rewrap = options.override_language_settings
12111                || allow_rewrap_based_on_language
12112                || self.hard_wrap.is_some();
12113            if !should_rewrap {
12114                continue;
12115            }
12116
12117            if from_empty_selection {
12118                'expand_upwards: while start_row > 0 {
12119                    let prev_row = start_row - 1;
12120                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12121                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12122                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12123                    {
12124                        start_row = prev_row;
12125                    } else {
12126                        break 'expand_upwards;
12127                    }
12128                }
12129
12130                'expand_downwards: while end_row < buffer.max_point().row {
12131                    let next_row = end_row + 1;
12132                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12133                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12134                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12135                    {
12136                        end_row = next_row;
12137                    } else {
12138                        break 'expand_downwards;
12139                    }
12140                }
12141            }
12142
12143            let start = Point::new(start_row, 0);
12144            let start_offset = start.to_offset(&buffer);
12145            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12146            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12147            let mut first_line_delimiter = None;
12148            let mut last_line_delimiter = None;
12149            let Some(lines_without_prefixes) = selection_text
12150                .lines()
12151                .enumerate()
12152                .map(|(ix, line)| {
12153                    let line_trimmed = line.trim_start();
12154                    if rewrap_prefix.is_some() && ix > 0 {
12155                        Ok(line_trimmed)
12156                    } else if let Some(
12157                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12158                            start,
12159                            prefix,
12160                            end,
12161                            tab_size,
12162                        })
12163                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12164                            start,
12165                            prefix,
12166                            end,
12167                            tab_size,
12168                        }),
12169                    ) = &comment_prefix
12170                    {
12171                        let line_trimmed = line_trimmed
12172                            .strip_prefix(start.as_ref())
12173                            .map(|s| {
12174                                let mut indent_size = indent_size;
12175                                indent_size.len -= tab_size;
12176                                let indent_prefix: String = indent_size.chars().collect();
12177                                first_line_delimiter = Some((indent_prefix, start));
12178                                s.trim_start()
12179                            })
12180                            .unwrap_or(line_trimmed);
12181                        let line_trimmed = line_trimmed
12182                            .strip_suffix(end.as_ref())
12183                            .map(|s| {
12184                                last_line_delimiter = Some(end);
12185                                s.trim_end()
12186                            })
12187                            .unwrap_or(line_trimmed);
12188                        let line_trimmed = line_trimmed
12189                            .strip_prefix(prefix.as_ref())
12190                            .unwrap_or(line_trimmed);
12191                        Ok(line_trimmed)
12192                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12193                        line_trimmed.strip_prefix(prefix).with_context(|| {
12194                            format!("line did not start with prefix {prefix:?}: {line:?}")
12195                        })
12196                    } else {
12197                        line_trimmed
12198                            .strip_prefix(&line_prefix.trim_start())
12199                            .with_context(|| {
12200                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12201                            })
12202                    }
12203                })
12204                .collect::<Result<Vec<_>, _>>()
12205                .log_err()
12206            else {
12207                continue;
12208            };
12209
12210            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12211                buffer
12212                    .language_settings_at(Point::new(start_row, 0), cx)
12213                    .preferred_line_length as usize
12214            });
12215
12216            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12217                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12218            } else {
12219                line_prefix.clone()
12220            };
12221
12222            let wrapped_text = {
12223                let mut wrapped_text = wrap_with_prefix(
12224                    line_prefix,
12225                    subsequent_lines_prefix,
12226                    lines_without_prefixes.join("\n"),
12227                    wrap_column,
12228                    tab_size,
12229                    options.preserve_existing_whitespace,
12230                );
12231
12232                if let Some((indent, delimiter)) = first_line_delimiter {
12233                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12234                }
12235                if let Some(last_line) = last_line_delimiter {
12236                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12237                }
12238
12239                wrapped_text
12240            };
12241
12242            // TODO: should always use char-based diff while still supporting cursor behavior that
12243            // matches vim.
12244            let mut diff_options = DiffOptions::default();
12245            if options.override_language_settings {
12246                diff_options.max_word_diff_len = 0;
12247                diff_options.max_word_diff_line_count = 0;
12248            } else {
12249                diff_options.max_word_diff_len = usize::MAX;
12250                diff_options.max_word_diff_line_count = usize::MAX;
12251            }
12252
12253            for (old_range, new_text) in
12254                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12255            {
12256                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12257                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12258                edits.push((edit_start..edit_end, new_text));
12259            }
12260
12261            rewrapped_row_ranges.push(start_row..=end_row);
12262        }
12263
12264        self.buffer
12265            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12266    }
12267
12268    pub fn cut_common(
12269        &mut self,
12270        cut_no_selection_line: bool,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) -> ClipboardItem {
12274        let mut text = String::new();
12275        let buffer = self.buffer.read(cx).snapshot(cx);
12276        let mut selections = self.selections.all::<Point>(cx);
12277        let mut clipboard_selections = Vec::with_capacity(selections.len());
12278        {
12279            let max_point = buffer.max_point();
12280            let mut is_first = true;
12281            for selection in &mut selections {
12282                let is_entire_line =
12283                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12284                if is_entire_line {
12285                    selection.start = Point::new(selection.start.row, 0);
12286                    if !selection.is_empty() && selection.end.column == 0 {
12287                        selection.end = cmp::min(max_point, selection.end);
12288                    } else {
12289                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12290                    }
12291                    selection.goal = SelectionGoal::None;
12292                }
12293                if is_first {
12294                    is_first = false;
12295                } else {
12296                    text += "\n";
12297                }
12298                let mut len = 0;
12299                for chunk in buffer.text_for_range(selection.start..selection.end) {
12300                    text.push_str(chunk);
12301                    len += chunk.len();
12302                }
12303                clipboard_selections.push(ClipboardSelection {
12304                    len,
12305                    is_entire_line,
12306                    first_line_indent: buffer
12307                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12308                        .len,
12309                });
12310            }
12311        }
12312
12313        self.transact(window, cx, |this, window, cx| {
12314            this.change_selections(Default::default(), window, cx, |s| {
12315                s.select(selections);
12316            });
12317            this.insert("", window, cx);
12318        });
12319        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12320    }
12321
12322    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12324        let item = self.cut_common(true, window, cx);
12325        cx.write_to_clipboard(item);
12326    }
12327
12328    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12330        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12331            s.move_with(|snapshot, sel| {
12332                if sel.is_empty() {
12333                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12334                }
12335                if sel.is_empty() {
12336                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12337                }
12338            });
12339        });
12340        let item = self.cut_common(true, window, cx);
12341        cx.set_global(KillRing(item))
12342    }
12343
12344    pub fn kill_ring_yank(
12345        &mut self,
12346        _: &KillRingYank,
12347        window: &mut Window,
12348        cx: &mut Context<Self>,
12349    ) {
12350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12351        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12352            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12353                (kill_ring.text().to_string(), kill_ring.metadata_json())
12354            } else {
12355                return;
12356            }
12357        } else {
12358            return;
12359        };
12360        self.do_paste(&text, metadata, false, window, cx);
12361    }
12362
12363    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12364        self.do_copy(true, cx);
12365    }
12366
12367    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12368        self.do_copy(false, cx);
12369    }
12370
12371    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12372        let selections = self.selections.all::<Point>(cx);
12373        let buffer = self.buffer.read(cx).read(cx);
12374        let mut text = String::new();
12375
12376        let mut clipboard_selections = Vec::with_capacity(selections.len());
12377        {
12378            let max_point = buffer.max_point();
12379            let mut is_first = true;
12380            for selection in &selections {
12381                let mut start = selection.start;
12382                let mut end = selection.end;
12383                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12384                if is_entire_line {
12385                    start = Point::new(start.row, 0);
12386                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12387                }
12388
12389                let mut trimmed_selections = Vec::new();
12390                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12391                    let row = MultiBufferRow(start.row);
12392                    let first_indent = buffer.indent_size_for_line(row);
12393                    if first_indent.len == 0 || start.column > first_indent.len {
12394                        trimmed_selections.push(start..end);
12395                    } else {
12396                        trimmed_selections.push(
12397                            Point::new(row.0, first_indent.len)
12398                                ..Point::new(row.0, buffer.line_len(row)),
12399                        );
12400                        for row in start.row + 1..=end.row {
12401                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12402                            if row == end.row {
12403                                line_len = end.column;
12404                            }
12405                            if line_len == 0 {
12406                                trimmed_selections
12407                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12408                                continue;
12409                            }
12410                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12411                            if row_indent_size.len >= first_indent.len {
12412                                trimmed_selections.push(
12413                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12414                                );
12415                            } else {
12416                                trimmed_selections.clear();
12417                                trimmed_selections.push(start..end);
12418                                break;
12419                            }
12420                        }
12421                    }
12422                } else {
12423                    trimmed_selections.push(start..end);
12424                }
12425
12426                for trimmed_range in trimmed_selections {
12427                    if is_first {
12428                        is_first = false;
12429                    } else {
12430                        text += "\n";
12431                    }
12432                    let mut len = 0;
12433                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12434                        text.push_str(chunk);
12435                        len += chunk.len();
12436                    }
12437                    clipboard_selections.push(ClipboardSelection {
12438                        len,
12439                        is_entire_line,
12440                        first_line_indent: buffer
12441                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12442                            .len,
12443                    });
12444                }
12445            }
12446        }
12447
12448        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12449            text,
12450            clipboard_selections,
12451        ));
12452    }
12453
12454    pub fn do_paste(
12455        &mut self,
12456        text: &String,
12457        clipboard_selections: Option<Vec<ClipboardSelection>>,
12458        handle_entire_lines: bool,
12459        window: &mut Window,
12460        cx: &mut Context<Self>,
12461    ) {
12462        if self.read_only(cx) {
12463            return;
12464        }
12465
12466        let clipboard_text = Cow::Borrowed(text.as_str());
12467
12468        self.transact(window, cx, |this, window, cx| {
12469            let had_active_edit_prediction = this.has_active_edit_prediction();
12470            let old_selections = this.selections.all::<usize>(cx);
12471            let cursor_offset = this.selections.last::<usize>(cx).head();
12472
12473            if let Some(mut clipboard_selections) = clipboard_selections {
12474                let all_selections_were_entire_line =
12475                    clipboard_selections.iter().all(|s| s.is_entire_line);
12476                let first_selection_indent_column =
12477                    clipboard_selections.first().map(|s| s.first_line_indent);
12478                if clipboard_selections.len() != old_selections.len() {
12479                    clipboard_selections.drain(..);
12480                }
12481                let mut auto_indent_on_paste = true;
12482
12483                this.buffer.update(cx, |buffer, cx| {
12484                    let snapshot = buffer.read(cx);
12485                    auto_indent_on_paste = snapshot
12486                        .language_settings_at(cursor_offset, cx)
12487                        .auto_indent_on_paste;
12488
12489                    let mut start_offset = 0;
12490                    let mut edits = Vec::new();
12491                    let mut original_indent_columns = Vec::new();
12492                    for (ix, selection) in old_selections.iter().enumerate() {
12493                        let to_insert;
12494                        let entire_line;
12495                        let original_indent_column;
12496                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12497                            let end_offset = start_offset + clipboard_selection.len;
12498                            to_insert = &clipboard_text[start_offset..end_offset];
12499                            entire_line = clipboard_selection.is_entire_line;
12500                            start_offset = end_offset + 1;
12501                            original_indent_column = Some(clipboard_selection.first_line_indent);
12502                        } else {
12503                            to_insert = &*clipboard_text;
12504                            entire_line = all_selections_were_entire_line;
12505                            original_indent_column = first_selection_indent_column
12506                        }
12507
12508                        let (range, to_insert) =
12509                            if selection.is_empty() && handle_entire_lines && entire_line {
12510                                // If the corresponding selection was empty when this slice of the
12511                                // clipboard text was written, then the entire line containing the
12512                                // selection was copied. If this selection is also currently empty,
12513                                // then paste the line before the current line of the buffer.
12514                                let column = selection.start.to_point(&snapshot).column as usize;
12515                                let line_start = selection.start - column;
12516                                (line_start..line_start, Cow::Borrowed(to_insert))
12517                            } else {
12518                                let language = snapshot.language_at(selection.head());
12519                                let range = selection.range();
12520                                if let Some(language) = language
12521                                    && language.name() == "Markdown".into()
12522                                {
12523                                    edit_for_markdown_paste(
12524                                        &snapshot,
12525                                        range,
12526                                        to_insert,
12527                                        url::Url::parse(to_insert).ok(),
12528                                    )
12529                                } else {
12530                                    (range, Cow::Borrowed(to_insert))
12531                                }
12532                            };
12533
12534                        edits.push((range, to_insert));
12535                        original_indent_columns.push(original_indent_column);
12536                    }
12537                    drop(snapshot);
12538
12539                    buffer.edit(
12540                        edits,
12541                        if auto_indent_on_paste {
12542                            Some(AutoindentMode::Block {
12543                                original_indent_columns,
12544                            })
12545                        } else {
12546                            None
12547                        },
12548                        cx,
12549                    );
12550                });
12551
12552                let selections = this.selections.all::<usize>(cx);
12553                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12554            } else {
12555                let url = url::Url::parse(&clipboard_text).ok();
12556
12557                let auto_indent_mode = if !clipboard_text.is_empty() {
12558                    Some(AutoindentMode::Block {
12559                        original_indent_columns: Vec::new(),
12560                    })
12561                } else {
12562                    None
12563                };
12564
12565                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12566                    let snapshot = buffer.snapshot(cx);
12567
12568                    let anchors = old_selections
12569                        .iter()
12570                        .map(|s| {
12571                            let anchor = snapshot.anchor_after(s.head());
12572                            s.map(|_| anchor)
12573                        })
12574                        .collect::<Vec<_>>();
12575
12576                    let mut edits = Vec::new();
12577
12578                    for selection in old_selections.iter() {
12579                        let language = snapshot.language_at(selection.head());
12580                        let range = selection.range();
12581
12582                        let (edit_range, edit_text) = if let Some(language) = language
12583                            && language.name() == "Markdown".into()
12584                        {
12585                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12586                        } else {
12587                            (range, clipboard_text.clone())
12588                        };
12589
12590                        edits.push((edit_range, edit_text));
12591                    }
12592
12593                    drop(snapshot);
12594                    buffer.edit(edits, auto_indent_mode, cx);
12595
12596                    anchors
12597                });
12598
12599                this.change_selections(Default::default(), window, cx, |s| {
12600                    s.select_anchors(selection_anchors);
12601                });
12602            }
12603
12604            let trigger_in_words =
12605                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12606
12607            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12608        });
12609    }
12610
12611    pub fn diff_clipboard_with_selection(
12612        &mut self,
12613        _: &DiffClipboardWithSelection,
12614        window: &mut Window,
12615        cx: &mut Context<Self>,
12616    ) {
12617        let selections = self.selections.all::<usize>(cx);
12618
12619        if selections.is_empty() {
12620            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12621            return;
12622        };
12623
12624        let clipboard_text = match cx.read_from_clipboard() {
12625            Some(item) => match item.entries().first() {
12626                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12627                _ => None,
12628            },
12629            None => None,
12630        };
12631
12632        let Some(clipboard_text) = clipboard_text else {
12633            log::warn!("Clipboard doesn't contain text.");
12634            return;
12635        };
12636
12637        window.dispatch_action(
12638            Box::new(DiffClipboardWithSelectionData {
12639                clipboard_text,
12640                editor: cx.entity(),
12641            }),
12642            cx,
12643        );
12644    }
12645
12646    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12647        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12648        if let Some(item) = cx.read_from_clipboard() {
12649            let entries = item.entries();
12650
12651            match entries.first() {
12652                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12653                // of all the pasted entries.
12654                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12655                    .do_paste(
12656                        clipboard_string.text(),
12657                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12658                        true,
12659                        window,
12660                        cx,
12661                    ),
12662                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12663            }
12664        }
12665    }
12666
12667    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12668        if self.read_only(cx) {
12669            return;
12670        }
12671
12672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12673
12674        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12675            if let Some((selections, _)) =
12676                self.selection_history.transaction(transaction_id).cloned()
12677            {
12678                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12679                    s.select_anchors(selections.to_vec());
12680                });
12681            } else {
12682                log::error!(
12683                    "No entry in selection_history found for undo. \
12684                     This may correspond to a bug where undo does not update the selection. \
12685                     If this is occurring, please add details to \
12686                     https://github.com/zed-industries/zed/issues/22692"
12687                );
12688            }
12689            self.request_autoscroll(Autoscroll::fit(), cx);
12690            self.unmark_text(window, cx);
12691            self.refresh_edit_prediction(true, false, window, cx);
12692            cx.emit(EditorEvent::Edited { transaction_id });
12693            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12694        }
12695    }
12696
12697    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12698        if self.read_only(cx) {
12699            return;
12700        }
12701
12702        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12703
12704        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12705            if let Some((_, Some(selections))) =
12706                self.selection_history.transaction(transaction_id).cloned()
12707            {
12708                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12709                    s.select_anchors(selections.to_vec());
12710                });
12711            } else {
12712                log::error!(
12713                    "No entry in selection_history found for redo. \
12714                     This may correspond to a bug where undo does not update the selection. \
12715                     If this is occurring, please add details to \
12716                     https://github.com/zed-industries/zed/issues/22692"
12717                );
12718            }
12719            self.request_autoscroll(Autoscroll::fit(), cx);
12720            self.unmark_text(window, cx);
12721            self.refresh_edit_prediction(true, false, window, cx);
12722            cx.emit(EditorEvent::Edited { transaction_id });
12723        }
12724    }
12725
12726    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12727        self.buffer
12728            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12729    }
12730
12731    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12732        self.buffer
12733            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12734    }
12735
12736    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12738        self.change_selections(Default::default(), window, cx, |s| {
12739            s.move_with(|map, selection| {
12740                let cursor = if selection.is_empty() {
12741                    movement::left(map, selection.start)
12742                } else {
12743                    selection.start
12744                };
12745                selection.collapse_to(cursor, SelectionGoal::None);
12746            });
12747        })
12748    }
12749
12750    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12752        self.change_selections(Default::default(), window, cx, |s| {
12753            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12754        })
12755    }
12756
12757    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12759        self.change_selections(Default::default(), window, cx, |s| {
12760            s.move_with(|map, selection| {
12761                let cursor = if selection.is_empty() {
12762                    movement::right(map, selection.end)
12763                } else {
12764                    selection.end
12765                };
12766                selection.collapse_to(cursor, SelectionGoal::None)
12767            });
12768        })
12769    }
12770
12771    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12773        self.change_selections(Default::default(), window, cx, |s| {
12774            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12775        })
12776    }
12777
12778    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12779        if self.take_rename(true, window, cx).is_some() {
12780            return;
12781        }
12782
12783        if self.mode.is_single_line() {
12784            cx.propagate();
12785            return;
12786        }
12787
12788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12789
12790        let text_layout_details = &self.text_layout_details(window);
12791        let selection_count = self.selections.count();
12792        let first_selection = self.selections.first_anchor();
12793
12794        self.change_selections(Default::default(), window, cx, |s| {
12795            s.move_with(|map, selection| {
12796                if !selection.is_empty() {
12797                    selection.goal = SelectionGoal::None;
12798                }
12799                let (cursor, goal) = movement::up(
12800                    map,
12801                    selection.start,
12802                    selection.goal,
12803                    false,
12804                    text_layout_details,
12805                );
12806                selection.collapse_to(cursor, goal);
12807            });
12808        });
12809
12810        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12811        {
12812            cx.propagate();
12813        }
12814    }
12815
12816    pub fn move_up_by_lines(
12817        &mut self,
12818        action: &MoveUpByLines,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        if self.take_rename(true, window, cx).is_some() {
12823            return;
12824        }
12825
12826        if self.mode.is_single_line() {
12827            cx.propagate();
12828            return;
12829        }
12830
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832
12833        let text_layout_details = &self.text_layout_details(window);
12834
12835        self.change_selections(Default::default(), window, cx, |s| {
12836            s.move_with(|map, selection| {
12837                if !selection.is_empty() {
12838                    selection.goal = SelectionGoal::None;
12839                }
12840                let (cursor, goal) = movement::up_by_rows(
12841                    map,
12842                    selection.start,
12843                    action.lines,
12844                    selection.goal,
12845                    false,
12846                    text_layout_details,
12847                );
12848                selection.collapse_to(cursor, goal);
12849            });
12850        })
12851    }
12852
12853    pub fn move_down_by_lines(
12854        &mut self,
12855        action: &MoveDownByLines,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        if self.take_rename(true, window, cx).is_some() {
12860            return;
12861        }
12862
12863        if self.mode.is_single_line() {
12864            cx.propagate();
12865            return;
12866        }
12867
12868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12869
12870        let text_layout_details = &self.text_layout_details(window);
12871
12872        self.change_selections(Default::default(), window, cx, |s| {
12873            s.move_with(|map, selection| {
12874                if !selection.is_empty() {
12875                    selection.goal = SelectionGoal::None;
12876                }
12877                let (cursor, goal) = movement::down_by_rows(
12878                    map,
12879                    selection.start,
12880                    action.lines,
12881                    selection.goal,
12882                    false,
12883                    text_layout_details,
12884                );
12885                selection.collapse_to(cursor, goal);
12886            });
12887        })
12888    }
12889
12890    pub fn select_down_by_lines(
12891        &mut self,
12892        action: &SelectDownByLines,
12893        window: &mut Window,
12894        cx: &mut Context<Self>,
12895    ) {
12896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12897        let text_layout_details = &self.text_layout_details(window);
12898        self.change_selections(Default::default(), window, cx, |s| {
12899            s.move_heads_with(|map, head, goal| {
12900                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12901            })
12902        })
12903    }
12904
12905    pub fn select_up_by_lines(
12906        &mut self,
12907        action: &SelectUpByLines,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) {
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912        let text_layout_details = &self.text_layout_details(window);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_heads_with(|map, head, goal| {
12915                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12916            })
12917        })
12918    }
12919
12920    pub fn select_page_up(
12921        &mut self,
12922        _: &SelectPageUp,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) {
12926        let Some(row_count) = self.visible_row_count() else {
12927            return;
12928        };
12929
12930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12931
12932        let text_layout_details = &self.text_layout_details(window);
12933
12934        self.change_selections(Default::default(), window, cx, |s| {
12935            s.move_heads_with(|map, head, goal| {
12936                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12937            })
12938        })
12939    }
12940
12941    pub fn move_page_up(
12942        &mut self,
12943        action: &MovePageUp,
12944        window: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        if self.take_rename(true, window, cx).is_some() {
12948            return;
12949        }
12950
12951        if self
12952            .context_menu
12953            .borrow_mut()
12954            .as_mut()
12955            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12956            .unwrap_or(false)
12957        {
12958            return;
12959        }
12960
12961        if matches!(self.mode, EditorMode::SingleLine) {
12962            cx.propagate();
12963            return;
12964        }
12965
12966        let Some(row_count) = self.visible_row_count() else {
12967            return;
12968        };
12969
12970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12971
12972        let effects = if action.center_cursor {
12973            SelectionEffects::scroll(Autoscroll::center())
12974        } else {
12975            SelectionEffects::default()
12976        };
12977
12978        let text_layout_details = &self.text_layout_details(window);
12979
12980        self.change_selections(effects, window, cx, |s| {
12981            s.move_with(|map, selection| {
12982                if !selection.is_empty() {
12983                    selection.goal = SelectionGoal::None;
12984                }
12985                let (cursor, goal) = movement::up_by_rows(
12986                    map,
12987                    selection.end,
12988                    row_count,
12989                    selection.goal,
12990                    false,
12991                    text_layout_details,
12992                );
12993                selection.collapse_to(cursor, goal);
12994            });
12995        });
12996    }
12997
12998    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000        let text_layout_details = &self.text_layout_details(window);
13001        self.change_selections(Default::default(), window, cx, |s| {
13002            s.move_heads_with(|map, head, goal| {
13003                movement::up(map, head, goal, false, text_layout_details)
13004            })
13005        })
13006    }
13007
13008    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13009        self.take_rename(true, window, cx);
13010
13011        if self.mode.is_single_line() {
13012            cx.propagate();
13013            return;
13014        }
13015
13016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13017
13018        let text_layout_details = &self.text_layout_details(window);
13019        let selection_count = self.selections.count();
13020        let first_selection = self.selections.first_anchor();
13021
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_with(|map, selection| {
13024                if !selection.is_empty() {
13025                    selection.goal = SelectionGoal::None;
13026                }
13027                let (cursor, goal) = movement::down(
13028                    map,
13029                    selection.end,
13030                    selection.goal,
13031                    false,
13032                    text_layout_details,
13033                );
13034                selection.collapse_to(cursor, goal);
13035            });
13036        });
13037
13038        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13039        {
13040            cx.propagate();
13041        }
13042    }
13043
13044    pub fn select_page_down(
13045        &mut self,
13046        _: &SelectPageDown,
13047        window: &mut Window,
13048        cx: &mut Context<Self>,
13049    ) {
13050        let Some(row_count) = self.visible_row_count() else {
13051            return;
13052        };
13053
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13055
13056        let text_layout_details = &self.text_layout_details(window);
13057
13058        self.change_selections(Default::default(), window, cx, |s| {
13059            s.move_heads_with(|map, head, goal| {
13060                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13061            })
13062        })
13063    }
13064
13065    pub fn move_page_down(
13066        &mut self,
13067        action: &MovePageDown,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        if self.take_rename(true, window, cx).is_some() {
13072            return;
13073        }
13074
13075        if self
13076            .context_menu
13077            .borrow_mut()
13078            .as_mut()
13079            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13080            .unwrap_or(false)
13081        {
13082            return;
13083        }
13084
13085        if matches!(self.mode, EditorMode::SingleLine) {
13086            cx.propagate();
13087            return;
13088        }
13089
13090        let Some(row_count) = self.visible_row_count() else {
13091            return;
13092        };
13093
13094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13095
13096        let effects = if action.center_cursor {
13097            SelectionEffects::scroll(Autoscroll::center())
13098        } else {
13099            SelectionEffects::default()
13100        };
13101
13102        let text_layout_details = &self.text_layout_details(window);
13103        self.change_selections(effects, window, cx, |s| {
13104            s.move_with(|map, selection| {
13105                if !selection.is_empty() {
13106                    selection.goal = SelectionGoal::None;
13107                }
13108                let (cursor, goal) = movement::down_by_rows(
13109                    map,
13110                    selection.end,
13111                    row_count,
13112                    selection.goal,
13113                    false,
13114                    text_layout_details,
13115                );
13116                selection.collapse_to(cursor, goal);
13117            });
13118        });
13119    }
13120
13121    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13123        let text_layout_details = &self.text_layout_details(window);
13124        self.change_selections(Default::default(), window, cx, |s| {
13125            s.move_heads_with(|map, head, goal| {
13126                movement::down(map, head, goal, false, text_layout_details)
13127            })
13128        });
13129    }
13130
13131    pub fn context_menu_first(
13132        &mut self,
13133        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
13139        }
13140    }
13141
13142    pub fn context_menu_prev(
13143        &mut self,
13144        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
13150        }
13151    }
13152
13153    pub fn context_menu_next(
13154        &mut self,
13155        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
13161        }
13162    }
13163
13164    pub fn context_menu_last(
13165        &mut self,
13166        _: &ContextMenuLast,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13171            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13172        }
13173    }
13174
13175    pub fn signature_help_prev(
13176        &mut self,
13177        _: &SignatureHelpPrevious,
13178        _: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) {
13181        if let Some(popover) = self.signature_help_state.popover_mut() {
13182            if popover.current_signature == 0 {
13183                popover.current_signature = popover.signatures.len() - 1;
13184            } else {
13185                popover.current_signature -= 1;
13186            }
13187            cx.notify();
13188        }
13189    }
13190
13191    pub fn signature_help_next(
13192        &mut self,
13193        _: &SignatureHelpNext,
13194        _: &mut Window,
13195        cx: &mut Context<Self>,
13196    ) {
13197        if let Some(popover) = self.signature_help_state.popover_mut() {
13198            if popover.current_signature + 1 == popover.signatures.len() {
13199                popover.current_signature = 0;
13200            } else {
13201                popover.current_signature += 1;
13202            }
13203            cx.notify();
13204        }
13205    }
13206
13207    pub fn move_to_previous_word_start(
13208        &mut self,
13209        _: &MoveToPreviousWordStart,
13210        window: &mut Window,
13211        cx: &mut Context<Self>,
13212    ) {
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214        self.change_selections(Default::default(), window, cx, |s| {
13215            s.move_cursors_with(|map, head, _| {
13216                (
13217                    movement::previous_word_start(map, head),
13218                    SelectionGoal::None,
13219                )
13220            });
13221        })
13222    }
13223
13224    pub fn move_to_previous_subword_start(
13225        &mut self,
13226        _: &MoveToPreviousSubwordStart,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_cursors_with(|map, head, _| {
13233                (
13234                    movement::previous_subword_start(map, head),
13235                    SelectionGoal::None,
13236                )
13237            });
13238        })
13239    }
13240
13241    pub fn select_to_previous_word_start(
13242        &mut self,
13243        _: &SelectToPreviousWordStart,
13244        window: &mut Window,
13245        cx: &mut Context<Self>,
13246    ) {
13247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13248        self.change_selections(Default::default(), window, cx, |s| {
13249            s.move_heads_with(|map, head, _| {
13250                (
13251                    movement::previous_word_start(map, head),
13252                    SelectionGoal::None,
13253                )
13254            });
13255        })
13256    }
13257
13258    pub fn select_to_previous_subword_start(
13259        &mut self,
13260        _: &SelectToPreviousSubwordStart,
13261        window: &mut Window,
13262        cx: &mut Context<Self>,
13263    ) {
13264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13265        self.change_selections(Default::default(), window, cx, |s| {
13266            s.move_heads_with(|map, head, _| {
13267                (
13268                    movement::previous_subword_start(map, head),
13269                    SelectionGoal::None,
13270                )
13271            });
13272        })
13273    }
13274
13275    pub fn delete_to_previous_word_start(
13276        &mut self,
13277        action: &DeleteToPreviousWordStart,
13278        window: &mut Window,
13279        cx: &mut Context<Self>,
13280    ) {
13281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13282        self.transact(window, cx, |this, window, cx| {
13283            this.select_autoclose_pair(window, cx);
13284            this.change_selections(Default::default(), window, cx, |s| {
13285                s.move_with(|map, selection| {
13286                    if selection.is_empty() {
13287                        let mut cursor = if action.ignore_newlines {
13288                            movement::previous_word_start(map, selection.head())
13289                        } else {
13290                            movement::previous_word_start_or_newline(map, selection.head())
13291                        };
13292                        cursor = movement::adjust_greedy_deletion(
13293                            map,
13294                            selection.head(),
13295                            cursor,
13296                            action.ignore_brackets,
13297                        );
13298                        selection.set_head(cursor, SelectionGoal::None);
13299                    }
13300                });
13301            });
13302            this.insert("", window, cx);
13303        });
13304    }
13305
13306    pub fn delete_to_previous_subword_start(
13307        &mut self,
13308        _: &DeleteToPreviousSubwordStart,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13313        self.transact(window, cx, |this, window, cx| {
13314            this.select_autoclose_pair(window, cx);
13315            this.change_selections(Default::default(), window, cx, |s| {
13316                s.move_with(|map, selection| {
13317                    if selection.is_empty() {
13318                        let mut cursor = movement::previous_subword_start(map, selection.head());
13319                        cursor =
13320                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13321                        selection.set_head(cursor, SelectionGoal::None);
13322                    }
13323                });
13324            });
13325            this.insert("", window, cx);
13326        });
13327    }
13328
13329    pub fn move_to_next_word_end(
13330        &mut self,
13331        _: &MoveToNextWordEnd,
13332        window: &mut Window,
13333        cx: &mut Context<Self>,
13334    ) {
13335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_cursors_with(|map, head, _| {
13338                (movement::next_word_end(map, head), SelectionGoal::None)
13339            });
13340        })
13341    }
13342
13343    pub fn move_to_next_subword_end(
13344        &mut self,
13345        _: &MoveToNextSubwordEnd,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13350        self.change_selections(Default::default(), window, cx, |s| {
13351            s.move_cursors_with(|map, head, _| {
13352                (movement::next_subword_end(map, head), SelectionGoal::None)
13353            });
13354        })
13355    }
13356
13357    pub fn select_to_next_word_end(
13358        &mut self,
13359        _: &SelectToNextWordEnd,
13360        window: &mut Window,
13361        cx: &mut Context<Self>,
13362    ) {
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        self.change_selections(Default::default(), window, cx, |s| {
13365            s.move_heads_with(|map, head, _| {
13366                (movement::next_word_end(map, head), SelectionGoal::None)
13367            });
13368        })
13369    }
13370
13371    pub fn select_to_next_subword_end(
13372        &mut self,
13373        _: &SelectToNextSubwordEnd,
13374        window: &mut Window,
13375        cx: &mut Context<Self>,
13376    ) {
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (movement::next_subword_end(map, head), SelectionGoal::None)
13381            });
13382        })
13383    }
13384
13385    pub fn delete_to_next_word_end(
13386        &mut self,
13387        action: &DeleteToNextWordEnd,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13392        self.transact(window, cx, |this, window, cx| {
13393            this.change_selections(Default::default(), window, cx, |s| {
13394                s.move_with(|map, selection| {
13395                    if selection.is_empty() {
13396                        let mut cursor = if action.ignore_newlines {
13397                            movement::next_word_end(map, selection.head())
13398                        } else {
13399                            movement::next_word_end_or_newline(map, selection.head())
13400                        };
13401                        cursor = movement::adjust_greedy_deletion(
13402                            map,
13403                            selection.head(),
13404                            cursor,
13405                            action.ignore_brackets,
13406                        );
13407                        selection.set_head(cursor, SelectionGoal::None);
13408                    }
13409                });
13410            });
13411            this.insert("", window, cx);
13412        });
13413    }
13414
13415    pub fn delete_to_next_subword_end(
13416        &mut self,
13417        _: &DeleteToNextSubwordEnd,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13422        self.transact(window, cx, |this, window, cx| {
13423            this.change_selections(Default::default(), window, cx, |s| {
13424                s.move_with(|map, selection| {
13425                    if selection.is_empty() {
13426                        let mut cursor = movement::next_subword_end(map, selection.head());
13427                        cursor =
13428                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13429                        selection.set_head(cursor, SelectionGoal::None);
13430                    }
13431                });
13432            });
13433            this.insert("", window, cx);
13434        });
13435    }
13436
13437    pub fn move_to_beginning_of_line(
13438        &mut self,
13439        action: &MoveToBeginningOfLine,
13440        window: &mut Window,
13441        cx: &mut Context<Self>,
13442    ) {
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.move_cursors_with(|map, head, _| {
13446                (
13447                    movement::indented_line_beginning(
13448                        map,
13449                        head,
13450                        action.stop_at_soft_wraps,
13451                        action.stop_at_indent,
13452                    ),
13453                    SelectionGoal::None,
13454                )
13455            });
13456        })
13457    }
13458
13459    pub fn select_to_beginning_of_line(
13460        &mut self,
13461        action: &SelectToBeginningOfLine,
13462        window: &mut Window,
13463        cx: &mut Context<Self>,
13464    ) {
13465        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13466        self.change_selections(Default::default(), window, cx, |s| {
13467            s.move_heads_with(|map, head, _| {
13468                (
13469                    movement::indented_line_beginning(
13470                        map,
13471                        head,
13472                        action.stop_at_soft_wraps,
13473                        action.stop_at_indent,
13474                    ),
13475                    SelectionGoal::None,
13476                )
13477            });
13478        });
13479    }
13480
13481    pub fn delete_to_beginning_of_line(
13482        &mut self,
13483        action: &DeleteToBeginningOfLine,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13488        self.transact(window, cx, |this, window, cx| {
13489            this.change_selections(Default::default(), window, cx, |s| {
13490                s.move_with(|_, selection| {
13491                    selection.reversed = true;
13492                });
13493            });
13494
13495            this.select_to_beginning_of_line(
13496                &SelectToBeginningOfLine {
13497                    stop_at_soft_wraps: false,
13498                    stop_at_indent: action.stop_at_indent,
13499                },
13500                window,
13501                cx,
13502            );
13503            this.backspace(&Backspace, window, cx);
13504        });
13505    }
13506
13507    pub fn move_to_end_of_line(
13508        &mut self,
13509        action: &MoveToEndOfLine,
13510        window: &mut Window,
13511        cx: &mut Context<Self>,
13512    ) {
13513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.move_cursors_with(|map, head, _| {
13516                (
13517                    movement::line_end(map, head, action.stop_at_soft_wraps),
13518                    SelectionGoal::None,
13519                )
13520            });
13521        })
13522    }
13523
13524    pub fn select_to_end_of_line(
13525        &mut self,
13526        action: &SelectToEndOfLine,
13527        window: &mut Window,
13528        cx: &mut Context<Self>,
13529    ) {
13530        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13531        self.change_selections(Default::default(), window, cx, |s| {
13532            s.move_heads_with(|map, head, _| {
13533                (
13534                    movement::line_end(map, head, action.stop_at_soft_wraps),
13535                    SelectionGoal::None,
13536                )
13537            });
13538        })
13539    }
13540
13541    pub fn delete_to_end_of_line(
13542        &mut self,
13543        _: &DeleteToEndOfLine,
13544        window: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13548        self.transact(window, cx, |this, window, cx| {
13549            this.select_to_end_of_line(
13550                &SelectToEndOfLine {
13551                    stop_at_soft_wraps: false,
13552                },
13553                window,
13554                cx,
13555            );
13556            this.delete(&Delete, window, cx);
13557        });
13558    }
13559
13560    pub fn cut_to_end_of_line(
13561        &mut self,
13562        action: &CutToEndOfLine,
13563        window: &mut Window,
13564        cx: &mut Context<Self>,
13565    ) {
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13567        self.transact(window, cx, |this, window, cx| {
13568            this.select_to_end_of_line(
13569                &SelectToEndOfLine {
13570                    stop_at_soft_wraps: false,
13571                },
13572                window,
13573                cx,
13574            );
13575            if !action.stop_at_newlines {
13576                this.change_selections(Default::default(), window, cx, |s| {
13577                    s.move_with(|_, sel| {
13578                        if sel.is_empty() {
13579                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13580                        }
13581                    });
13582                });
13583            }
13584            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13585            let item = this.cut_common(false, window, cx);
13586            cx.write_to_clipboard(item);
13587        });
13588    }
13589
13590    pub fn move_to_start_of_paragraph(
13591        &mut self,
13592        _: &MoveToStartOfParagraph,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        if matches!(self.mode, EditorMode::SingleLine) {
13597            cx.propagate();
13598            return;
13599        }
13600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13601        self.change_selections(Default::default(), window, cx, |s| {
13602            s.move_with(|map, selection| {
13603                selection.collapse_to(
13604                    movement::start_of_paragraph(map, selection.head(), 1),
13605                    SelectionGoal::None,
13606                )
13607            });
13608        })
13609    }
13610
13611    pub fn move_to_end_of_paragraph(
13612        &mut self,
13613        _: &MoveToEndOfParagraph,
13614        window: &mut Window,
13615        cx: &mut Context<Self>,
13616    ) {
13617        if matches!(self.mode, EditorMode::SingleLine) {
13618            cx.propagate();
13619            return;
13620        }
13621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13622        self.change_selections(Default::default(), window, cx, |s| {
13623            s.move_with(|map, selection| {
13624                selection.collapse_to(
13625                    movement::end_of_paragraph(map, selection.head(), 1),
13626                    SelectionGoal::None,
13627                )
13628            });
13629        })
13630    }
13631
13632    pub fn select_to_start_of_paragraph(
13633        &mut self,
13634        _: &SelectToStartOfParagraph,
13635        window: &mut Window,
13636        cx: &mut Context<Self>,
13637    ) {
13638        if matches!(self.mode, EditorMode::SingleLine) {
13639            cx.propagate();
13640            return;
13641        }
13642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13643        self.change_selections(Default::default(), window, cx, |s| {
13644            s.move_heads_with(|map, head, _| {
13645                (
13646                    movement::start_of_paragraph(map, head, 1),
13647                    SelectionGoal::None,
13648                )
13649            });
13650        })
13651    }
13652
13653    pub fn select_to_end_of_paragraph(
13654        &mut self,
13655        _: &SelectToEndOfParagraph,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        if matches!(self.mode, EditorMode::SingleLine) {
13660            cx.propagate();
13661            return;
13662        }
13663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13664        self.change_selections(Default::default(), window, cx, |s| {
13665            s.move_heads_with(|map, head, _| {
13666                (
13667                    movement::end_of_paragraph(map, head, 1),
13668                    SelectionGoal::None,
13669                )
13670            });
13671        })
13672    }
13673
13674    pub fn move_to_start_of_excerpt(
13675        &mut self,
13676        _: &MoveToStartOfExcerpt,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        if matches!(self.mode, EditorMode::SingleLine) {
13681            cx.propagate();
13682            return;
13683        }
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13685        self.change_selections(Default::default(), window, cx, |s| {
13686            s.move_with(|map, selection| {
13687                selection.collapse_to(
13688                    movement::start_of_excerpt(
13689                        map,
13690                        selection.head(),
13691                        workspace::searchable::Direction::Prev,
13692                    ),
13693                    SelectionGoal::None,
13694                )
13695            });
13696        })
13697    }
13698
13699    pub fn move_to_start_of_next_excerpt(
13700        &mut self,
13701        _: &MoveToStartOfNextExcerpt,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        if matches!(self.mode, EditorMode::SingleLine) {
13706            cx.propagate();
13707            return;
13708        }
13709
13710        self.change_selections(Default::default(), window, cx, |s| {
13711            s.move_with(|map, selection| {
13712                selection.collapse_to(
13713                    movement::start_of_excerpt(
13714                        map,
13715                        selection.head(),
13716                        workspace::searchable::Direction::Next,
13717                    ),
13718                    SelectionGoal::None,
13719                )
13720            });
13721        })
13722    }
13723
13724    pub fn move_to_end_of_excerpt(
13725        &mut self,
13726        _: &MoveToEndOfExcerpt,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        if matches!(self.mode, EditorMode::SingleLine) {
13731            cx.propagate();
13732            return;
13733        }
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13735        self.change_selections(Default::default(), window, cx, |s| {
13736            s.move_with(|map, selection| {
13737                selection.collapse_to(
13738                    movement::end_of_excerpt(
13739                        map,
13740                        selection.head(),
13741                        workspace::searchable::Direction::Next,
13742                    ),
13743                    SelectionGoal::None,
13744                )
13745            });
13746        })
13747    }
13748
13749    pub fn move_to_end_of_previous_excerpt(
13750        &mut self,
13751        _: &MoveToEndOfPreviousExcerpt,
13752        window: &mut Window,
13753        cx: &mut Context<Self>,
13754    ) {
13755        if matches!(self.mode, EditorMode::SingleLine) {
13756            cx.propagate();
13757            return;
13758        }
13759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13760        self.change_selections(Default::default(), window, cx, |s| {
13761            s.move_with(|map, selection| {
13762                selection.collapse_to(
13763                    movement::end_of_excerpt(
13764                        map,
13765                        selection.head(),
13766                        workspace::searchable::Direction::Prev,
13767                    ),
13768                    SelectionGoal::None,
13769                )
13770            });
13771        })
13772    }
13773
13774    pub fn select_to_start_of_excerpt(
13775        &mut self,
13776        _: &SelectToStartOfExcerpt,
13777        window: &mut Window,
13778        cx: &mut Context<Self>,
13779    ) {
13780        if matches!(self.mode, EditorMode::SingleLine) {
13781            cx.propagate();
13782            return;
13783        }
13784        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13785        self.change_selections(Default::default(), window, cx, |s| {
13786            s.move_heads_with(|map, head, _| {
13787                (
13788                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13789                    SelectionGoal::None,
13790                )
13791            });
13792        })
13793    }
13794
13795    pub fn select_to_start_of_next_excerpt(
13796        &mut self,
13797        _: &SelectToStartOfNextExcerpt,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        if matches!(self.mode, EditorMode::SingleLine) {
13802            cx.propagate();
13803            return;
13804        }
13805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13806        self.change_selections(Default::default(), window, cx, |s| {
13807            s.move_heads_with(|map, head, _| {
13808                (
13809                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13810                    SelectionGoal::None,
13811                )
13812            });
13813        })
13814    }
13815
13816    pub fn select_to_end_of_excerpt(
13817        &mut self,
13818        _: &SelectToEndOfExcerpt,
13819        window: &mut Window,
13820        cx: &mut Context<Self>,
13821    ) {
13822        if matches!(self.mode, EditorMode::SingleLine) {
13823            cx.propagate();
13824            return;
13825        }
13826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13827        self.change_selections(Default::default(), window, cx, |s| {
13828            s.move_heads_with(|map, head, _| {
13829                (
13830                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13831                    SelectionGoal::None,
13832                )
13833            });
13834        })
13835    }
13836
13837    pub fn select_to_end_of_previous_excerpt(
13838        &mut self,
13839        _: &SelectToEndOfPreviousExcerpt,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        if matches!(self.mode, EditorMode::SingleLine) {
13844            cx.propagate();
13845            return;
13846        }
13847        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13848        self.change_selections(Default::default(), window, cx, |s| {
13849            s.move_heads_with(|map, head, _| {
13850                (
13851                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13852                    SelectionGoal::None,
13853                )
13854            });
13855        })
13856    }
13857
13858    pub fn move_to_beginning(
13859        &mut self,
13860        _: &MoveToBeginning,
13861        window: &mut Window,
13862        cx: &mut Context<Self>,
13863    ) {
13864        if matches!(self.mode, EditorMode::SingleLine) {
13865            cx.propagate();
13866            return;
13867        }
13868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.select_ranges(vec![0..0]);
13871        });
13872    }
13873
13874    pub fn select_to_beginning(
13875        &mut self,
13876        _: &SelectToBeginning,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let mut selection = self.selections.last::<Point>(cx);
13881        selection.set_head(Point::zero(), SelectionGoal::None);
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        self.change_selections(Default::default(), window, cx, |s| {
13884            s.select(vec![selection]);
13885        });
13886    }
13887
13888    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13889        if matches!(self.mode, EditorMode::SingleLine) {
13890            cx.propagate();
13891            return;
13892        }
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        let cursor = self.buffer.read(cx).read(cx).len();
13895        self.change_selections(Default::default(), window, cx, |s| {
13896            s.select_ranges(vec![cursor..cursor])
13897        });
13898    }
13899
13900    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13901        self.nav_history = nav_history;
13902    }
13903
13904    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13905        self.nav_history.as_ref()
13906    }
13907
13908    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13909        self.push_to_nav_history(
13910            self.selections.newest_anchor().head(),
13911            None,
13912            false,
13913            true,
13914            cx,
13915        );
13916    }
13917
13918    fn push_to_nav_history(
13919        &mut self,
13920        cursor_anchor: Anchor,
13921        new_position: Option<Point>,
13922        is_deactivate: bool,
13923        always: bool,
13924        cx: &mut Context<Self>,
13925    ) {
13926        if let Some(nav_history) = self.nav_history.as_mut() {
13927            let buffer = self.buffer.read(cx).read(cx);
13928            let cursor_position = cursor_anchor.to_point(&buffer);
13929            let scroll_state = self.scroll_manager.anchor();
13930            let scroll_top_row = scroll_state.top_row(&buffer);
13931            drop(buffer);
13932
13933            if let Some(new_position) = new_position {
13934                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13935                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13936                    return;
13937                }
13938            }
13939
13940            nav_history.push(
13941                Some(NavigationData {
13942                    cursor_anchor,
13943                    cursor_position,
13944                    scroll_anchor: scroll_state,
13945                    scroll_top_row,
13946                }),
13947                cx,
13948            );
13949            cx.emit(EditorEvent::PushedToNavHistory {
13950                anchor: cursor_anchor,
13951                is_deactivate,
13952            })
13953        }
13954    }
13955
13956    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13958        let buffer = self.buffer.read(cx).snapshot(cx);
13959        let mut selection = self.selections.first::<usize>(cx);
13960        selection.set_head(buffer.len(), SelectionGoal::None);
13961        self.change_selections(Default::default(), window, cx, |s| {
13962            s.select(vec![selection]);
13963        });
13964    }
13965
13966    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        let end = self.buffer.read(cx).read(cx).len();
13969        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13970            s.select_ranges(vec![0..end]);
13971        });
13972    }
13973
13974    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13977        let mut selections = self.selections.all::<Point>(cx);
13978        let max_point = display_map.buffer_snapshot.max_point();
13979        for selection in &mut selections {
13980            let rows = selection.spanned_rows(true, &display_map);
13981            selection.start = Point::new(rows.start.0, 0);
13982            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13983            selection.reversed = false;
13984        }
13985        self.change_selections(Default::default(), window, cx, |s| {
13986            s.select(selections);
13987        });
13988    }
13989
13990    pub fn split_selection_into_lines(
13991        &mut self,
13992        action: &SplitSelectionIntoLines,
13993        window: &mut Window,
13994        cx: &mut Context<Self>,
13995    ) {
13996        let selections = self
13997            .selections
13998            .all::<Point>(cx)
13999            .into_iter()
14000            .map(|selection| selection.start..selection.end)
14001            .collect::<Vec<_>>();
14002        self.unfold_ranges(&selections, true, true, cx);
14003
14004        let mut new_selection_ranges = Vec::new();
14005        {
14006            let buffer = self.buffer.read(cx).read(cx);
14007            for selection in selections {
14008                for row in selection.start.row..selection.end.row {
14009                    let line_start = Point::new(row, 0);
14010                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14011
14012                    if action.keep_selections {
14013                        // Keep the selection range for each line
14014                        let selection_start = if row == selection.start.row {
14015                            selection.start
14016                        } else {
14017                            line_start
14018                        };
14019                        new_selection_ranges.push(selection_start..line_end);
14020                    } else {
14021                        // Collapse to cursor at end of line
14022                        new_selection_ranges.push(line_end..line_end);
14023                    }
14024                }
14025
14026                let is_multiline_selection = selection.start.row != selection.end.row;
14027                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14028                // so this action feels more ergonomic when paired with other selection operations
14029                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14030                if !should_skip_last {
14031                    if action.keep_selections {
14032                        if is_multiline_selection {
14033                            let line_start = Point::new(selection.end.row, 0);
14034                            new_selection_ranges.push(line_start..selection.end);
14035                        } else {
14036                            new_selection_ranges.push(selection.start..selection.end);
14037                        }
14038                    } else {
14039                        new_selection_ranges.push(selection.end..selection.end);
14040                    }
14041                }
14042            }
14043        }
14044        self.change_selections(Default::default(), window, cx, |s| {
14045            s.select_ranges(new_selection_ranges);
14046        });
14047    }
14048
14049    pub fn add_selection_above(
14050        &mut self,
14051        _: &AddSelectionAbove,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        self.add_selection(true, window, cx);
14056    }
14057
14058    pub fn add_selection_below(
14059        &mut self,
14060        _: &AddSelectionBelow,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) {
14064        self.add_selection(false, window, cx);
14065    }
14066
14067    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14069
14070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14071        let all_selections = self.selections.all::<Point>(cx);
14072        let text_layout_details = self.text_layout_details(window);
14073
14074        let (mut columnar_selections, new_selections_to_columnarize) = {
14075            if let Some(state) = self.add_selections_state.as_ref() {
14076                let columnar_selection_ids: HashSet<_> = state
14077                    .groups
14078                    .iter()
14079                    .flat_map(|group| group.stack.iter())
14080                    .copied()
14081                    .collect();
14082
14083                all_selections
14084                    .into_iter()
14085                    .partition(|s| columnar_selection_ids.contains(&s.id))
14086            } else {
14087                (Vec::new(), all_selections)
14088            }
14089        };
14090
14091        let mut state = self
14092            .add_selections_state
14093            .take()
14094            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14095
14096        for selection in new_selections_to_columnarize {
14097            let range = selection.display_range(&display_map).sorted();
14098            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14099            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14100            let positions = start_x.min(end_x)..start_x.max(end_x);
14101            let mut stack = Vec::new();
14102            for row in range.start.row().0..=range.end.row().0 {
14103                if let Some(selection) = self.selections.build_columnar_selection(
14104                    &display_map,
14105                    DisplayRow(row),
14106                    &positions,
14107                    selection.reversed,
14108                    &text_layout_details,
14109                ) {
14110                    stack.push(selection.id);
14111                    columnar_selections.push(selection);
14112                }
14113            }
14114            if !stack.is_empty() {
14115                if above {
14116                    stack.reverse();
14117                }
14118                state.groups.push(AddSelectionsGroup { above, stack });
14119            }
14120        }
14121
14122        let mut final_selections = Vec::new();
14123        let end_row = if above {
14124            DisplayRow(0)
14125        } else {
14126            display_map.max_point().row()
14127        };
14128
14129        let mut last_added_item_per_group = HashMap::default();
14130        for group in state.groups.iter_mut() {
14131            if let Some(last_id) = group.stack.last() {
14132                last_added_item_per_group.insert(*last_id, group);
14133            }
14134        }
14135
14136        for selection in columnar_selections {
14137            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14138                if above == group.above {
14139                    let range = selection.display_range(&display_map).sorted();
14140                    debug_assert_eq!(range.start.row(), range.end.row());
14141                    let mut row = range.start.row();
14142                    let positions =
14143                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14144                            px(start)..px(end)
14145                        } else {
14146                            let start_x =
14147                                display_map.x_for_display_point(range.start, &text_layout_details);
14148                            let end_x =
14149                                display_map.x_for_display_point(range.end, &text_layout_details);
14150                            start_x.min(end_x)..start_x.max(end_x)
14151                        };
14152
14153                    let mut maybe_new_selection = None;
14154                    while row != end_row {
14155                        if above {
14156                            row.0 -= 1;
14157                        } else {
14158                            row.0 += 1;
14159                        }
14160                        if let Some(new_selection) = self.selections.build_columnar_selection(
14161                            &display_map,
14162                            row,
14163                            &positions,
14164                            selection.reversed,
14165                            &text_layout_details,
14166                        ) {
14167                            maybe_new_selection = Some(new_selection);
14168                            break;
14169                        }
14170                    }
14171
14172                    if let Some(new_selection) = maybe_new_selection {
14173                        group.stack.push(new_selection.id);
14174                        if above {
14175                            final_selections.push(new_selection);
14176                            final_selections.push(selection);
14177                        } else {
14178                            final_selections.push(selection);
14179                            final_selections.push(new_selection);
14180                        }
14181                    } else {
14182                        final_selections.push(selection);
14183                    }
14184                } else {
14185                    group.stack.pop();
14186                }
14187            } else {
14188                final_selections.push(selection);
14189            }
14190        }
14191
14192        self.change_selections(Default::default(), window, cx, |s| {
14193            s.select(final_selections);
14194        });
14195
14196        let final_selection_ids: HashSet<_> = self
14197            .selections
14198            .all::<Point>(cx)
14199            .iter()
14200            .map(|s| s.id)
14201            .collect();
14202        state.groups.retain_mut(|group| {
14203            // selections might get merged above so we remove invalid items from stacks
14204            group.stack.retain(|id| final_selection_ids.contains(id));
14205
14206            // single selection in stack can be treated as initial state
14207            group.stack.len() > 1
14208        });
14209
14210        if !state.groups.is_empty() {
14211            self.add_selections_state = Some(state);
14212        }
14213    }
14214
14215    fn select_match_ranges(
14216        &mut self,
14217        range: Range<usize>,
14218        reversed: bool,
14219        replace_newest: bool,
14220        auto_scroll: Option<Autoscroll>,
14221        window: &mut Window,
14222        cx: &mut Context<Editor>,
14223    ) {
14224        self.unfold_ranges(
14225            std::slice::from_ref(&range),
14226            false,
14227            auto_scroll.is_some(),
14228            cx,
14229        );
14230        let effects = if let Some(scroll) = auto_scroll {
14231            SelectionEffects::scroll(scroll)
14232        } else {
14233            SelectionEffects::no_scroll()
14234        };
14235        self.change_selections(effects, window, cx, |s| {
14236            if replace_newest {
14237                s.delete(s.newest_anchor().id);
14238            }
14239            if reversed {
14240                s.insert_range(range.end..range.start);
14241            } else {
14242                s.insert_range(range);
14243            }
14244        });
14245    }
14246
14247    pub fn select_next_match_internal(
14248        &mut self,
14249        display_map: &DisplaySnapshot,
14250        replace_newest: bool,
14251        autoscroll: Option<Autoscroll>,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) -> Result<()> {
14255        let buffer = &display_map.buffer_snapshot;
14256        let mut selections = self.selections.all::<usize>(cx);
14257        if let Some(mut select_next_state) = self.select_next_state.take() {
14258            let query = &select_next_state.query;
14259            if !select_next_state.done {
14260                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14261                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14262                let mut next_selected_range = None;
14263
14264                let bytes_after_last_selection =
14265                    buffer.bytes_in_range(last_selection.end..buffer.len());
14266                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14267                let query_matches = query
14268                    .stream_find_iter(bytes_after_last_selection)
14269                    .map(|result| (last_selection.end, result))
14270                    .chain(
14271                        query
14272                            .stream_find_iter(bytes_before_first_selection)
14273                            .map(|result| (0, result)),
14274                    );
14275
14276                for (start_offset, query_match) in query_matches {
14277                    let query_match = query_match.unwrap(); // can only fail due to I/O
14278                    let offset_range =
14279                        start_offset + query_match.start()..start_offset + query_match.end();
14280
14281                    if !select_next_state.wordwise
14282                        || (!buffer.is_inside_word(offset_range.start, None)
14283                            && !buffer.is_inside_word(offset_range.end, None))
14284                    {
14285                        // TODO: This is n^2, because we might check all the selections
14286                        if !selections
14287                            .iter()
14288                            .any(|selection| selection.range().overlaps(&offset_range))
14289                        {
14290                            next_selected_range = Some(offset_range);
14291                            break;
14292                        }
14293                    }
14294                }
14295
14296                if let Some(next_selected_range) = next_selected_range {
14297                    self.select_match_ranges(
14298                        next_selected_range,
14299                        last_selection.reversed,
14300                        replace_newest,
14301                        autoscroll,
14302                        window,
14303                        cx,
14304                    );
14305                } else {
14306                    select_next_state.done = true;
14307                }
14308            }
14309
14310            self.select_next_state = Some(select_next_state);
14311        } else {
14312            let mut only_carets = true;
14313            let mut same_text_selected = true;
14314            let mut selected_text = None;
14315
14316            let mut selections_iter = selections.iter().peekable();
14317            while let Some(selection) = selections_iter.next() {
14318                if selection.start != selection.end {
14319                    only_carets = false;
14320                }
14321
14322                if same_text_selected {
14323                    if selected_text.is_none() {
14324                        selected_text =
14325                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14326                    }
14327
14328                    if let Some(next_selection) = selections_iter.peek() {
14329                        if next_selection.range().len() == selection.range().len() {
14330                            let next_selected_text = buffer
14331                                .text_for_range(next_selection.range())
14332                                .collect::<String>();
14333                            if Some(next_selected_text) != selected_text {
14334                                same_text_selected = false;
14335                                selected_text = None;
14336                            }
14337                        } else {
14338                            same_text_selected = false;
14339                            selected_text = None;
14340                        }
14341                    }
14342                }
14343            }
14344
14345            if only_carets {
14346                for selection in &mut selections {
14347                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14348                    selection.start = word_range.start;
14349                    selection.end = word_range.end;
14350                    selection.goal = SelectionGoal::None;
14351                    selection.reversed = false;
14352                    self.select_match_ranges(
14353                        selection.start..selection.end,
14354                        selection.reversed,
14355                        replace_newest,
14356                        autoscroll,
14357                        window,
14358                        cx,
14359                    );
14360                }
14361
14362                if selections.len() == 1 {
14363                    let selection = selections
14364                        .last()
14365                        .expect("ensured that there's only one selection");
14366                    let query = buffer
14367                        .text_for_range(selection.start..selection.end)
14368                        .collect::<String>();
14369                    let is_empty = query.is_empty();
14370                    let select_state = SelectNextState {
14371                        query: AhoCorasick::new(&[query])?,
14372                        wordwise: true,
14373                        done: is_empty,
14374                    };
14375                    self.select_next_state = Some(select_state);
14376                } else {
14377                    self.select_next_state = None;
14378                }
14379            } else if let Some(selected_text) = selected_text {
14380                self.select_next_state = Some(SelectNextState {
14381                    query: AhoCorasick::new(&[selected_text])?,
14382                    wordwise: false,
14383                    done: false,
14384                });
14385                self.select_next_match_internal(
14386                    display_map,
14387                    replace_newest,
14388                    autoscroll,
14389                    window,
14390                    cx,
14391                )?;
14392            }
14393        }
14394        Ok(())
14395    }
14396
14397    pub fn select_all_matches(
14398        &mut self,
14399        _action: &SelectAllMatches,
14400        window: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) -> Result<()> {
14403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14404
14405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14406
14407        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14408        let Some(select_next_state) = self.select_next_state.as_mut() else {
14409            return Ok(());
14410        };
14411        if select_next_state.done {
14412            return Ok(());
14413        }
14414
14415        let mut new_selections = Vec::new();
14416
14417        let reversed = self.selections.oldest::<usize>(cx).reversed;
14418        let buffer = &display_map.buffer_snapshot;
14419        let query_matches = select_next_state
14420            .query
14421            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14422
14423        for query_match in query_matches.into_iter() {
14424            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14425            let offset_range = if reversed {
14426                query_match.end()..query_match.start()
14427            } else {
14428                query_match.start()..query_match.end()
14429            };
14430
14431            if !select_next_state.wordwise
14432                || (!buffer.is_inside_word(offset_range.start, None)
14433                    && !buffer.is_inside_word(offset_range.end, None))
14434            {
14435                new_selections.push(offset_range.start..offset_range.end);
14436            }
14437        }
14438
14439        select_next_state.done = true;
14440
14441        if new_selections.is_empty() {
14442            log::error!("bug: new_selections is empty in select_all_matches");
14443            return Ok(());
14444        }
14445
14446        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14447        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14448            selections.select_ranges(new_selections)
14449        });
14450
14451        Ok(())
14452    }
14453
14454    pub fn select_next(
14455        &mut self,
14456        action: &SelectNext,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) -> Result<()> {
14460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14462        self.select_next_match_internal(
14463            &display_map,
14464            action.replace_newest,
14465            Some(Autoscroll::newest()),
14466            window,
14467            cx,
14468        )?;
14469        Ok(())
14470    }
14471
14472    pub fn select_previous(
14473        &mut self,
14474        action: &SelectPrevious,
14475        window: &mut Window,
14476        cx: &mut Context<Self>,
14477    ) -> Result<()> {
14478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14480        let buffer = &display_map.buffer_snapshot;
14481        let mut selections = self.selections.all::<usize>(cx);
14482        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14483            let query = &select_prev_state.query;
14484            if !select_prev_state.done {
14485                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14486                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14487                let mut next_selected_range = None;
14488                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14489                let bytes_before_last_selection =
14490                    buffer.reversed_bytes_in_range(0..last_selection.start);
14491                let bytes_after_first_selection =
14492                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14493                let query_matches = query
14494                    .stream_find_iter(bytes_before_last_selection)
14495                    .map(|result| (last_selection.start, result))
14496                    .chain(
14497                        query
14498                            .stream_find_iter(bytes_after_first_selection)
14499                            .map(|result| (buffer.len(), result)),
14500                    );
14501                for (end_offset, query_match) in query_matches {
14502                    let query_match = query_match.unwrap(); // can only fail due to I/O
14503                    let offset_range =
14504                        end_offset - query_match.end()..end_offset - query_match.start();
14505
14506                    if !select_prev_state.wordwise
14507                        || (!buffer.is_inside_word(offset_range.start, None)
14508                            && !buffer.is_inside_word(offset_range.end, None))
14509                    {
14510                        next_selected_range = Some(offset_range);
14511                        break;
14512                    }
14513                }
14514
14515                if let Some(next_selected_range) = next_selected_range {
14516                    self.select_match_ranges(
14517                        next_selected_range,
14518                        last_selection.reversed,
14519                        action.replace_newest,
14520                        Some(Autoscroll::newest()),
14521                        window,
14522                        cx,
14523                    );
14524                } else {
14525                    select_prev_state.done = true;
14526                }
14527            }
14528
14529            self.select_prev_state = Some(select_prev_state);
14530        } else {
14531            let mut only_carets = true;
14532            let mut same_text_selected = true;
14533            let mut selected_text = None;
14534
14535            let mut selections_iter = selections.iter().peekable();
14536            while let Some(selection) = selections_iter.next() {
14537                if selection.start != selection.end {
14538                    only_carets = false;
14539                }
14540
14541                if same_text_selected {
14542                    if selected_text.is_none() {
14543                        selected_text =
14544                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14545                    }
14546
14547                    if let Some(next_selection) = selections_iter.peek() {
14548                        if next_selection.range().len() == selection.range().len() {
14549                            let next_selected_text = buffer
14550                                .text_for_range(next_selection.range())
14551                                .collect::<String>();
14552                            if Some(next_selected_text) != selected_text {
14553                                same_text_selected = false;
14554                                selected_text = None;
14555                            }
14556                        } else {
14557                            same_text_selected = false;
14558                            selected_text = None;
14559                        }
14560                    }
14561                }
14562            }
14563
14564            if only_carets {
14565                for selection in &mut selections {
14566                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14567                    selection.start = word_range.start;
14568                    selection.end = word_range.end;
14569                    selection.goal = SelectionGoal::None;
14570                    selection.reversed = false;
14571                    self.select_match_ranges(
14572                        selection.start..selection.end,
14573                        selection.reversed,
14574                        action.replace_newest,
14575                        Some(Autoscroll::newest()),
14576                        window,
14577                        cx,
14578                    );
14579                }
14580                if selections.len() == 1 {
14581                    let selection = selections
14582                        .last()
14583                        .expect("ensured that there's only one selection");
14584                    let query = buffer
14585                        .text_for_range(selection.start..selection.end)
14586                        .collect::<String>();
14587                    let is_empty = query.is_empty();
14588                    let select_state = SelectNextState {
14589                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14590                        wordwise: true,
14591                        done: is_empty,
14592                    };
14593                    self.select_prev_state = Some(select_state);
14594                } else {
14595                    self.select_prev_state = None;
14596                }
14597            } else if let Some(selected_text) = selected_text {
14598                self.select_prev_state = Some(SelectNextState {
14599                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14600                    wordwise: false,
14601                    done: false,
14602                });
14603                self.select_previous(action, window, cx)?;
14604            }
14605        }
14606        Ok(())
14607    }
14608
14609    pub fn find_next_match(
14610        &mut self,
14611        _: &FindNextMatch,
14612        window: &mut Window,
14613        cx: &mut Context<Self>,
14614    ) -> Result<()> {
14615        let selections = self.selections.disjoint_anchors_arc();
14616        match selections.first() {
14617            Some(first) if selections.len() >= 2 => {
14618                self.change_selections(Default::default(), window, cx, |s| {
14619                    s.select_ranges([first.range()]);
14620                });
14621            }
14622            _ => self.select_next(
14623                &SelectNext {
14624                    replace_newest: true,
14625                },
14626                window,
14627                cx,
14628            )?,
14629        }
14630        Ok(())
14631    }
14632
14633    pub fn find_previous_match(
14634        &mut self,
14635        _: &FindPreviousMatch,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) -> Result<()> {
14639        let selections = self.selections.disjoint_anchors_arc();
14640        match selections.last() {
14641            Some(last) if selections.len() >= 2 => {
14642                self.change_selections(Default::default(), window, cx, |s| {
14643                    s.select_ranges([last.range()]);
14644                });
14645            }
14646            _ => self.select_previous(
14647                &SelectPrevious {
14648                    replace_newest: true,
14649                },
14650                window,
14651                cx,
14652            )?,
14653        }
14654        Ok(())
14655    }
14656
14657    pub fn toggle_comments(
14658        &mut self,
14659        action: &ToggleComments,
14660        window: &mut Window,
14661        cx: &mut Context<Self>,
14662    ) {
14663        if self.read_only(cx) {
14664            return;
14665        }
14666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14667        let text_layout_details = &self.text_layout_details(window);
14668        self.transact(window, cx, |this, window, cx| {
14669            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14670            let mut edits = Vec::new();
14671            let mut selection_edit_ranges = Vec::new();
14672            let mut last_toggled_row = None;
14673            let snapshot = this.buffer.read(cx).read(cx);
14674            let empty_str: Arc<str> = Arc::default();
14675            let mut suffixes_inserted = Vec::new();
14676            let ignore_indent = action.ignore_indent;
14677
14678            fn comment_prefix_range(
14679                snapshot: &MultiBufferSnapshot,
14680                row: MultiBufferRow,
14681                comment_prefix: &str,
14682                comment_prefix_whitespace: &str,
14683                ignore_indent: bool,
14684            ) -> Range<Point> {
14685                let indent_size = if ignore_indent {
14686                    0
14687                } else {
14688                    snapshot.indent_size_for_line(row).len
14689                };
14690
14691                let start = Point::new(row.0, indent_size);
14692
14693                let mut line_bytes = snapshot
14694                    .bytes_in_range(start..snapshot.max_point())
14695                    .flatten()
14696                    .copied();
14697
14698                // If this line currently begins with the line comment prefix, then record
14699                // the range containing the prefix.
14700                if line_bytes
14701                    .by_ref()
14702                    .take(comment_prefix.len())
14703                    .eq(comment_prefix.bytes())
14704                {
14705                    // Include any whitespace that matches the comment prefix.
14706                    let matching_whitespace_len = line_bytes
14707                        .zip(comment_prefix_whitespace.bytes())
14708                        .take_while(|(a, b)| a == b)
14709                        .count() as u32;
14710                    let end = Point::new(
14711                        start.row,
14712                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14713                    );
14714                    start..end
14715                } else {
14716                    start..start
14717                }
14718            }
14719
14720            fn comment_suffix_range(
14721                snapshot: &MultiBufferSnapshot,
14722                row: MultiBufferRow,
14723                comment_suffix: &str,
14724                comment_suffix_has_leading_space: bool,
14725            ) -> Range<Point> {
14726                let end = Point::new(row.0, snapshot.line_len(row));
14727                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14728
14729                let mut line_end_bytes = snapshot
14730                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14731                    .flatten()
14732                    .copied();
14733
14734                let leading_space_len = if suffix_start_column > 0
14735                    && line_end_bytes.next() == Some(b' ')
14736                    && comment_suffix_has_leading_space
14737                {
14738                    1
14739                } else {
14740                    0
14741                };
14742
14743                // If this line currently begins with the line comment prefix, then record
14744                // the range containing the prefix.
14745                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14746                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14747                    start..end
14748                } else {
14749                    end..end
14750                }
14751            }
14752
14753            // TODO: Handle selections that cross excerpts
14754            for selection in &mut selections {
14755                let start_column = snapshot
14756                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14757                    .len;
14758                let language = if let Some(language) =
14759                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14760                {
14761                    language
14762                } else {
14763                    continue;
14764                };
14765
14766                selection_edit_ranges.clear();
14767
14768                // If multiple selections contain a given row, avoid processing that
14769                // row more than once.
14770                let mut start_row = MultiBufferRow(selection.start.row);
14771                if last_toggled_row == Some(start_row) {
14772                    start_row = start_row.next_row();
14773                }
14774                let end_row =
14775                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14776                        MultiBufferRow(selection.end.row - 1)
14777                    } else {
14778                        MultiBufferRow(selection.end.row)
14779                    };
14780                last_toggled_row = Some(end_row);
14781
14782                if start_row > end_row {
14783                    continue;
14784                }
14785
14786                // If the language has line comments, toggle those.
14787                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14788
14789                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14790                if ignore_indent {
14791                    full_comment_prefixes = full_comment_prefixes
14792                        .into_iter()
14793                        .map(|s| Arc::from(s.trim_end()))
14794                        .collect();
14795                }
14796
14797                if !full_comment_prefixes.is_empty() {
14798                    let first_prefix = full_comment_prefixes
14799                        .first()
14800                        .expect("prefixes is non-empty");
14801                    let prefix_trimmed_lengths = full_comment_prefixes
14802                        .iter()
14803                        .map(|p| p.trim_end_matches(' ').len())
14804                        .collect::<SmallVec<[usize; 4]>>();
14805
14806                    let mut all_selection_lines_are_comments = true;
14807
14808                    for row in start_row.0..=end_row.0 {
14809                        let row = MultiBufferRow(row);
14810                        if start_row < end_row && snapshot.is_line_blank(row) {
14811                            continue;
14812                        }
14813
14814                        let prefix_range = full_comment_prefixes
14815                            .iter()
14816                            .zip(prefix_trimmed_lengths.iter().copied())
14817                            .map(|(prefix, trimmed_prefix_len)| {
14818                                comment_prefix_range(
14819                                    snapshot.deref(),
14820                                    row,
14821                                    &prefix[..trimmed_prefix_len],
14822                                    &prefix[trimmed_prefix_len..],
14823                                    ignore_indent,
14824                                )
14825                            })
14826                            .max_by_key(|range| range.end.column - range.start.column)
14827                            .expect("prefixes is non-empty");
14828
14829                        if prefix_range.is_empty() {
14830                            all_selection_lines_are_comments = false;
14831                        }
14832
14833                        selection_edit_ranges.push(prefix_range);
14834                    }
14835
14836                    if all_selection_lines_are_comments {
14837                        edits.extend(
14838                            selection_edit_ranges
14839                                .iter()
14840                                .cloned()
14841                                .map(|range| (range, empty_str.clone())),
14842                        );
14843                    } else {
14844                        let min_column = selection_edit_ranges
14845                            .iter()
14846                            .map(|range| range.start.column)
14847                            .min()
14848                            .unwrap_or(0);
14849                        edits.extend(selection_edit_ranges.iter().map(|range| {
14850                            let position = Point::new(range.start.row, min_column);
14851                            (position..position, first_prefix.clone())
14852                        }));
14853                    }
14854                } else if let Some(BlockCommentConfig {
14855                    start: full_comment_prefix,
14856                    end: comment_suffix,
14857                    ..
14858                }) = language.block_comment()
14859                {
14860                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14861                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14862                    let prefix_range = comment_prefix_range(
14863                        snapshot.deref(),
14864                        start_row,
14865                        comment_prefix,
14866                        comment_prefix_whitespace,
14867                        ignore_indent,
14868                    );
14869                    let suffix_range = comment_suffix_range(
14870                        snapshot.deref(),
14871                        end_row,
14872                        comment_suffix.trim_start_matches(' '),
14873                        comment_suffix.starts_with(' '),
14874                    );
14875
14876                    if prefix_range.is_empty() || suffix_range.is_empty() {
14877                        edits.push((
14878                            prefix_range.start..prefix_range.start,
14879                            full_comment_prefix.clone(),
14880                        ));
14881                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14882                        suffixes_inserted.push((end_row, comment_suffix.len()));
14883                    } else {
14884                        edits.push((prefix_range, empty_str.clone()));
14885                        edits.push((suffix_range, empty_str.clone()));
14886                    }
14887                } else {
14888                    continue;
14889                }
14890            }
14891
14892            drop(snapshot);
14893            this.buffer.update(cx, |buffer, cx| {
14894                buffer.edit(edits, None, cx);
14895            });
14896
14897            // Adjust selections so that they end before any comment suffixes that
14898            // were inserted.
14899            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14900            let mut selections = this.selections.all::<Point>(cx);
14901            let snapshot = this.buffer.read(cx).read(cx);
14902            for selection in &mut selections {
14903                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14904                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14905                        Ordering::Less => {
14906                            suffixes_inserted.next();
14907                            continue;
14908                        }
14909                        Ordering::Greater => break,
14910                        Ordering::Equal => {
14911                            if selection.end.column == snapshot.line_len(row) {
14912                                if selection.is_empty() {
14913                                    selection.start.column -= suffix_len as u32;
14914                                }
14915                                selection.end.column -= suffix_len as u32;
14916                            }
14917                            break;
14918                        }
14919                    }
14920                }
14921            }
14922
14923            drop(snapshot);
14924            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14925
14926            let selections = this.selections.all::<Point>(cx);
14927            let selections_on_single_row = selections.windows(2).all(|selections| {
14928                selections[0].start.row == selections[1].start.row
14929                    && selections[0].end.row == selections[1].end.row
14930                    && selections[0].start.row == selections[0].end.row
14931            });
14932            let selections_selecting = selections
14933                .iter()
14934                .any(|selection| selection.start != selection.end);
14935            let advance_downwards = action.advance_downwards
14936                && selections_on_single_row
14937                && !selections_selecting
14938                && !matches!(this.mode, EditorMode::SingleLine);
14939
14940            if advance_downwards {
14941                let snapshot = this.buffer.read(cx).snapshot(cx);
14942
14943                this.change_selections(Default::default(), window, cx, |s| {
14944                    s.move_cursors_with(|display_snapshot, display_point, _| {
14945                        let mut point = display_point.to_point(display_snapshot);
14946                        point.row += 1;
14947                        point = snapshot.clip_point(point, Bias::Left);
14948                        let display_point = point.to_display_point(display_snapshot);
14949                        let goal = SelectionGoal::HorizontalPosition(
14950                            display_snapshot
14951                                .x_for_display_point(display_point, text_layout_details)
14952                                .into(),
14953                        );
14954                        (display_point, goal)
14955                    })
14956                });
14957            }
14958        });
14959    }
14960
14961    pub fn select_enclosing_symbol(
14962        &mut self,
14963        _: &SelectEnclosingSymbol,
14964        window: &mut Window,
14965        cx: &mut Context<Self>,
14966    ) {
14967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14968
14969        let buffer = self.buffer.read(cx).snapshot(cx);
14970        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14971
14972        fn update_selection(
14973            selection: &Selection<usize>,
14974            buffer_snap: &MultiBufferSnapshot,
14975        ) -> Option<Selection<usize>> {
14976            let cursor = selection.head();
14977            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14978            for symbol in symbols.iter().rev() {
14979                let start = symbol.range.start.to_offset(buffer_snap);
14980                let end = symbol.range.end.to_offset(buffer_snap);
14981                let new_range = start..end;
14982                if start < selection.start || end > selection.end {
14983                    return Some(Selection {
14984                        id: selection.id,
14985                        start: new_range.start,
14986                        end: new_range.end,
14987                        goal: SelectionGoal::None,
14988                        reversed: selection.reversed,
14989                    });
14990                }
14991            }
14992            None
14993        }
14994
14995        let mut selected_larger_symbol = false;
14996        let new_selections = old_selections
14997            .iter()
14998            .map(|selection| match update_selection(selection, &buffer) {
14999                Some(new_selection) => {
15000                    if new_selection.range() != selection.range() {
15001                        selected_larger_symbol = true;
15002                    }
15003                    new_selection
15004                }
15005                None => selection.clone(),
15006            })
15007            .collect::<Vec<_>>();
15008
15009        if selected_larger_symbol {
15010            self.change_selections(Default::default(), window, cx, |s| {
15011                s.select(new_selections);
15012            });
15013        }
15014    }
15015
15016    pub fn select_larger_syntax_node(
15017        &mut self,
15018        _: &SelectLargerSyntaxNode,
15019        window: &mut Window,
15020        cx: &mut Context<Self>,
15021    ) {
15022        let Some(visible_row_count) = self.visible_row_count() else {
15023            return;
15024        };
15025        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15026        if old_selections.is_empty() {
15027            return;
15028        }
15029
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031
15032        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15033        let buffer = self.buffer.read(cx).snapshot(cx);
15034
15035        let mut selected_larger_node = false;
15036        let mut new_selections = old_selections
15037            .iter()
15038            .map(|selection| {
15039                let old_range = selection.start..selection.end;
15040
15041                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15042                    // manually select word at selection
15043                    if ["string_content", "inline"].contains(&node.kind()) {
15044                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15045                        // ignore if word is already selected
15046                        if !word_range.is_empty() && old_range != word_range {
15047                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15048                            // only select word if start and end point belongs to same word
15049                            if word_range == last_word_range {
15050                                selected_larger_node = true;
15051                                return Selection {
15052                                    id: selection.id,
15053                                    start: word_range.start,
15054                                    end: word_range.end,
15055                                    goal: SelectionGoal::None,
15056                                    reversed: selection.reversed,
15057                                };
15058                            }
15059                        }
15060                    }
15061                }
15062
15063                let mut new_range = old_range.clone();
15064                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15065                {
15066                    new_range = match containing_range {
15067                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15068                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15069                    };
15070                    if !node.is_named() {
15071                        continue;
15072                    }
15073                    if !display_map.intersects_fold(new_range.start)
15074                        && !display_map.intersects_fold(new_range.end)
15075                    {
15076                        break;
15077                    }
15078                }
15079
15080                selected_larger_node |= new_range != old_range;
15081                Selection {
15082                    id: selection.id,
15083                    start: new_range.start,
15084                    end: new_range.end,
15085                    goal: SelectionGoal::None,
15086                    reversed: selection.reversed,
15087                }
15088            })
15089            .collect::<Vec<_>>();
15090
15091        if !selected_larger_node {
15092            return; // don't put this call in the history
15093        }
15094
15095        // scroll based on transformation done to the last selection created by the user
15096        let (last_old, last_new) = old_selections
15097            .last()
15098            .zip(new_selections.last().cloned())
15099            .expect("old_selections isn't empty");
15100
15101        // revert selection
15102        let is_selection_reversed = {
15103            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15104            new_selections.last_mut().expect("checked above").reversed =
15105                should_newest_selection_be_reversed;
15106            should_newest_selection_be_reversed
15107        };
15108
15109        if selected_larger_node {
15110            self.select_syntax_node_history.disable_clearing = true;
15111            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15112                s.select(new_selections.clone());
15113            });
15114            self.select_syntax_node_history.disable_clearing = false;
15115        }
15116
15117        let start_row = last_new.start.to_display_point(&display_map).row().0;
15118        let end_row = last_new.end.to_display_point(&display_map).row().0;
15119        let selection_height = end_row - start_row + 1;
15120        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15121
15122        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15123        let scroll_behavior = if fits_on_the_screen {
15124            self.request_autoscroll(Autoscroll::fit(), cx);
15125            SelectSyntaxNodeScrollBehavior::FitSelection
15126        } else if is_selection_reversed {
15127            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15128            SelectSyntaxNodeScrollBehavior::CursorTop
15129        } else {
15130            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15131            SelectSyntaxNodeScrollBehavior::CursorBottom
15132        };
15133
15134        self.select_syntax_node_history.push((
15135            old_selections,
15136            scroll_behavior,
15137            is_selection_reversed,
15138        ));
15139    }
15140
15141    pub fn select_smaller_syntax_node(
15142        &mut self,
15143        _: &SelectSmallerSyntaxNode,
15144        window: &mut Window,
15145        cx: &mut Context<Self>,
15146    ) {
15147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15148
15149        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15150            self.select_syntax_node_history.pop()
15151        {
15152            if let Some(selection) = selections.last_mut() {
15153                selection.reversed = is_selection_reversed;
15154            }
15155
15156            self.select_syntax_node_history.disable_clearing = true;
15157            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15158                s.select(selections.to_vec());
15159            });
15160            self.select_syntax_node_history.disable_clearing = false;
15161
15162            match scroll_behavior {
15163                SelectSyntaxNodeScrollBehavior::CursorTop => {
15164                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15165                }
15166                SelectSyntaxNodeScrollBehavior::FitSelection => {
15167                    self.request_autoscroll(Autoscroll::fit(), cx);
15168                }
15169                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15170                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15171                }
15172            }
15173        }
15174    }
15175
15176    pub fn unwrap_syntax_node(
15177        &mut self,
15178        _: &UnwrapSyntaxNode,
15179        window: &mut Window,
15180        cx: &mut Context<Self>,
15181    ) {
15182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15183
15184        let buffer = self.buffer.read(cx).snapshot(cx);
15185        let selections = self
15186            .selections
15187            .all::<usize>(cx)
15188            .into_iter()
15189            // subtracting the offset requires sorting
15190            .sorted_by_key(|i| i.start);
15191
15192        let full_edits = selections
15193            .into_iter()
15194            .filter_map(|selection| {
15195                let child = if selection.is_empty()
15196                    && let Some((_, ancestor_range)) =
15197                        buffer.syntax_ancestor(selection.start..selection.end)
15198                {
15199                    match ancestor_range {
15200                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15201                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15202                    }
15203                } else {
15204                    selection.range()
15205                };
15206
15207                let mut parent = child.clone();
15208                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15209                    parent = match ancestor_range {
15210                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15211                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15212                    };
15213                    if parent.start < child.start || parent.end > child.end {
15214                        break;
15215                    }
15216                }
15217
15218                if parent == child {
15219                    return None;
15220                }
15221                let text = buffer.text_for_range(child).collect::<String>();
15222                Some((selection.id, parent, text))
15223            })
15224            .collect::<Vec<_>>();
15225        if full_edits.is_empty() {
15226            return;
15227        }
15228
15229        self.transact(window, cx, |this, window, cx| {
15230            this.buffer.update(cx, |buffer, cx| {
15231                buffer.edit(
15232                    full_edits
15233                        .iter()
15234                        .map(|(_, p, t)| (p.clone(), t.clone()))
15235                        .collect::<Vec<_>>(),
15236                    None,
15237                    cx,
15238                );
15239            });
15240            this.change_selections(Default::default(), window, cx, |s| {
15241                let mut offset = 0;
15242                let mut selections = vec![];
15243                for (id, parent, text) in full_edits {
15244                    let start = parent.start - offset;
15245                    offset += parent.len() - text.len();
15246                    selections.push(Selection {
15247                        id,
15248                        start,
15249                        end: start + text.len(),
15250                        reversed: false,
15251                        goal: Default::default(),
15252                    });
15253                }
15254                s.select(selections);
15255            });
15256        });
15257    }
15258
15259    pub fn select_next_syntax_node(
15260        &mut self,
15261        _: &SelectNextSyntaxNode,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15266        if old_selections.is_empty() {
15267            return;
15268        }
15269
15270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15271
15272        let buffer = self.buffer.read(cx).snapshot(cx);
15273        let mut selected_sibling = false;
15274
15275        let new_selections = old_selections
15276            .iter()
15277            .map(|selection| {
15278                let old_range = selection.start..selection.end;
15279
15280                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15281                    let new_range = node.byte_range();
15282                    selected_sibling = true;
15283                    Selection {
15284                        id: selection.id,
15285                        start: new_range.start,
15286                        end: new_range.end,
15287                        goal: SelectionGoal::None,
15288                        reversed: selection.reversed,
15289                    }
15290                } else {
15291                    selection.clone()
15292                }
15293            })
15294            .collect::<Vec<_>>();
15295
15296        if selected_sibling {
15297            self.change_selections(
15298                SelectionEffects::scroll(Autoscroll::fit()),
15299                window,
15300                cx,
15301                |s| {
15302                    s.select(new_selections);
15303                },
15304            );
15305        }
15306    }
15307
15308    pub fn select_prev_syntax_node(
15309        &mut self,
15310        _: &SelectPreviousSyntaxNode,
15311        window: &mut Window,
15312        cx: &mut Context<Self>,
15313    ) {
15314        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15315        if old_selections.is_empty() {
15316            return;
15317        }
15318
15319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15320
15321        let buffer = self.buffer.read(cx).snapshot(cx);
15322        let mut selected_sibling = false;
15323
15324        let new_selections = old_selections
15325            .iter()
15326            .map(|selection| {
15327                let old_range = selection.start..selection.end;
15328
15329                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15330                    let new_range = node.byte_range();
15331                    selected_sibling = true;
15332                    Selection {
15333                        id: selection.id,
15334                        start: new_range.start,
15335                        end: new_range.end,
15336                        goal: SelectionGoal::None,
15337                        reversed: selection.reversed,
15338                    }
15339                } else {
15340                    selection.clone()
15341                }
15342            })
15343            .collect::<Vec<_>>();
15344
15345        if selected_sibling {
15346            self.change_selections(
15347                SelectionEffects::scroll(Autoscroll::fit()),
15348                window,
15349                cx,
15350                |s| {
15351                    s.select(new_selections);
15352                },
15353            );
15354        }
15355    }
15356
15357    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15358        if !EditorSettings::get_global(cx).gutter.runnables {
15359            self.clear_tasks();
15360            return Task::ready(());
15361        }
15362        let project = self.project().map(Entity::downgrade);
15363        let task_sources = self.lsp_task_sources(cx);
15364        let multi_buffer = self.buffer.downgrade();
15365        cx.spawn_in(window, async move |editor, cx| {
15366            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15367            let Some(project) = project.and_then(|p| p.upgrade()) else {
15368                return;
15369            };
15370            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15371                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15372            }) else {
15373                return;
15374            };
15375
15376            let hide_runnables = project
15377                .update(cx, |project, _| project.is_via_collab())
15378                .unwrap_or(true);
15379            if hide_runnables {
15380                return;
15381            }
15382            let new_rows =
15383                cx.background_spawn({
15384                    let snapshot = display_snapshot.clone();
15385                    async move {
15386                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15387                    }
15388                })
15389                    .await;
15390            let Ok(lsp_tasks) =
15391                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15392            else {
15393                return;
15394            };
15395            let lsp_tasks = lsp_tasks.await;
15396
15397            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15398                lsp_tasks
15399                    .into_iter()
15400                    .flat_map(|(kind, tasks)| {
15401                        tasks.into_iter().filter_map(move |(location, task)| {
15402                            Some((kind.clone(), location?, task))
15403                        })
15404                    })
15405                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15406                        let buffer = location.target.buffer;
15407                        let buffer_snapshot = buffer.read(cx).snapshot();
15408                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15409                            |(excerpt_id, snapshot, _)| {
15410                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15411                                    display_snapshot
15412                                        .buffer_snapshot
15413                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15414                                } else {
15415                                    None
15416                                }
15417                            },
15418                        );
15419                        if let Some(offset) = offset {
15420                            let task_buffer_range =
15421                                location.target.range.to_point(&buffer_snapshot);
15422                            let context_buffer_range =
15423                                task_buffer_range.to_offset(&buffer_snapshot);
15424                            let context_range = BufferOffset(context_buffer_range.start)
15425                                ..BufferOffset(context_buffer_range.end);
15426
15427                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15428                                .or_insert_with(|| RunnableTasks {
15429                                    templates: Vec::new(),
15430                                    offset,
15431                                    column: task_buffer_range.start.column,
15432                                    extra_variables: HashMap::default(),
15433                                    context_range,
15434                                })
15435                                .templates
15436                                .push((kind, task.original_task().clone()));
15437                        }
15438
15439                        acc
15440                    })
15441            }) else {
15442                return;
15443            };
15444
15445            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15446                buffer.language_settings(cx).tasks.prefer_lsp
15447            }) else {
15448                return;
15449            };
15450
15451            let rows = Self::runnable_rows(
15452                project,
15453                display_snapshot,
15454                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15455                new_rows,
15456                cx.clone(),
15457            )
15458            .await;
15459            editor
15460                .update(cx, |editor, _| {
15461                    editor.clear_tasks();
15462                    for (key, mut value) in rows {
15463                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15464                            value.templates.extend(lsp_tasks.templates);
15465                        }
15466
15467                        editor.insert_tasks(key, value);
15468                    }
15469                    for (key, value) in lsp_tasks_by_rows {
15470                        editor.insert_tasks(key, value);
15471                    }
15472                })
15473                .ok();
15474        })
15475    }
15476    fn fetch_runnable_ranges(
15477        snapshot: &DisplaySnapshot,
15478        range: Range<Anchor>,
15479    ) -> Vec<language::RunnableRange> {
15480        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15481    }
15482
15483    fn runnable_rows(
15484        project: Entity<Project>,
15485        snapshot: DisplaySnapshot,
15486        prefer_lsp: bool,
15487        runnable_ranges: Vec<RunnableRange>,
15488        cx: AsyncWindowContext,
15489    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15490        cx.spawn(async move |cx| {
15491            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15492            for mut runnable in runnable_ranges {
15493                let Some(tasks) = cx
15494                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15495                    .ok()
15496                else {
15497                    continue;
15498                };
15499                let mut tasks = tasks.await;
15500
15501                if prefer_lsp {
15502                    tasks.retain(|(task_kind, _)| {
15503                        !matches!(task_kind, TaskSourceKind::Language { .. })
15504                    });
15505                }
15506                if tasks.is_empty() {
15507                    continue;
15508                }
15509
15510                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15511                let Some(row) = snapshot
15512                    .buffer_snapshot
15513                    .buffer_line_for_row(MultiBufferRow(point.row))
15514                    .map(|(_, range)| range.start.row)
15515                else {
15516                    continue;
15517                };
15518
15519                let context_range =
15520                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15521                runnable_rows.push((
15522                    (runnable.buffer_id, row),
15523                    RunnableTasks {
15524                        templates: tasks,
15525                        offset: snapshot
15526                            .buffer_snapshot
15527                            .anchor_before(runnable.run_range.start),
15528                        context_range,
15529                        column: point.column,
15530                        extra_variables: runnable.extra_captures,
15531                    },
15532                ));
15533            }
15534            runnable_rows
15535        })
15536    }
15537
15538    fn templates_with_tags(
15539        project: &Entity<Project>,
15540        runnable: &mut Runnable,
15541        cx: &mut App,
15542    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15543        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15544            let (worktree_id, file) = project
15545                .buffer_for_id(runnable.buffer, cx)
15546                .and_then(|buffer| buffer.read(cx).file())
15547                .map(|file| (file.worktree_id(cx), file.clone()))
15548                .unzip();
15549
15550            (
15551                project.task_store().read(cx).task_inventory().cloned(),
15552                worktree_id,
15553                file,
15554            )
15555        });
15556
15557        let tags = mem::take(&mut runnable.tags);
15558        let language = runnable.language.clone();
15559        cx.spawn(async move |cx| {
15560            let mut templates_with_tags = Vec::new();
15561            if let Some(inventory) = inventory {
15562                for RunnableTag(tag) in tags {
15563                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15564                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15565                    }) else {
15566                        return templates_with_tags;
15567                    };
15568                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15569                        move |(_, template)| {
15570                            template.tags.iter().any(|source_tag| source_tag == &tag)
15571                        },
15572                    ));
15573                }
15574            }
15575            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15576
15577            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15578                // Strongest source wins; if we have worktree tag binding, prefer that to
15579                // global and language bindings;
15580                // if we have a global binding, prefer that to language binding.
15581                let first_mismatch = templates_with_tags
15582                    .iter()
15583                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15584                if let Some(index) = first_mismatch {
15585                    templates_with_tags.truncate(index);
15586                }
15587            }
15588
15589            templates_with_tags
15590        })
15591    }
15592
15593    pub fn move_to_enclosing_bracket(
15594        &mut self,
15595        _: &MoveToEnclosingBracket,
15596        window: &mut Window,
15597        cx: &mut Context<Self>,
15598    ) {
15599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15600        self.change_selections(Default::default(), window, cx, |s| {
15601            s.move_offsets_with(|snapshot, selection| {
15602                let Some(enclosing_bracket_ranges) =
15603                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15604                else {
15605                    return;
15606                };
15607
15608                let mut best_length = usize::MAX;
15609                let mut best_inside = false;
15610                let mut best_in_bracket_range = false;
15611                let mut best_destination = None;
15612                for (open, close) in enclosing_bracket_ranges {
15613                    let close = close.to_inclusive();
15614                    let length = close.end() - open.start;
15615                    let inside = selection.start >= open.end && selection.end <= *close.start();
15616                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15617                        || close.contains(&selection.head());
15618
15619                    // If best is next to a bracket and current isn't, skip
15620                    if !in_bracket_range && best_in_bracket_range {
15621                        continue;
15622                    }
15623
15624                    // Prefer smaller lengths unless best is inside and current isn't
15625                    if length > best_length && (best_inside || !inside) {
15626                        continue;
15627                    }
15628
15629                    best_length = length;
15630                    best_inside = inside;
15631                    best_in_bracket_range = in_bracket_range;
15632                    best_destination = Some(
15633                        if close.contains(&selection.start) && close.contains(&selection.end) {
15634                            if inside { open.end } else { open.start }
15635                        } else if inside {
15636                            *close.start()
15637                        } else {
15638                            *close.end()
15639                        },
15640                    );
15641                }
15642
15643                if let Some(destination) = best_destination {
15644                    selection.collapse_to(destination, SelectionGoal::None);
15645                }
15646            })
15647        });
15648    }
15649
15650    pub fn undo_selection(
15651        &mut self,
15652        _: &UndoSelection,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) {
15656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15657        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15658            self.selection_history.mode = SelectionHistoryMode::Undoing;
15659            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15660                this.end_selection(window, cx);
15661                this.change_selections(
15662                    SelectionEffects::scroll(Autoscroll::newest()),
15663                    window,
15664                    cx,
15665                    |s| s.select_anchors(entry.selections.to_vec()),
15666                );
15667            });
15668            self.selection_history.mode = SelectionHistoryMode::Normal;
15669
15670            self.select_next_state = entry.select_next_state;
15671            self.select_prev_state = entry.select_prev_state;
15672            self.add_selections_state = entry.add_selections_state;
15673        }
15674    }
15675
15676    pub fn redo_selection(
15677        &mut self,
15678        _: &RedoSelection,
15679        window: &mut Window,
15680        cx: &mut Context<Self>,
15681    ) {
15682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15683        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15684            self.selection_history.mode = SelectionHistoryMode::Redoing;
15685            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15686                this.end_selection(window, cx);
15687                this.change_selections(
15688                    SelectionEffects::scroll(Autoscroll::newest()),
15689                    window,
15690                    cx,
15691                    |s| s.select_anchors(entry.selections.to_vec()),
15692                );
15693            });
15694            self.selection_history.mode = SelectionHistoryMode::Normal;
15695
15696            self.select_next_state = entry.select_next_state;
15697            self.select_prev_state = entry.select_prev_state;
15698            self.add_selections_state = entry.add_selections_state;
15699        }
15700    }
15701
15702    pub fn expand_excerpts(
15703        &mut self,
15704        action: &ExpandExcerpts,
15705        _: &mut Window,
15706        cx: &mut Context<Self>,
15707    ) {
15708        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15709    }
15710
15711    pub fn expand_excerpts_down(
15712        &mut self,
15713        action: &ExpandExcerptsDown,
15714        _: &mut Window,
15715        cx: &mut Context<Self>,
15716    ) {
15717        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15718    }
15719
15720    pub fn expand_excerpts_up(
15721        &mut self,
15722        action: &ExpandExcerptsUp,
15723        _: &mut Window,
15724        cx: &mut Context<Self>,
15725    ) {
15726        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15727    }
15728
15729    pub fn expand_excerpts_for_direction(
15730        &mut self,
15731        lines: u32,
15732        direction: ExpandExcerptDirection,
15733
15734        cx: &mut Context<Self>,
15735    ) {
15736        let selections = self.selections.disjoint_anchors_arc();
15737
15738        let lines = if lines == 0 {
15739            EditorSettings::get_global(cx).expand_excerpt_lines
15740        } else {
15741            lines
15742        };
15743
15744        self.buffer.update(cx, |buffer, cx| {
15745            let snapshot = buffer.snapshot(cx);
15746            let mut excerpt_ids = selections
15747                .iter()
15748                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15749                .collect::<Vec<_>>();
15750            excerpt_ids.sort();
15751            excerpt_ids.dedup();
15752            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15753        })
15754    }
15755
15756    pub fn expand_excerpt(
15757        &mut self,
15758        excerpt: ExcerptId,
15759        direction: ExpandExcerptDirection,
15760        window: &mut Window,
15761        cx: &mut Context<Self>,
15762    ) {
15763        let current_scroll_position = self.scroll_position(cx);
15764        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15765        let mut should_scroll_up = false;
15766
15767        if direction == ExpandExcerptDirection::Down {
15768            let multi_buffer = self.buffer.read(cx);
15769            let snapshot = multi_buffer.snapshot(cx);
15770            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15771                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15772                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15773            {
15774                let buffer_snapshot = buffer.read(cx).snapshot();
15775                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15776                let last_row = buffer_snapshot.max_point().row;
15777                let lines_below = last_row.saturating_sub(excerpt_end_row);
15778                should_scroll_up = lines_below >= lines_to_expand;
15779            }
15780        }
15781
15782        self.buffer.update(cx, |buffer, cx| {
15783            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15784        });
15785
15786        if should_scroll_up {
15787            let new_scroll_position =
15788                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15789            self.set_scroll_position(new_scroll_position, window, cx);
15790        }
15791    }
15792
15793    pub fn go_to_singleton_buffer_point(
15794        &mut self,
15795        point: Point,
15796        window: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        self.go_to_singleton_buffer_range(point..point, window, cx);
15800    }
15801
15802    pub fn go_to_singleton_buffer_range(
15803        &mut self,
15804        range: Range<Point>,
15805        window: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        let multibuffer = self.buffer().read(cx);
15809        let Some(buffer) = multibuffer.as_singleton() else {
15810            return;
15811        };
15812        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15813            return;
15814        };
15815        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15816            return;
15817        };
15818        self.change_selections(
15819            SelectionEffects::default().nav_history(true),
15820            window,
15821            cx,
15822            |s| s.select_anchor_ranges([start..end]),
15823        );
15824    }
15825
15826    pub fn go_to_diagnostic(
15827        &mut self,
15828        action: &GoToDiagnostic,
15829        window: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        if !self.diagnostics_enabled() {
15833            return;
15834        }
15835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15836        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15837    }
15838
15839    pub fn go_to_prev_diagnostic(
15840        &mut self,
15841        action: &GoToPreviousDiagnostic,
15842        window: &mut Window,
15843        cx: &mut Context<Self>,
15844    ) {
15845        if !self.diagnostics_enabled() {
15846            return;
15847        }
15848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15849        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15850    }
15851
15852    pub fn go_to_diagnostic_impl(
15853        &mut self,
15854        direction: Direction,
15855        severity: GoToDiagnosticSeverityFilter,
15856        window: &mut Window,
15857        cx: &mut Context<Self>,
15858    ) {
15859        let buffer = self.buffer.read(cx).snapshot(cx);
15860        let selection = self.selections.newest::<usize>(cx);
15861
15862        let mut active_group_id = None;
15863        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15864            && active_group.active_range.start.to_offset(&buffer) == selection.start
15865        {
15866            active_group_id = Some(active_group.group_id);
15867        }
15868
15869        fn filtered(
15870            snapshot: EditorSnapshot,
15871            severity: GoToDiagnosticSeverityFilter,
15872            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15873        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15874            diagnostics
15875                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15876                .filter(|entry| entry.range.start != entry.range.end)
15877                .filter(|entry| !entry.diagnostic.is_unnecessary)
15878                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15879        }
15880
15881        let snapshot = self.snapshot(window, cx);
15882        let before = filtered(
15883            snapshot.clone(),
15884            severity,
15885            buffer
15886                .diagnostics_in_range(0..selection.start)
15887                .filter(|entry| entry.range.start <= selection.start),
15888        );
15889        let after = filtered(
15890            snapshot,
15891            severity,
15892            buffer
15893                .diagnostics_in_range(selection.start..buffer.len())
15894                .filter(|entry| entry.range.start >= selection.start),
15895        );
15896
15897        let mut found: Option<DiagnosticEntry<usize>> = None;
15898        if direction == Direction::Prev {
15899            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15900            {
15901                for diagnostic in prev_diagnostics.into_iter().rev() {
15902                    if diagnostic.range.start != selection.start
15903                        || active_group_id
15904                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15905                    {
15906                        found = Some(diagnostic);
15907                        break 'outer;
15908                    }
15909                }
15910            }
15911        } else {
15912            for diagnostic in after.chain(before) {
15913                if diagnostic.range.start != selection.start
15914                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15915                {
15916                    found = Some(diagnostic);
15917                    break;
15918                }
15919            }
15920        }
15921        let Some(next_diagnostic) = found else {
15922            return;
15923        };
15924
15925        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15926        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15927            return;
15928        };
15929        self.change_selections(Default::default(), window, cx, |s| {
15930            s.select_ranges(vec![
15931                next_diagnostic.range.start..next_diagnostic.range.start,
15932            ])
15933        });
15934        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15935        self.refresh_edit_prediction(false, true, window, cx);
15936    }
15937
15938    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15940        let snapshot = self.snapshot(window, cx);
15941        let selection = self.selections.newest::<Point>(cx);
15942        self.go_to_hunk_before_or_after_position(
15943            &snapshot,
15944            selection.head(),
15945            Direction::Next,
15946            window,
15947            cx,
15948        );
15949    }
15950
15951    pub fn go_to_hunk_before_or_after_position(
15952        &mut self,
15953        snapshot: &EditorSnapshot,
15954        position: Point,
15955        direction: Direction,
15956        window: &mut Window,
15957        cx: &mut Context<Editor>,
15958    ) {
15959        let row = if direction == Direction::Next {
15960            self.hunk_after_position(snapshot, position)
15961                .map(|hunk| hunk.row_range.start)
15962        } else {
15963            self.hunk_before_position(snapshot, position)
15964        };
15965
15966        if let Some(row) = row {
15967            let destination = Point::new(row.0, 0);
15968            let autoscroll = Autoscroll::center();
15969
15970            self.unfold_ranges(&[destination..destination], false, false, cx);
15971            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15972                s.select_ranges([destination..destination]);
15973            });
15974        }
15975    }
15976
15977    fn hunk_after_position(
15978        &mut self,
15979        snapshot: &EditorSnapshot,
15980        position: Point,
15981    ) -> Option<MultiBufferDiffHunk> {
15982        snapshot
15983            .buffer_snapshot
15984            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15985            .find(|hunk| hunk.row_range.start.0 > position.row)
15986            .or_else(|| {
15987                snapshot
15988                    .buffer_snapshot
15989                    .diff_hunks_in_range(Point::zero()..position)
15990                    .find(|hunk| hunk.row_range.end.0 < position.row)
15991            })
15992    }
15993
15994    fn go_to_prev_hunk(
15995        &mut self,
15996        _: &GoToPreviousHunk,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16001        let snapshot = self.snapshot(window, cx);
16002        let selection = self.selections.newest::<Point>(cx);
16003        self.go_to_hunk_before_or_after_position(
16004            &snapshot,
16005            selection.head(),
16006            Direction::Prev,
16007            window,
16008            cx,
16009        );
16010    }
16011
16012    fn hunk_before_position(
16013        &mut self,
16014        snapshot: &EditorSnapshot,
16015        position: Point,
16016    ) -> Option<MultiBufferRow> {
16017        snapshot
16018            .buffer_snapshot
16019            .diff_hunk_before(position)
16020            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16021    }
16022
16023    fn go_to_next_change(
16024        &mut self,
16025        _: &GoToNextChange,
16026        window: &mut Window,
16027        cx: &mut Context<Self>,
16028    ) {
16029        if let Some(selections) = self
16030            .change_list
16031            .next_change(1, Direction::Next)
16032            .map(|s| s.to_vec())
16033        {
16034            self.change_selections(Default::default(), window, cx, |s| {
16035                let map = s.display_map();
16036                s.select_display_ranges(selections.iter().map(|a| {
16037                    let point = a.to_display_point(&map);
16038                    point..point
16039                }))
16040            })
16041        }
16042    }
16043
16044    fn go_to_previous_change(
16045        &mut self,
16046        _: &GoToPreviousChange,
16047        window: &mut Window,
16048        cx: &mut Context<Self>,
16049    ) {
16050        if let Some(selections) = self
16051            .change_list
16052            .next_change(1, Direction::Prev)
16053            .map(|s| s.to_vec())
16054        {
16055            self.change_selections(Default::default(), window, cx, |s| {
16056                let map = s.display_map();
16057                s.select_display_ranges(selections.iter().map(|a| {
16058                    let point = a.to_display_point(&map);
16059                    point..point
16060                }))
16061            })
16062        }
16063    }
16064
16065    pub fn go_to_next_document_highlight(
16066        &mut self,
16067        _: &GoToNextDocumentHighlight,
16068        window: &mut Window,
16069        cx: &mut Context<Self>,
16070    ) {
16071        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16072    }
16073
16074    pub fn go_to_prev_document_highlight(
16075        &mut self,
16076        _: &GoToPreviousDocumentHighlight,
16077        window: &mut Window,
16078        cx: &mut Context<Self>,
16079    ) {
16080        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16081    }
16082
16083    pub fn go_to_document_highlight_before_or_after_position(
16084        &mut self,
16085        direction: Direction,
16086        window: &mut Window,
16087        cx: &mut Context<Editor>,
16088    ) {
16089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16090        let snapshot = self.snapshot(window, cx);
16091        let buffer = &snapshot.buffer_snapshot;
16092        let position = self.selections.newest::<Point>(cx).head();
16093        let anchor_position = buffer.anchor_after(position);
16094
16095        // Get all document highlights (both read and write)
16096        let mut all_highlights = Vec::new();
16097
16098        if let Some((_, read_highlights)) = self
16099            .background_highlights
16100            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16101        {
16102            all_highlights.extend(read_highlights.iter());
16103        }
16104
16105        if let Some((_, write_highlights)) = self
16106            .background_highlights
16107            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16108        {
16109            all_highlights.extend(write_highlights.iter());
16110        }
16111
16112        if all_highlights.is_empty() {
16113            return;
16114        }
16115
16116        // Sort highlights by position
16117        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16118
16119        let target_highlight = match direction {
16120            Direction::Next => {
16121                // Find the first highlight after the current position
16122                all_highlights
16123                    .iter()
16124                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16125            }
16126            Direction::Prev => {
16127                // Find the last highlight before the current position
16128                all_highlights
16129                    .iter()
16130                    .rev()
16131                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16132            }
16133        };
16134
16135        if let Some(highlight) = target_highlight {
16136            let destination = highlight.start.to_point(buffer);
16137            let autoscroll = Autoscroll::center();
16138
16139            self.unfold_ranges(&[destination..destination], false, false, cx);
16140            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16141                s.select_ranges([destination..destination]);
16142            });
16143        }
16144    }
16145
16146    fn go_to_line<T: 'static>(
16147        &mut self,
16148        position: Anchor,
16149        highlight_color: Option<Hsla>,
16150        window: &mut Window,
16151        cx: &mut Context<Self>,
16152    ) {
16153        let snapshot = self.snapshot(window, cx).display_snapshot;
16154        let position = position.to_point(&snapshot.buffer_snapshot);
16155        let start = snapshot
16156            .buffer_snapshot
16157            .clip_point(Point::new(position.row, 0), Bias::Left);
16158        let end = start + Point::new(1, 0);
16159        let start = snapshot.buffer_snapshot.anchor_before(start);
16160        let end = snapshot.buffer_snapshot.anchor_before(end);
16161
16162        self.highlight_rows::<T>(
16163            start..end,
16164            highlight_color
16165                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16166            Default::default(),
16167            cx,
16168        );
16169
16170        if self.buffer.read(cx).is_singleton() {
16171            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16172        }
16173    }
16174
16175    pub fn go_to_definition(
16176        &mut self,
16177        _: &GoToDefinition,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) -> Task<Result<Navigated>> {
16181        let definition =
16182            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16183        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16184        cx.spawn_in(window, async move |editor, cx| {
16185            if definition.await? == Navigated::Yes {
16186                return Ok(Navigated::Yes);
16187            }
16188            match fallback_strategy {
16189                GoToDefinitionFallback::None => Ok(Navigated::No),
16190                GoToDefinitionFallback::FindAllReferences => {
16191                    match editor.update_in(cx, |editor, window, cx| {
16192                        editor.find_all_references(&FindAllReferences, window, cx)
16193                    })? {
16194                        Some(references) => references.await,
16195                        None => Ok(Navigated::No),
16196                    }
16197                }
16198            }
16199        })
16200    }
16201
16202    pub fn go_to_declaration(
16203        &mut self,
16204        _: &GoToDeclaration,
16205        window: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) -> Task<Result<Navigated>> {
16208        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16209    }
16210
16211    pub fn go_to_declaration_split(
16212        &mut self,
16213        _: &GoToDeclaration,
16214        window: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) -> Task<Result<Navigated>> {
16217        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16218    }
16219
16220    pub fn go_to_implementation(
16221        &mut self,
16222        _: &GoToImplementation,
16223        window: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) -> Task<Result<Navigated>> {
16226        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16227    }
16228
16229    pub fn go_to_implementation_split(
16230        &mut self,
16231        _: &GoToImplementationSplit,
16232        window: &mut Window,
16233        cx: &mut Context<Self>,
16234    ) -> Task<Result<Navigated>> {
16235        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16236    }
16237
16238    pub fn go_to_type_definition(
16239        &mut self,
16240        _: &GoToTypeDefinition,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) -> Task<Result<Navigated>> {
16244        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16245    }
16246
16247    pub fn go_to_definition_split(
16248        &mut self,
16249        _: &GoToDefinitionSplit,
16250        window: &mut Window,
16251        cx: &mut Context<Self>,
16252    ) -> Task<Result<Navigated>> {
16253        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16254    }
16255
16256    pub fn go_to_type_definition_split(
16257        &mut self,
16258        _: &GoToTypeDefinitionSplit,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) -> Task<Result<Navigated>> {
16262        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16263    }
16264
16265    fn go_to_definition_of_kind(
16266        &mut self,
16267        kind: GotoDefinitionKind,
16268        split: bool,
16269        window: &mut Window,
16270        cx: &mut Context<Self>,
16271    ) -> Task<Result<Navigated>> {
16272        let Some(provider) = self.semantics_provider.clone() else {
16273            return Task::ready(Ok(Navigated::No));
16274        };
16275        let head = self.selections.newest::<usize>(cx).head();
16276        let buffer = self.buffer.read(cx);
16277        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16278            return Task::ready(Ok(Navigated::No));
16279        };
16280        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16281            return Task::ready(Ok(Navigated::No));
16282        };
16283
16284        cx.spawn_in(window, async move |editor, cx| {
16285            let Some(definitions) = definitions.await? else {
16286                return Ok(Navigated::No);
16287            };
16288            let navigated = editor
16289                .update_in(cx, |editor, window, cx| {
16290                    editor.navigate_to_hover_links(
16291                        Some(kind),
16292                        definitions
16293                            .into_iter()
16294                            .filter(|location| {
16295                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16296                            })
16297                            .map(HoverLink::Text)
16298                            .collect::<Vec<_>>(),
16299                        split,
16300                        window,
16301                        cx,
16302                    )
16303                })?
16304                .await?;
16305            anyhow::Ok(navigated)
16306        })
16307    }
16308
16309    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16310        let selection = self.selections.newest_anchor();
16311        let head = selection.head();
16312        let tail = selection.tail();
16313
16314        let Some((buffer, start_position)) =
16315            self.buffer.read(cx).text_anchor_for_position(head, cx)
16316        else {
16317            return;
16318        };
16319
16320        let end_position = if head != tail {
16321            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16322                return;
16323            };
16324            Some(pos)
16325        } else {
16326            None
16327        };
16328
16329        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16330            let url = if let Some(end_pos) = end_position {
16331                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16332            } else {
16333                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16334            };
16335
16336            if let Some(url) = url {
16337                editor.update(cx, |_, cx| {
16338                    cx.open_url(&url);
16339                })
16340            } else {
16341                Ok(())
16342            }
16343        });
16344
16345        url_finder.detach();
16346    }
16347
16348    pub fn open_selected_filename(
16349        &mut self,
16350        _: &OpenSelectedFilename,
16351        window: &mut Window,
16352        cx: &mut Context<Self>,
16353    ) {
16354        let Some(workspace) = self.workspace() else {
16355            return;
16356        };
16357
16358        let position = self.selections.newest_anchor().head();
16359
16360        let Some((buffer, buffer_position)) =
16361            self.buffer.read(cx).text_anchor_for_position(position, cx)
16362        else {
16363            return;
16364        };
16365
16366        let project = self.project.clone();
16367
16368        cx.spawn_in(window, async move |_, cx| {
16369            let result = find_file(&buffer, project, buffer_position, cx).await;
16370
16371            if let Some((_, path)) = result {
16372                workspace
16373                    .update_in(cx, |workspace, window, cx| {
16374                        workspace.open_resolved_path(path, window, cx)
16375                    })?
16376                    .await?;
16377            }
16378            anyhow::Ok(())
16379        })
16380        .detach();
16381    }
16382
16383    pub(crate) fn navigate_to_hover_links(
16384        &mut self,
16385        kind: Option<GotoDefinitionKind>,
16386        definitions: Vec<HoverLink>,
16387        split: bool,
16388        window: &mut Window,
16389        cx: &mut Context<Editor>,
16390    ) -> Task<Result<Navigated>> {
16391        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16392        let mut first_url_or_file = None;
16393        let definitions: Vec<_> = definitions
16394            .into_iter()
16395            .filter_map(|def| match def {
16396                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16397                HoverLink::InlayHint(lsp_location, server_id) => {
16398                    let computation =
16399                        self.compute_target_location(lsp_location, server_id, window, cx);
16400                    Some(cx.background_spawn(computation))
16401                }
16402                HoverLink::Url(url) => {
16403                    first_url_or_file = Some(Either::Left(url));
16404                    None
16405                }
16406                HoverLink::File(path) => {
16407                    first_url_or_file = Some(Either::Right(path));
16408                    None
16409                }
16410            })
16411            .collect();
16412
16413        let workspace = self.workspace();
16414
16415        cx.spawn_in(window, async move |editor, cx| {
16416            let locations: Vec<Location> = future::join_all(definitions)
16417                .await
16418                .into_iter()
16419                .filter_map(|location| location.transpose())
16420                .collect::<Result<_>>()
16421                .context("location tasks")?;
16422            let mut locations = cx.update(|_, cx| {
16423                locations
16424                    .into_iter()
16425                    .map(|location| {
16426                        let buffer = location.buffer.read(cx);
16427                        (location.buffer, location.range.to_point(buffer))
16428                    })
16429                    .into_group_map()
16430            })?;
16431            let mut num_locations = 0;
16432            for ranges in locations.values_mut() {
16433                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16434                ranges.dedup();
16435                num_locations += ranges.len();
16436            }
16437
16438            if num_locations > 1 {
16439                let Some(workspace) = workspace else {
16440                    return Ok(Navigated::No);
16441                };
16442
16443                let tab_kind = match kind {
16444                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16445                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16446                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16447                    Some(GotoDefinitionKind::Type) => "Types",
16448                };
16449                let title = editor
16450                    .update_in(cx, |_, _, cx| {
16451                        let target = locations
16452                            .iter()
16453                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16454                            .map(|(buffer, location)| {
16455                                buffer
16456                                    .read(cx)
16457                                    .text_for_range(location.clone())
16458                                    .collect::<String>()
16459                            })
16460                            .filter(|text| !text.contains('\n'))
16461                            .unique()
16462                            .take(3)
16463                            .join(", ");
16464                        if target.is_empty() {
16465                            tab_kind.to_owned()
16466                        } else {
16467                            format!("{tab_kind} for {target}")
16468                        }
16469                    })
16470                    .context("buffer title")?;
16471
16472                let opened = workspace
16473                    .update_in(cx, |workspace, window, cx| {
16474                        Self::open_locations_in_multibuffer(
16475                            workspace,
16476                            locations,
16477                            title,
16478                            split,
16479                            MultibufferSelectionMode::First,
16480                            window,
16481                            cx,
16482                        )
16483                    })
16484                    .is_ok();
16485
16486                anyhow::Ok(Navigated::from_bool(opened))
16487            } else if num_locations == 0 {
16488                // If there is one url or file, open it directly
16489                match first_url_or_file {
16490                    Some(Either::Left(url)) => {
16491                        cx.update(|_, cx| cx.open_url(&url))?;
16492                        Ok(Navigated::Yes)
16493                    }
16494                    Some(Either::Right(path)) => {
16495                        let Some(workspace) = workspace else {
16496                            return Ok(Navigated::No);
16497                        };
16498
16499                        workspace
16500                            .update_in(cx, |workspace, window, cx| {
16501                                workspace.open_resolved_path(path, window, cx)
16502                            })?
16503                            .await?;
16504                        Ok(Navigated::Yes)
16505                    }
16506                    None => Ok(Navigated::No),
16507                }
16508            } else {
16509                let Some(workspace) = workspace else {
16510                    return Ok(Navigated::No);
16511                };
16512
16513                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16514                let target_range = target_ranges.first().unwrap().clone();
16515
16516                editor.update_in(cx, |editor, window, cx| {
16517                    let range = target_range.to_point(target_buffer.read(cx));
16518                    let range = editor.range_for_match(&range);
16519                    let range = collapse_multiline_range(range);
16520
16521                    if !split
16522                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16523                    {
16524                        editor.go_to_singleton_buffer_range(range, window, cx);
16525                    } else {
16526                        let pane = workspace.read(cx).active_pane().clone();
16527                        window.defer(cx, move |window, cx| {
16528                            let target_editor: Entity<Self> =
16529                                workspace.update(cx, |workspace, cx| {
16530                                    let pane = if split {
16531                                        workspace.adjacent_pane(window, cx)
16532                                    } else {
16533                                        workspace.active_pane().clone()
16534                                    };
16535
16536                                    workspace.open_project_item(
16537                                        pane,
16538                                        target_buffer.clone(),
16539                                        true,
16540                                        true,
16541                                        window,
16542                                        cx,
16543                                    )
16544                                });
16545                            target_editor.update(cx, |target_editor, cx| {
16546                                // When selecting a definition in a different buffer, disable the nav history
16547                                // to avoid creating a history entry at the previous cursor location.
16548                                pane.update(cx, |pane, _| pane.disable_history());
16549                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16550                                pane.update(cx, |pane, _| pane.enable_history());
16551                            });
16552                        });
16553                    }
16554                    Navigated::Yes
16555                })
16556            }
16557        })
16558    }
16559
16560    fn compute_target_location(
16561        &self,
16562        lsp_location: lsp::Location,
16563        server_id: LanguageServerId,
16564        window: &mut Window,
16565        cx: &mut Context<Self>,
16566    ) -> Task<anyhow::Result<Option<Location>>> {
16567        let Some(project) = self.project.clone() else {
16568            return Task::ready(Ok(None));
16569        };
16570
16571        cx.spawn_in(window, async move |editor, cx| {
16572            let location_task = editor.update(cx, |_, cx| {
16573                project.update(cx, |project, cx| {
16574                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16575                })
16576            })?;
16577            let location = Some({
16578                let target_buffer_handle = location_task.await.context("open local buffer")?;
16579                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16580                    let target_start = target_buffer
16581                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16582                    let target_end = target_buffer
16583                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16584                    target_buffer.anchor_after(target_start)
16585                        ..target_buffer.anchor_before(target_end)
16586                })?;
16587                Location {
16588                    buffer: target_buffer_handle,
16589                    range,
16590                }
16591            });
16592            Ok(location)
16593        })
16594    }
16595
16596    pub fn find_all_references(
16597        &mut self,
16598        _: &FindAllReferences,
16599        window: &mut Window,
16600        cx: &mut Context<Self>,
16601    ) -> Option<Task<Result<Navigated>>> {
16602        let selection = self.selections.newest::<usize>(cx);
16603        let multi_buffer = self.buffer.read(cx);
16604        let head = selection.head();
16605
16606        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16607        let head_anchor = multi_buffer_snapshot.anchor_at(
16608            head,
16609            if head < selection.tail() {
16610                Bias::Right
16611            } else {
16612                Bias::Left
16613            },
16614        );
16615
16616        match self
16617            .find_all_references_task_sources
16618            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16619        {
16620            Ok(_) => {
16621                log::info!(
16622                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16623                );
16624                return None;
16625            }
16626            Err(i) => {
16627                self.find_all_references_task_sources.insert(i, head_anchor);
16628            }
16629        }
16630
16631        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16632        let workspace = self.workspace()?;
16633        let project = workspace.read(cx).project().clone();
16634        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16635        Some(cx.spawn_in(window, async move |editor, cx| {
16636            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16637                if let Ok(i) = editor
16638                    .find_all_references_task_sources
16639                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16640                {
16641                    editor.find_all_references_task_sources.remove(i);
16642                }
16643            });
16644
16645            let Some(locations) = references.await? else {
16646                return anyhow::Ok(Navigated::No);
16647            };
16648            let mut locations = cx.update(|_, cx| {
16649                locations
16650                    .into_iter()
16651                    .map(|location| {
16652                        let buffer = location.buffer.read(cx);
16653                        (location.buffer, location.range.to_point(buffer))
16654                    })
16655                    .into_group_map()
16656            })?;
16657            if locations.is_empty() {
16658                return anyhow::Ok(Navigated::No);
16659            }
16660            for ranges in locations.values_mut() {
16661                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16662                ranges.dedup();
16663            }
16664
16665            workspace.update_in(cx, |workspace, window, cx| {
16666                let target = locations
16667                    .iter()
16668                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16669                    .map(|(buffer, location)| {
16670                        buffer
16671                            .read(cx)
16672                            .text_for_range(location.clone())
16673                            .collect::<String>()
16674                    })
16675                    .filter(|text| !text.contains('\n'))
16676                    .unique()
16677                    .take(3)
16678                    .join(", ");
16679                let title = if target.is_empty() {
16680                    "References".to_owned()
16681                } else {
16682                    format!("References to {target}")
16683                };
16684                Self::open_locations_in_multibuffer(
16685                    workspace,
16686                    locations,
16687                    title,
16688                    false,
16689                    MultibufferSelectionMode::First,
16690                    window,
16691                    cx,
16692                );
16693                Navigated::Yes
16694            })
16695        }))
16696    }
16697
16698    /// Opens a multibuffer with the given project locations in it
16699    pub fn open_locations_in_multibuffer(
16700        workspace: &mut Workspace,
16701        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16702        title: String,
16703        split: bool,
16704        multibuffer_selection_mode: MultibufferSelectionMode,
16705        window: &mut Window,
16706        cx: &mut Context<Workspace>,
16707    ) {
16708        if locations.is_empty() {
16709            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16710            return;
16711        }
16712
16713        let capability = workspace.project().read(cx).capability();
16714        let mut ranges = <Vec<Range<Anchor>>>::new();
16715
16716        // a key to find existing multibuffer editors with the same set of locations
16717        // to prevent us from opening more and more multibuffer tabs for searches and the like
16718        let mut key = (title.clone(), vec![]);
16719        let excerpt_buffer = cx.new(|cx| {
16720            let key = &mut key.1;
16721            let mut multibuffer = MultiBuffer::new(capability);
16722            for (buffer, mut ranges_for_buffer) in locations {
16723                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16724                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16725                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16726                    PathKey::for_buffer(&buffer, cx),
16727                    buffer.clone(),
16728                    ranges_for_buffer,
16729                    multibuffer_context_lines(cx),
16730                    cx,
16731                );
16732                ranges.extend(new_ranges)
16733            }
16734
16735            multibuffer.with_title(title)
16736        });
16737        let existing = workspace.active_pane().update(cx, |pane, cx| {
16738            pane.items()
16739                .filter_map(|item| item.downcast::<Editor>())
16740                .find(|editor| {
16741                    editor
16742                        .read(cx)
16743                        .lookup_key
16744                        .as_ref()
16745                        .and_then(|it| {
16746                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16747                        })
16748                        .is_some_and(|it| *it == key)
16749                })
16750        });
16751        let editor = existing.unwrap_or_else(|| {
16752            cx.new(|cx| {
16753                let mut editor = Editor::for_multibuffer(
16754                    excerpt_buffer,
16755                    Some(workspace.project().clone()),
16756                    window,
16757                    cx,
16758                );
16759                editor.lookup_key = Some(Box::new(key));
16760                editor
16761            })
16762        });
16763        editor.update(cx, |editor, cx| {
16764            match multibuffer_selection_mode {
16765                MultibufferSelectionMode::First => {
16766                    if let Some(first_range) = ranges.first() {
16767                        editor.change_selections(
16768                            SelectionEffects::no_scroll(),
16769                            window,
16770                            cx,
16771                            |selections| {
16772                                selections.clear_disjoint();
16773                                selections
16774                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16775                            },
16776                        );
16777                    }
16778                    editor.highlight_background::<Self>(
16779                        &ranges,
16780                        |theme| theme.colors().editor_highlighted_line_background,
16781                        cx,
16782                    );
16783                }
16784                MultibufferSelectionMode::All => {
16785                    editor.change_selections(
16786                        SelectionEffects::no_scroll(),
16787                        window,
16788                        cx,
16789                        |selections| {
16790                            selections.clear_disjoint();
16791                            selections.select_anchor_ranges(ranges);
16792                        },
16793                    );
16794                }
16795            }
16796            editor.register_buffers_with_language_servers(cx);
16797        });
16798
16799        let item = Box::new(editor);
16800        let item_id = item.item_id();
16801
16802        if split {
16803            workspace.split_item(SplitDirection::Right, item, window, cx);
16804        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16805            let (preview_item_id, preview_item_idx) =
16806                workspace.active_pane().read_with(cx, |pane, _| {
16807                    (pane.preview_item_id(), pane.preview_item_idx())
16808                });
16809
16810            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16811
16812            if let Some(preview_item_id) = preview_item_id {
16813                workspace.active_pane().update(cx, |pane, cx| {
16814                    pane.remove_item(preview_item_id, false, false, window, cx);
16815                });
16816            }
16817        } else {
16818            workspace.add_item_to_active_pane(item, None, true, window, cx);
16819        }
16820        workspace.active_pane().update(cx, |pane, cx| {
16821            pane.set_preview_item_id(Some(item_id), cx);
16822        });
16823    }
16824
16825    pub fn rename(
16826        &mut self,
16827        _: &Rename,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) -> Option<Task<Result<()>>> {
16831        use language::ToOffset as _;
16832
16833        let provider = self.semantics_provider.clone()?;
16834        let selection = self.selections.newest_anchor().clone();
16835        let (cursor_buffer, cursor_buffer_position) = self
16836            .buffer
16837            .read(cx)
16838            .text_anchor_for_position(selection.head(), cx)?;
16839        let (tail_buffer, cursor_buffer_position_end) = self
16840            .buffer
16841            .read(cx)
16842            .text_anchor_for_position(selection.tail(), cx)?;
16843        if tail_buffer != cursor_buffer {
16844            return None;
16845        }
16846
16847        let snapshot = cursor_buffer.read(cx).snapshot();
16848        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16849        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16850        let prepare_rename = provider
16851            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16852            .unwrap_or_else(|| Task::ready(Ok(None)));
16853        drop(snapshot);
16854
16855        Some(cx.spawn_in(window, async move |this, cx| {
16856            let rename_range = if let Some(range) = prepare_rename.await? {
16857                Some(range)
16858            } else {
16859                this.update(cx, |this, cx| {
16860                    let buffer = this.buffer.read(cx).snapshot(cx);
16861                    let mut buffer_highlights = this
16862                        .document_highlights_for_position(selection.head(), &buffer)
16863                        .filter(|highlight| {
16864                            highlight.start.excerpt_id == selection.head().excerpt_id
16865                                && highlight.end.excerpt_id == selection.head().excerpt_id
16866                        });
16867                    buffer_highlights
16868                        .next()
16869                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16870                })?
16871            };
16872            if let Some(rename_range) = rename_range {
16873                this.update_in(cx, |this, window, cx| {
16874                    let snapshot = cursor_buffer.read(cx).snapshot();
16875                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16876                    let cursor_offset_in_rename_range =
16877                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16878                    let cursor_offset_in_rename_range_end =
16879                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16880
16881                    this.take_rename(false, window, cx);
16882                    let buffer = this.buffer.read(cx).read(cx);
16883                    let cursor_offset = selection.head().to_offset(&buffer);
16884                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16885                    let rename_end = rename_start + rename_buffer_range.len();
16886                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16887                    let mut old_highlight_id = None;
16888                    let old_name: Arc<str> = buffer
16889                        .chunks(rename_start..rename_end, true)
16890                        .map(|chunk| {
16891                            if old_highlight_id.is_none() {
16892                                old_highlight_id = chunk.syntax_highlight_id;
16893                            }
16894                            chunk.text
16895                        })
16896                        .collect::<String>()
16897                        .into();
16898
16899                    drop(buffer);
16900
16901                    // Position the selection in the rename editor so that it matches the current selection.
16902                    this.show_local_selections = false;
16903                    let rename_editor = cx.new(|cx| {
16904                        let mut editor = Editor::single_line(window, cx);
16905                        editor.buffer.update(cx, |buffer, cx| {
16906                            buffer.edit([(0..0, old_name.clone())], None, cx)
16907                        });
16908                        let rename_selection_range = match cursor_offset_in_rename_range
16909                            .cmp(&cursor_offset_in_rename_range_end)
16910                        {
16911                            Ordering::Equal => {
16912                                editor.select_all(&SelectAll, window, cx);
16913                                return editor;
16914                            }
16915                            Ordering::Less => {
16916                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16917                            }
16918                            Ordering::Greater => {
16919                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16920                            }
16921                        };
16922                        if rename_selection_range.end > old_name.len() {
16923                            editor.select_all(&SelectAll, window, cx);
16924                        } else {
16925                            editor.change_selections(Default::default(), window, cx, |s| {
16926                                s.select_ranges([rename_selection_range]);
16927                            });
16928                        }
16929                        editor
16930                    });
16931                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16932                        if e == &EditorEvent::Focused {
16933                            cx.emit(EditorEvent::FocusedIn)
16934                        }
16935                    })
16936                    .detach();
16937
16938                    let write_highlights =
16939                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16940                    let read_highlights =
16941                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16942                    let ranges = write_highlights
16943                        .iter()
16944                        .flat_map(|(_, ranges)| ranges.iter())
16945                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16946                        .cloned()
16947                        .collect();
16948
16949                    this.highlight_text::<Rename>(
16950                        ranges,
16951                        HighlightStyle {
16952                            fade_out: Some(0.6),
16953                            ..Default::default()
16954                        },
16955                        cx,
16956                    );
16957                    let rename_focus_handle = rename_editor.focus_handle(cx);
16958                    window.focus(&rename_focus_handle);
16959                    let block_id = this.insert_blocks(
16960                        [BlockProperties {
16961                            style: BlockStyle::Flex,
16962                            placement: BlockPlacement::Below(range.start),
16963                            height: Some(1),
16964                            render: Arc::new({
16965                                let rename_editor = rename_editor.clone();
16966                                move |cx: &mut BlockContext| {
16967                                    let mut text_style = cx.editor_style.text.clone();
16968                                    if let Some(highlight_style) = old_highlight_id
16969                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16970                                    {
16971                                        text_style = text_style.highlight(highlight_style);
16972                                    }
16973                                    div()
16974                                        .block_mouse_except_scroll()
16975                                        .pl(cx.anchor_x)
16976                                        .child(EditorElement::new(
16977                                            &rename_editor,
16978                                            EditorStyle {
16979                                                background: cx.theme().system().transparent,
16980                                                local_player: cx.editor_style.local_player,
16981                                                text: text_style,
16982                                                scrollbar_width: cx.editor_style.scrollbar_width,
16983                                                syntax: cx.editor_style.syntax.clone(),
16984                                                status: cx.editor_style.status.clone(),
16985                                                inlay_hints_style: HighlightStyle {
16986                                                    font_weight: Some(FontWeight::BOLD),
16987                                                    ..make_inlay_hints_style(cx.app)
16988                                                },
16989                                                edit_prediction_styles: make_suggestion_styles(
16990                                                    cx.app,
16991                                                ),
16992                                                ..EditorStyle::default()
16993                                            },
16994                                        ))
16995                                        .into_any_element()
16996                                }
16997                            }),
16998                            priority: 0,
16999                        }],
17000                        Some(Autoscroll::fit()),
17001                        cx,
17002                    )[0];
17003                    this.pending_rename = Some(RenameState {
17004                        range,
17005                        old_name,
17006                        editor: rename_editor,
17007                        block_id,
17008                    });
17009                })?;
17010            }
17011
17012            Ok(())
17013        }))
17014    }
17015
17016    pub fn confirm_rename(
17017        &mut self,
17018        _: &ConfirmRename,
17019        window: &mut Window,
17020        cx: &mut Context<Self>,
17021    ) -> Option<Task<Result<()>>> {
17022        let rename = self.take_rename(false, window, cx)?;
17023        let workspace = self.workspace()?.downgrade();
17024        let (buffer, start) = self
17025            .buffer
17026            .read(cx)
17027            .text_anchor_for_position(rename.range.start, cx)?;
17028        let (end_buffer, _) = self
17029            .buffer
17030            .read(cx)
17031            .text_anchor_for_position(rename.range.end, cx)?;
17032        if buffer != end_buffer {
17033            return None;
17034        }
17035
17036        let old_name = rename.old_name;
17037        let new_name = rename.editor.read(cx).text(cx);
17038
17039        let rename = self.semantics_provider.as_ref()?.perform_rename(
17040            &buffer,
17041            start,
17042            new_name.clone(),
17043            cx,
17044        )?;
17045
17046        Some(cx.spawn_in(window, async move |editor, cx| {
17047            let project_transaction = rename.await?;
17048            Self::open_project_transaction(
17049                &editor,
17050                workspace,
17051                project_transaction,
17052                format!("Rename: {}{}", old_name, new_name),
17053                cx,
17054            )
17055            .await?;
17056
17057            editor.update(cx, |editor, cx| {
17058                editor.refresh_document_highlights(cx);
17059            })?;
17060            Ok(())
17061        }))
17062    }
17063
17064    fn take_rename(
17065        &mut self,
17066        moving_cursor: bool,
17067        window: &mut Window,
17068        cx: &mut Context<Self>,
17069    ) -> Option<RenameState> {
17070        let rename = self.pending_rename.take()?;
17071        if rename.editor.focus_handle(cx).is_focused(window) {
17072            window.focus(&self.focus_handle);
17073        }
17074
17075        self.remove_blocks(
17076            [rename.block_id].into_iter().collect(),
17077            Some(Autoscroll::fit()),
17078            cx,
17079        );
17080        self.clear_highlights::<Rename>(cx);
17081        self.show_local_selections = true;
17082
17083        if moving_cursor {
17084            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17085                editor.selections.newest::<usize>(cx).head()
17086            });
17087
17088            // Update the selection to match the position of the selection inside
17089            // the rename editor.
17090            let snapshot = self.buffer.read(cx).read(cx);
17091            let rename_range = rename.range.to_offset(&snapshot);
17092            let cursor_in_editor = snapshot
17093                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17094                .min(rename_range.end);
17095            drop(snapshot);
17096
17097            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17098                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17099            });
17100        } else {
17101            self.refresh_document_highlights(cx);
17102        }
17103
17104        Some(rename)
17105    }
17106
17107    pub fn pending_rename(&self) -> Option<&RenameState> {
17108        self.pending_rename.as_ref()
17109    }
17110
17111    fn format(
17112        &mut self,
17113        _: &Format,
17114        window: &mut Window,
17115        cx: &mut Context<Self>,
17116    ) -> Option<Task<Result<()>>> {
17117        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17118
17119        let project = match &self.project {
17120            Some(project) => project.clone(),
17121            None => return None,
17122        };
17123
17124        Some(self.perform_format(
17125            project,
17126            FormatTrigger::Manual,
17127            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17128            window,
17129            cx,
17130        ))
17131    }
17132
17133    fn format_selections(
17134        &mut self,
17135        _: &FormatSelections,
17136        window: &mut Window,
17137        cx: &mut Context<Self>,
17138    ) -> Option<Task<Result<()>>> {
17139        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17140
17141        let project = match &self.project {
17142            Some(project) => project.clone(),
17143            None => return None,
17144        };
17145
17146        let ranges = self
17147            .selections
17148            .all_adjusted(cx)
17149            .into_iter()
17150            .map(|selection| selection.range())
17151            .collect_vec();
17152
17153        Some(self.perform_format(
17154            project,
17155            FormatTrigger::Manual,
17156            FormatTarget::Ranges(ranges),
17157            window,
17158            cx,
17159        ))
17160    }
17161
17162    fn perform_format(
17163        &mut self,
17164        project: Entity<Project>,
17165        trigger: FormatTrigger,
17166        target: FormatTarget,
17167        window: &mut Window,
17168        cx: &mut Context<Self>,
17169    ) -> Task<Result<()>> {
17170        let buffer = self.buffer.clone();
17171        let (buffers, target) = match target {
17172            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17173            FormatTarget::Ranges(selection_ranges) => {
17174                let multi_buffer = buffer.read(cx);
17175                let snapshot = multi_buffer.read(cx);
17176                let mut buffers = HashSet::default();
17177                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17178                    BTreeMap::new();
17179                for selection_range in selection_ranges {
17180                    for (buffer, buffer_range, _) in
17181                        snapshot.range_to_buffer_ranges(selection_range)
17182                    {
17183                        let buffer_id = buffer.remote_id();
17184                        let start = buffer.anchor_before(buffer_range.start);
17185                        let end = buffer.anchor_after(buffer_range.end);
17186                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17187                        buffer_id_to_ranges
17188                            .entry(buffer_id)
17189                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17190                            .or_insert_with(|| vec![start..end]);
17191                    }
17192                }
17193                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17194            }
17195        };
17196
17197        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17198        let selections_prev = transaction_id_prev
17199            .and_then(|transaction_id_prev| {
17200                // default to selections as they were after the last edit, if we have them,
17201                // instead of how they are now.
17202                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17203                // will take you back to where you made the last edit, instead of staying where you scrolled
17204                self.selection_history
17205                    .transaction(transaction_id_prev)
17206                    .map(|t| t.0.clone())
17207            })
17208            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17209
17210        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17211        let format = project.update(cx, |project, cx| {
17212            project.format(buffers, target, true, trigger, cx)
17213        });
17214
17215        cx.spawn_in(window, async move |editor, cx| {
17216            let transaction = futures::select_biased! {
17217                transaction = format.log_err().fuse() => transaction,
17218                () = timeout => {
17219                    log::warn!("timed out waiting for formatting");
17220                    None
17221                }
17222            };
17223
17224            buffer
17225                .update(cx, |buffer, cx| {
17226                    if let Some(transaction) = transaction
17227                        && !buffer.is_singleton()
17228                    {
17229                        buffer.push_transaction(&transaction.0, cx);
17230                    }
17231                    cx.notify();
17232                })
17233                .ok();
17234
17235            if let Some(transaction_id_now) =
17236                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17237            {
17238                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17239                if has_new_transaction {
17240                    _ = editor.update(cx, |editor, _| {
17241                        editor
17242                            .selection_history
17243                            .insert_transaction(transaction_id_now, selections_prev);
17244                    });
17245                }
17246            }
17247
17248            Ok(())
17249        })
17250    }
17251
17252    fn organize_imports(
17253        &mut self,
17254        _: &OrganizeImports,
17255        window: &mut Window,
17256        cx: &mut Context<Self>,
17257    ) -> Option<Task<Result<()>>> {
17258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17259        let project = match &self.project {
17260            Some(project) => project.clone(),
17261            None => return None,
17262        };
17263        Some(self.perform_code_action_kind(
17264            project,
17265            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17266            window,
17267            cx,
17268        ))
17269    }
17270
17271    fn perform_code_action_kind(
17272        &mut self,
17273        project: Entity<Project>,
17274        kind: CodeActionKind,
17275        window: &mut Window,
17276        cx: &mut Context<Self>,
17277    ) -> Task<Result<()>> {
17278        let buffer = self.buffer.clone();
17279        let buffers = buffer.read(cx).all_buffers();
17280        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17281        let apply_action = project.update(cx, |project, cx| {
17282            project.apply_code_action_kind(buffers, kind, true, cx)
17283        });
17284        cx.spawn_in(window, async move |_, cx| {
17285            let transaction = futures::select_biased! {
17286                () = timeout => {
17287                    log::warn!("timed out waiting for executing code action");
17288                    None
17289                }
17290                transaction = apply_action.log_err().fuse() => transaction,
17291            };
17292            buffer
17293                .update(cx, |buffer, cx| {
17294                    // check if we need this
17295                    if let Some(transaction) = transaction
17296                        && !buffer.is_singleton()
17297                    {
17298                        buffer.push_transaction(&transaction.0, cx);
17299                    }
17300                    cx.notify();
17301                })
17302                .ok();
17303            Ok(())
17304        })
17305    }
17306
17307    pub fn restart_language_server(
17308        &mut self,
17309        _: &RestartLanguageServer,
17310        _: &mut Window,
17311        cx: &mut Context<Self>,
17312    ) {
17313        if let Some(project) = self.project.clone() {
17314            self.buffer.update(cx, |multi_buffer, cx| {
17315                project.update(cx, |project, cx| {
17316                    project.restart_language_servers_for_buffers(
17317                        multi_buffer.all_buffers().into_iter().collect(),
17318                        HashSet::default(),
17319                        cx,
17320                    );
17321                });
17322            })
17323        }
17324    }
17325
17326    pub fn stop_language_server(
17327        &mut self,
17328        _: &StopLanguageServer,
17329        _: &mut Window,
17330        cx: &mut Context<Self>,
17331    ) {
17332        if let Some(project) = self.project.clone() {
17333            self.buffer.update(cx, |multi_buffer, cx| {
17334                project.update(cx, |project, cx| {
17335                    project.stop_language_servers_for_buffers(
17336                        multi_buffer.all_buffers().into_iter().collect(),
17337                        HashSet::default(),
17338                        cx,
17339                    );
17340                    cx.emit(project::Event::RefreshInlayHints);
17341                });
17342            });
17343        }
17344    }
17345
17346    fn cancel_language_server_work(
17347        workspace: &mut Workspace,
17348        _: &actions::CancelLanguageServerWork,
17349        _: &mut Window,
17350        cx: &mut Context<Workspace>,
17351    ) {
17352        let project = workspace.project();
17353        let buffers = workspace
17354            .active_item(cx)
17355            .and_then(|item| item.act_as::<Editor>(cx))
17356            .map_or(HashSet::default(), |editor| {
17357                editor.read(cx).buffer.read(cx).all_buffers()
17358            });
17359        project.update(cx, |project, cx| {
17360            project.cancel_language_server_work_for_buffers(buffers, cx);
17361        });
17362    }
17363
17364    fn show_character_palette(
17365        &mut self,
17366        _: &ShowCharacterPalette,
17367        window: &mut Window,
17368        _: &mut Context<Self>,
17369    ) {
17370        window.show_character_palette();
17371    }
17372
17373    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17374        if !self.diagnostics_enabled() {
17375            return;
17376        }
17377
17378        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17379            let buffer = self.buffer.read(cx).snapshot(cx);
17380            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17381            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17382            let is_valid = buffer
17383                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17384                .any(|entry| {
17385                    entry.diagnostic.is_primary
17386                        && !entry.range.is_empty()
17387                        && entry.range.start == primary_range_start
17388                        && entry.diagnostic.message == active_diagnostics.active_message
17389                });
17390
17391            if !is_valid {
17392                self.dismiss_diagnostics(cx);
17393            }
17394        }
17395    }
17396
17397    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17398        match &self.active_diagnostics {
17399            ActiveDiagnostic::Group(group) => Some(group),
17400            _ => None,
17401        }
17402    }
17403
17404    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17405        if !self.diagnostics_enabled() {
17406            return;
17407        }
17408        self.dismiss_diagnostics(cx);
17409        self.active_diagnostics = ActiveDiagnostic::All;
17410    }
17411
17412    fn activate_diagnostics(
17413        &mut self,
17414        buffer_id: BufferId,
17415        diagnostic: DiagnosticEntry<usize>,
17416        window: &mut Window,
17417        cx: &mut Context<Self>,
17418    ) {
17419        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17420            return;
17421        }
17422        self.dismiss_diagnostics(cx);
17423        let snapshot = self.snapshot(window, cx);
17424        let buffer = self.buffer.read(cx).snapshot(cx);
17425        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17426            return;
17427        };
17428
17429        let diagnostic_group = buffer
17430            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17431            .collect::<Vec<_>>();
17432
17433        let blocks =
17434            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17435
17436        let blocks = self.display_map.update(cx, |display_map, cx| {
17437            display_map.insert_blocks(blocks, cx).into_iter().collect()
17438        });
17439        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17440            active_range: buffer.anchor_before(diagnostic.range.start)
17441                ..buffer.anchor_after(diagnostic.range.end),
17442            active_message: diagnostic.diagnostic.message.clone(),
17443            group_id: diagnostic.diagnostic.group_id,
17444            blocks,
17445        });
17446        cx.notify();
17447    }
17448
17449    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17450        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17451            return;
17452        };
17453
17454        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17455        if let ActiveDiagnostic::Group(group) = prev {
17456            self.display_map.update(cx, |display_map, cx| {
17457                display_map.remove_blocks(group.blocks, cx);
17458            });
17459            cx.notify();
17460        }
17461    }
17462
17463    /// Disable inline diagnostics rendering for this editor.
17464    pub fn disable_inline_diagnostics(&mut self) {
17465        self.inline_diagnostics_enabled = false;
17466        self.inline_diagnostics_update = Task::ready(());
17467        self.inline_diagnostics.clear();
17468    }
17469
17470    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17471        self.diagnostics_enabled = false;
17472        self.dismiss_diagnostics(cx);
17473        self.inline_diagnostics_update = Task::ready(());
17474        self.inline_diagnostics.clear();
17475    }
17476
17477    pub fn disable_word_completions(&mut self) {
17478        self.word_completions_enabled = false;
17479    }
17480
17481    pub fn diagnostics_enabled(&self) -> bool {
17482        self.diagnostics_enabled && self.mode.is_full()
17483    }
17484
17485    pub fn inline_diagnostics_enabled(&self) -> bool {
17486        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17487    }
17488
17489    pub fn show_inline_diagnostics(&self) -> bool {
17490        self.show_inline_diagnostics
17491    }
17492
17493    pub fn toggle_inline_diagnostics(
17494        &mut self,
17495        _: &ToggleInlineDiagnostics,
17496        window: &mut Window,
17497        cx: &mut Context<Editor>,
17498    ) {
17499        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17500        self.refresh_inline_diagnostics(false, window, cx);
17501    }
17502
17503    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17504        self.diagnostics_max_severity = severity;
17505        self.display_map.update(cx, |display_map, _| {
17506            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17507        });
17508    }
17509
17510    pub fn toggle_diagnostics(
17511        &mut self,
17512        _: &ToggleDiagnostics,
17513        window: &mut Window,
17514        cx: &mut Context<Editor>,
17515    ) {
17516        if !self.diagnostics_enabled() {
17517            return;
17518        }
17519
17520        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17521            EditorSettings::get_global(cx)
17522                .diagnostics_max_severity
17523                .filter(|severity| severity != &DiagnosticSeverity::Off)
17524                .unwrap_or(DiagnosticSeverity::Hint)
17525        } else {
17526            DiagnosticSeverity::Off
17527        };
17528        self.set_max_diagnostics_severity(new_severity, cx);
17529        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17530            self.active_diagnostics = ActiveDiagnostic::None;
17531            self.inline_diagnostics_update = Task::ready(());
17532            self.inline_diagnostics.clear();
17533        } else {
17534            self.refresh_inline_diagnostics(false, window, cx);
17535        }
17536
17537        cx.notify();
17538    }
17539
17540    pub fn toggle_minimap(
17541        &mut self,
17542        _: &ToggleMinimap,
17543        window: &mut Window,
17544        cx: &mut Context<Editor>,
17545    ) {
17546        if self.supports_minimap(cx) {
17547            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17548        }
17549    }
17550
17551    fn refresh_inline_diagnostics(
17552        &mut self,
17553        debounce: bool,
17554        window: &mut Window,
17555        cx: &mut Context<Self>,
17556    ) {
17557        let max_severity = ProjectSettings::get_global(cx)
17558            .diagnostics
17559            .inline
17560            .max_severity
17561            .unwrap_or(self.diagnostics_max_severity);
17562
17563        if !self.inline_diagnostics_enabled()
17564            || !self.show_inline_diagnostics
17565            || max_severity == DiagnosticSeverity::Off
17566        {
17567            self.inline_diagnostics_update = Task::ready(());
17568            self.inline_diagnostics.clear();
17569            return;
17570        }
17571
17572        let debounce_ms = ProjectSettings::get_global(cx)
17573            .diagnostics
17574            .inline
17575            .update_debounce_ms;
17576        let debounce = if debounce && debounce_ms > 0 {
17577            Some(Duration::from_millis(debounce_ms))
17578        } else {
17579            None
17580        };
17581        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17582            if let Some(debounce) = debounce {
17583                cx.background_executor().timer(debounce).await;
17584            }
17585            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17586                editor
17587                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17588                    .ok()
17589            }) else {
17590                return;
17591            };
17592
17593            let new_inline_diagnostics = cx
17594                .background_spawn(async move {
17595                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17596                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17597                        let message = diagnostic_entry
17598                            .diagnostic
17599                            .message
17600                            .split_once('\n')
17601                            .map(|(line, _)| line)
17602                            .map(SharedString::new)
17603                            .unwrap_or_else(|| {
17604                                SharedString::from(diagnostic_entry.diagnostic.message)
17605                            });
17606                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17607                        let (Ok(i) | Err(i)) = inline_diagnostics
17608                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17609                        inline_diagnostics.insert(
17610                            i,
17611                            (
17612                                start_anchor,
17613                                InlineDiagnostic {
17614                                    message,
17615                                    group_id: diagnostic_entry.diagnostic.group_id,
17616                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17617                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17618                                    severity: diagnostic_entry.diagnostic.severity,
17619                                },
17620                            ),
17621                        );
17622                    }
17623                    inline_diagnostics
17624                })
17625                .await;
17626
17627            editor
17628                .update(cx, |editor, cx| {
17629                    editor.inline_diagnostics = new_inline_diagnostics;
17630                    cx.notify();
17631                })
17632                .ok();
17633        });
17634    }
17635
17636    fn pull_diagnostics(
17637        &mut self,
17638        buffer_id: Option<BufferId>,
17639        window: &Window,
17640        cx: &mut Context<Self>,
17641    ) -> Option<()> {
17642        if !self.mode().is_full() {
17643            return None;
17644        }
17645        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17646            .diagnostics
17647            .lsp_pull_diagnostics;
17648        if !pull_diagnostics_settings.enabled {
17649            return None;
17650        }
17651        let project = self.project()?.downgrade();
17652        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17653        let mut buffers = self.buffer.read(cx).all_buffers();
17654        if let Some(buffer_id) = buffer_id {
17655            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17656        }
17657
17658        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17659            cx.background_executor().timer(debounce).await;
17660
17661            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17662                buffers
17663                    .into_iter()
17664                    .filter_map(|buffer| {
17665                        project
17666                            .update(cx, |project, cx| {
17667                                project.lsp_store().update(cx, |lsp_store, cx| {
17668                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17669                                })
17670                            })
17671                            .ok()
17672                    })
17673                    .collect::<FuturesUnordered<_>>()
17674            }) else {
17675                return;
17676            };
17677
17678            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17679                match pull_task {
17680                    Ok(()) => {
17681                        if editor
17682                            .update_in(cx, |editor, window, cx| {
17683                                editor.update_diagnostics_state(window, cx);
17684                            })
17685                            .is_err()
17686                        {
17687                            return;
17688                        }
17689                    }
17690                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17691                }
17692            }
17693        });
17694
17695        Some(())
17696    }
17697
17698    pub fn set_selections_from_remote(
17699        &mut self,
17700        selections: Vec<Selection<Anchor>>,
17701        pending_selection: Option<Selection<Anchor>>,
17702        window: &mut Window,
17703        cx: &mut Context<Self>,
17704    ) {
17705        let old_cursor_position = self.selections.newest_anchor().head();
17706        self.selections.change_with(cx, |s| {
17707            s.select_anchors(selections);
17708            if let Some(pending_selection) = pending_selection {
17709                s.set_pending(pending_selection, SelectMode::Character);
17710            } else {
17711                s.clear_pending();
17712            }
17713        });
17714        self.selections_did_change(
17715            false,
17716            &old_cursor_position,
17717            SelectionEffects::default(),
17718            window,
17719            cx,
17720        );
17721    }
17722
17723    pub fn transact(
17724        &mut self,
17725        window: &mut Window,
17726        cx: &mut Context<Self>,
17727        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17728    ) -> Option<TransactionId> {
17729        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17730            this.start_transaction_at(Instant::now(), window, cx);
17731            update(this, window, cx);
17732            this.end_transaction_at(Instant::now(), cx)
17733        })
17734    }
17735
17736    pub fn start_transaction_at(
17737        &mut self,
17738        now: Instant,
17739        window: &mut Window,
17740        cx: &mut Context<Self>,
17741    ) -> Option<TransactionId> {
17742        self.end_selection(window, cx);
17743        if let Some(tx_id) = self
17744            .buffer
17745            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17746        {
17747            self.selection_history
17748                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17749            cx.emit(EditorEvent::TransactionBegun {
17750                transaction_id: tx_id,
17751            });
17752            Some(tx_id)
17753        } else {
17754            None
17755        }
17756    }
17757
17758    pub fn end_transaction_at(
17759        &mut self,
17760        now: Instant,
17761        cx: &mut Context<Self>,
17762    ) -> Option<TransactionId> {
17763        if let Some(transaction_id) = self
17764            .buffer
17765            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17766        {
17767            if let Some((_, end_selections)) =
17768                self.selection_history.transaction_mut(transaction_id)
17769            {
17770                *end_selections = Some(self.selections.disjoint_anchors_arc());
17771            } else {
17772                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17773            }
17774
17775            cx.emit(EditorEvent::Edited { transaction_id });
17776            Some(transaction_id)
17777        } else {
17778            None
17779        }
17780    }
17781
17782    pub fn modify_transaction_selection_history(
17783        &mut self,
17784        transaction_id: TransactionId,
17785        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17786    ) -> bool {
17787        self.selection_history
17788            .transaction_mut(transaction_id)
17789            .map(modify)
17790            .is_some()
17791    }
17792
17793    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17794        if self.selection_mark_mode {
17795            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17796                s.move_with(|_, sel| {
17797                    sel.collapse_to(sel.head(), SelectionGoal::None);
17798                });
17799            })
17800        }
17801        self.selection_mark_mode = true;
17802        cx.notify();
17803    }
17804
17805    pub fn swap_selection_ends(
17806        &mut self,
17807        _: &actions::SwapSelectionEnds,
17808        window: &mut Window,
17809        cx: &mut Context<Self>,
17810    ) {
17811        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17812            s.move_with(|_, sel| {
17813                if sel.start != sel.end {
17814                    sel.reversed = !sel.reversed
17815                }
17816            });
17817        });
17818        self.request_autoscroll(Autoscroll::newest(), cx);
17819        cx.notify();
17820    }
17821
17822    pub fn toggle_focus(
17823        workspace: &mut Workspace,
17824        _: &actions::ToggleFocus,
17825        window: &mut Window,
17826        cx: &mut Context<Workspace>,
17827    ) {
17828        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17829            return;
17830        };
17831        workspace.activate_item(&item, true, true, window, cx);
17832    }
17833
17834    pub fn toggle_fold(
17835        &mut self,
17836        _: &actions::ToggleFold,
17837        window: &mut Window,
17838        cx: &mut Context<Self>,
17839    ) {
17840        if self.is_singleton(cx) {
17841            let selection = self.selections.newest::<Point>(cx);
17842
17843            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17844            let range = if selection.is_empty() {
17845                let point = selection.head().to_display_point(&display_map);
17846                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17847                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17848                    .to_point(&display_map);
17849                start..end
17850            } else {
17851                selection.range()
17852            };
17853            if display_map.folds_in_range(range).next().is_some() {
17854                self.unfold_lines(&Default::default(), window, cx)
17855            } else {
17856                self.fold(&Default::default(), window, cx)
17857            }
17858        } else {
17859            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17860            let buffer_ids: HashSet<_> = self
17861                .selections
17862                .disjoint_anchor_ranges()
17863                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17864                .collect();
17865
17866            let should_unfold = buffer_ids
17867                .iter()
17868                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17869
17870            for buffer_id in buffer_ids {
17871                if should_unfold {
17872                    self.unfold_buffer(buffer_id, cx);
17873                } else {
17874                    self.fold_buffer(buffer_id, cx);
17875                }
17876            }
17877        }
17878    }
17879
17880    pub fn toggle_fold_recursive(
17881        &mut self,
17882        _: &actions::ToggleFoldRecursive,
17883        window: &mut Window,
17884        cx: &mut Context<Self>,
17885    ) {
17886        let selection = self.selections.newest::<Point>(cx);
17887
17888        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17889        let range = if selection.is_empty() {
17890            let point = selection.head().to_display_point(&display_map);
17891            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17892            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17893                .to_point(&display_map);
17894            start..end
17895        } else {
17896            selection.range()
17897        };
17898        if display_map.folds_in_range(range).next().is_some() {
17899            self.unfold_recursive(&Default::default(), window, cx)
17900        } else {
17901            self.fold_recursive(&Default::default(), window, cx)
17902        }
17903    }
17904
17905    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17906        if self.is_singleton(cx) {
17907            let mut to_fold = Vec::new();
17908            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17909            let selections = self.selections.all_adjusted(cx);
17910
17911            for selection in selections {
17912                let range = selection.range().sorted();
17913                let buffer_start_row = range.start.row;
17914
17915                if range.start.row != range.end.row {
17916                    let mut found = false;
17917                    let mut row = range.start.row;
17918                    while row <= range.end.row {
17919                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17920                        {
17921                            found = true;
17922                            row = crease.range().end.row + 1;
17923                            to_fold.push(crease);
17924                        } else {
17925                            row += 1
17926                        }
17927                    }
17928                    if found {
17929                        continue;
17930                    }
17931                }
17932
17933                for row in (0..=range.start.row).rev() {
17934                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17935                        && crease.range().end.row >= buffer_start_row
17936                    {
17937                        to_fold.push(crease);
17938                        if row <= range.start.row {
17939                            break;
17940                        }
17941                    }
17942                }
17943            }
17944
17945            self.fold_creases(to_fold, true, window, cx);
17946        } else {
17947            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17948            let buffer_ids = self
17949                .selections
17950                .disjoint_anchor_ranges()
17951                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17952                .collect::<HashSet<_>>();
17953            for buffer_id in buffer_ids {
17954                self.fold_buffer(buffer_id, cx);
17955            }
17956        }
17957    }
17958
17959    pub fn toggle_fold_all(
17960        &mut self,
17961        _: &actions::ToggleFoldAll,
17962        window: &mut Window,
17963        cx: &mut Context<Self>,
17964    ) {
17965        if self.buffer.read(cx).is_singleton() {
17966            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17967            let has_folds = display_map
17968                .folds_in_range(0..display_map.buffer_snapshot.len())
17969                .next()
17970                .is_some();
17971
17972            if has_folds {
17973                self.unfold_all(&actions::UnfoldAll, window, cx);
17974            } else {
17975                self.fold_all(&actions::FoldAll, window, cx);
17976            }
17977        } else {
17978            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17979            let should_unfold = buffer_ids
17980                .iter()
17981                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17982
17983            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17984                editor
17985                    .update_in(cx, |editor, _, cx| {
17986                        for buffer_id in buffer_ids {
17987                            if should_unfold {
17988                                editor.unfold_buffer(buffer_id, cx);
17989                            } else {
17990                                editor.fold_buffer(buffer_id, cx);
17991                            }
17992                        }
17993                    })
17994                    .ok();
17995            });
17996        }
17997    }
17998
17999    fn fold_at_level(
18000        &mut self,
18001        fold_at: &FoldAtLevel,
18002        window: &mut Window,
18003        cx: &mut Context<Self>,
18004    ) {
18005        if !self.buffer.read(cx).is_singleton() {
18006            return;
18007        }
18008
18009        let fold_at_level = fold_at.0;
18010        let snapshot = self.buffer.read(cx).snapshot(cx);
18011        let mut to_fold = Vec::new();
18012        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18013
18014        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18015            while start_row < end_row {
18016                match self
18017                    .snapshot(window, cx)
18018                    .crease_for_buffer_row(MultiBufferRow(start_row))
18019                {
18020                    Some(crease) => {
18021                        let nested_start_row = crease.range().start.row + 1;
18022                        let nested_end_row = crease.range().end.row;
18023
18024                        if current_level < fold_at_level {
18025                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18026                        } else if current_level == fold_at_level {
18027                            to_fold.push(crease);
18028                        }
18029
18030                        start_row = nested_end_row + 1;
18031                    }
18032                    None => start_row += 1,
18033                }
18034            }
18035        }
18036
18037        self.fold_creases(to_fold, true, window, cx);
18038    }
18039
18040    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18041        if self.buffer.read(cx).is_singleton() {
18042            let mut fold_ranges = Vec::new();
18043            let snapshot = self.buffer.read(cx).snapshot(cx);
18044
18045            for row in 0..snapshot.max_row().0 {
18046                if let Some(foldable_range) = self
18047                    .snapshot(window, cx)
18048                    .crease_for_buffer_row(MultiBufferRow(row))
18049                {
18050                    fold_ranges.push(foldable_range);
18051                }
18052            }
18053
18054            self.fold_creases(fold_ranges, true, window, cx);
18055        } else {
18056            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18057                editor
18058                    .update_in(cx, |editor, _, cx| {
18059                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18060                            editor.fold_buffer(buffer_id, cx);
18061                        }
18062                    })
18063                    .ok();
18064            });
18065        }
18066    }
18067
18068    pub fn fold_function_bodies(
18069        &mut self,
18070        _: &actions::FoldFunctionBodies,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        let snapshot = self.buffer.read(cx).snapshot(cx);
18075
18076        let ranges = snapshot
18077            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18078            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18079            .collect::<Vec<_>>();
18080
18081        let creases = ranges
18082            .into_iter()
18083            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18084            .collect();
18085
18086        self.fold_creases(creases, true, window, cx);
18087    }
18088
18089    pub fn fold_recursive(
18090        &mut self,
18091        _: &actions::FoldRecursive,
18092        window: &mut Window,
18093        cx: &mut Context<Self>,
18094    ) {
18095        let mut to_fold = Vec::new();
18096        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18097        let selections = self.selections.all_adjusted(cx);
18098
18099        for selection in selections {
18100            let range = selection.range().sorted();
18101            let buffer_start_row = range.start.row;
18102
18103            if range.start.row != range.end.row {
18104                let mut found = false;
18105                for row in range.start.row..=range.end.row {
18106                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18107                        found = true;
18108                        to_fold.push(crease);
18109                    }
18110                }
18111                if found {
18112                    continue;
18113                }
18114            }
18115
18116            for row in (0..=range.start.row).rev() {
18117                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18118                    if crease.range().end.row >= buffer_start_row {
18119                        to_fold.push(crease);
18120                    } else {
18121                        break;
18122                    }
18123                }
18124            }
18125        }
18126
18127        self.fold_creases(to_fold, true, window, cx);
18128    }
18129
18130    pub fn fold_at(
18131        &mut self,
18132        buffer_row: MultiBufferRow,
18133        window: &mut Window,
18134        cx: &mut Context<Self>,
18135    ) {
18136        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18137
18138        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18139            let autoscroll = self
18140                .selections
18141                .all::<Point>(cx)
18142                .iter()
18143                .any(|selection| crease.range().overlaps(&selection.range()));
18144
18145            self.fold_creases(vec![crease], autoscroll, window, cx);
18146        }
18147    }
18148
18149    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18150        if self.is_singleton(cx) {
18151            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18152            let buffer = &display_map.buffer_snapshot;
18153            let selections = self.selections.all::<Point>(cx);
18154            let ranges = selections
18155                .iter()
18156                .map(|s| {
18157                    let range = s.display_range(&display_map).sorted();
18158                    let mut start = range.start.to_point(&display_map);
18159                    let mut end = range.end.to_point(&display_map);
18160                    start.column = 0;
18161                    end.column = buffer.line_len(MultiBufferRow(end.row));
18162                    start..end
18163                })
18164                .collect::<Vec<_>>();
18165
18166            self.unfold_ranges(&ranges, true, true, cx);
18167        } else {
18168            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18169            let buffer_ids = self
18170                .selections
18171                .disjoint_anchor_ranges()
18172                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18173                .collect::<HashSet<_>>();
18174            for buffer_id in buffer_ids {
18175                self.unfold_buffer(buffer_id, cx);
18176            }
18177        }
18178    }
18179
18180    pub fn unfold_recursive(
18181        &mut self,
18182        _: &UnfoldRecursive,
18183        _window: &mut Window,
18184        cx: &mut Context<Self>,
18185    ) {
18186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18187        let selections = self.selections.all::<Point>(cx);
18188        let ranges = selections
18189            .iter()
18190            .map(|s| {
18191                let mut range = s.display_range(&display_map).sorted();
18192                *range.start.column_mut() = 0;
18193                *range.end.column_mut() = display_map.line_len(range.end.row());
18194                let start = range.start.to_point(&display_map);
18195                let end = range.end.to_point(&display_map);
18196                start..end
18197            })
18198            .collect::<Vec<_>>();
18199
18200        self.unfold_ranges(&ranges, true, true, cx);
18201    }
18202
18203    pub fn unfold_at(
18204        &mut self,
18205        buffer_row: MultiBufferRow,
18206        _window: &mut Window,
18207        cx: &mut Context<Self>,
18208    ) {
18209        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18210
18211        let intersection_range = Point::new(buffer_row.0, 0)
18212            ..Point::new(
18213                buffer_row.0,
18214                display_map.buffer_snapshot.line_len(buffer_row),
18215            );
18216
18217        let autoscroll = self
18218            .selections
18219            .all::<Point>(cx)
18220            .iter()
18221            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18222
18223        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18224    }
18225
18226    pub fn unfold_all(
18227        &mut self,
18228        _: &actions::UnfoldAll,
18229        _window: &mut Window,
18230        cx: &mut Context<Self>,
18231    ) {
18232        if self.buffer.read(cx).is_singleton() {
18233            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18234            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18235        } else {
18236            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18237                editor
18238                    .update(cx, |editor, cx| {
18239                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18240                            editor.unfold_buffer(buffer_id, cx);
18241                        }
18242                    })
18243                    .ok();
18244            });
18245        }
18246    }
18247
18248    pub fn fold_selected_ranges(
18249        &mut self,
18250        _: &FoldSelectedRanges,
18251        window: &mut Window,
18252        cx: &mut Context<Self>,
18253    ) {
18254        let selections = self.selections.all_adjusted(cx);
18255        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18256        let ranges = selections
18257            .into_iter()
18258            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18259            .collect::<Vec<_>>();
18260        self.fold_creases(ranges, true, window, cx);
18261    }
18262
18263    pub fn fold_ranges<T: ToOffset + Clone>(
18264        &mut self,
18265        ranges: Vec<Range<T>>,
18266        auto_scroll: bool,
18267        window: &mut Window,
18268        cx: &mut Context<Self>,
18269    ) {
18270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18271        let ranges = ranges
18272            .into_iter()
18273            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18274            .collect::<Vec<_>>();
18275        self.fold_creases(ranges, auto_scroll, window, cx);
18276    }
18277
18278    pub fn fold_creases<T: ToOffset + Clone>(
18279        &mut self,
18280        creases: Vec<Crease<T>>,
18281        auto_scroll: bool,
18282        _window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) {
18285        if creases.is_empty() {
18286            return;
18287        }
18288
18289        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18290
18291        if auto_scroll {
18292            self.request_autoscroll(Autoscroll::fit(), cx);
18293        }
18294
18295        cx.notify();
18296
18297        self.scrollbar_marker_state.dirty = true;
18298        self.folds_did_change(cx);
18299    }
18300
18301    /// Removes any folds whose ranges intersect any of the given ranges.
18302    pub fn unfold_ranges<T: ToOffset + Clone>(
18303        &mut self,
18304        ranges: &[Range<T>],
18305        inclusive: bool,
18306        auto_scroll: bool,
18307        cx: &mut Context<Self>,
18308    ) {
18309        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18310            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18311        });
18312        self.folds_did_change(cx);
18313    }
18314
18315    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18316        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18317            return;
18318        }
18319        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18320        self.display_map.update(cx, |display_map, cx| {
18321            display_map.fold_buffers([buffer_id], cx)
18322        });
18323        cx.emit(EditorEvent::BufferFoldToggled {
18324            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18325            folded: true,
18326        });
18327        cx.notify();
18328    }
18329
18330    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18331        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18332            return;
18333        }
18334        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18335        self.display_map.update(cx, |display_map, cx| {
18336            display_map.unfold_buffers([buffer_id], cx);
18337        });
18338        cx.emit(EditorEvent::BufferFoldToggled {
18339            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18340            folded: false,
18341        });
18342        cx.notify();
18343    }
18344
18345    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18346        self.display_map.read(cx).is_buffer_folded(buffer)
18347    }
18348
18349    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18350        self.display_map.read(cx).folded_buffers()
18351    }
18352
18353    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18354        self.display_map.update(cx, |display_map, cx| {
18355            display_map.disable_header_for_buffer(buffer_id, cx);
18356        });
18357        cx.notify();
18358    }
18359
18360    /// Removes any folds with the given ranges.
18361    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18362        &mut self,
18363        ranges: &[Range<T>],
18364        type_id: TypeId,
18365        auto_scroll: bool,
18366        cx: &mut Context<Self>,
18367    ) {
18368        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18369            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18370        });
18371        self.folds_did_change(cx);
18372    }
18373
18374    fn remove_folds_with<T: ToOffset + Clone>(
18375        &mut self,
18376        ranges: &[Range<T>],
18377        auto_scroll: bool,
18378        cx: &mut Context<Self>,
18379        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18380    ) {
18381        if ranges.is_empty() {
18382            return;
18383        }
18384
18385        let mut buffers_affected = HashSet::default();
18386        let multi_buffer = self.buffer().read(cx);
18387        for range in ranges {
18388            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18389                buffers_affected.insert(buffer.read(cx).remote_id());
18390            };
18391        }
18392
18393        self.display_map.update(cx, update);
18394
18395        if auto_scroll {
18396            self.request_autoscroll(Autoscroll::fit(), cx);
18397        }
18398
18399        cx.notify();
18400        self.scrollbar_marker_state.dirty = true;
18401        self.active_indent_guides_state.dirty = true;
18402    }
18403
18404    pub fn update_renderer_widths(
18405        &mut self,
18406        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18407        cx: &mut Context<Self>,
18408    ) -> bool {
18409        self.display_map
18410            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18411    }
18412
18413    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18414        self.display_map.read(cx).fold_placeholder.clone()
18415    }
18416
18417    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18418        self.buffer.update(cx, |buffer, cx| {
18419            buffer.set_all_diff_hunks_expanded(cx);
18420        });
18421    }
18422
18423    pub fn expand_all_diff_hunks(
18424        &mut self,
18425        _: &ExpandAllDiffHunks,
18426        _window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        self.buffer.update(cx, |buffer, cx| {
18430            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18431        });
18432    }
18433
18434    pub fn toggle_selected_diff_hunks(
18435        &mut self,
18436        _: &ToggleSelectedDiffHunks,
18437        _window: &mut Window,
18438        cx: &mut Context<Self>,
18439    ) {
18440        let ranges: Vec<_> = self
18441            .selections
18442            .disjoint_anchors()
18443            .iter()
18444            .map(|s| s.range())
18445            .collect();
18446        self.toggle_diff_hunks_in_ranges(ranges, cx);
18447    }
18448
18449    pub fn diff_hunks_in_ranges<'a>(
18450        &'a self,
18451        ranges: &'a [Range<Anchor>],
18452        buffer: &'a MultiBufferSnapshot,
18453    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18454        ranges.iter().flat_map(move |range| {
18455            let end_excerpt_id = range.end.excerpt_id;
18456            let range = range.to_point(buffer);
18457            let mut peek_end = range.end;
18458            if range.end.row < buffer.max_row().0 {
18459                peek_end = Point::new(range.end.row + 1, 0);
18460            }
18461            buffer
18462                .diff_hunks_in_range(range.start..peek_end)
18463                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18464        })
18465    }
18466
18467    pub fn has_stageable_diff_hunks_in_ranges(
18468        &self,
18469        ranges: &[Range<Anchor>],
18470        snapshot: &MultiBufferSnapshot,
18471    ) -> bool {
18472        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18473        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18474    }
18475
18476    pub fn toggle_staged_selected_diff_hunks(
18477        &mut self,
18478        _: &::git::ToggleStaged,
18479        _: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        let snapshot = self.buffer.read(cx).snapshot(cx);
18483        let ranges: Vec<_> = self
18484            .selections
18485            .disjoint_anchors()
18486            .iter()
18487            .map(|s| s.range())
18488            .collect();
18489        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18490        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18491    }
18492
18493    pub fn set_render_diff_hunk_controls(
18494        &mut self,
18495        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18496        cx: &mut Context<Self>,
18497    ) {
18498        self.render_diff_hunk_controls = render_diff_hunk_controls;
18499        cx.notify();
18500    }
18501
18502    pub fn stage_and_next(
18503        &mut self,
18504        _: &::git::StageAndNext,
18505        window: &mut Window,
18506        cx: &mut Context<Self>,
18507    ) {
18508        self.do_stage_or_unstage_and_next(true, window, cx);
18509    }
18510
18511    pub fn unstage_and_next(
18512        &mut self,
18513        _: &::git::UnstageAndNext,
18514        window: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        self.do_stage_or_unstage_and_next(false, window, cx);
18518    }
18519
18520    pub fn stage_or_unstage_diff_hunks(
18521        &mut self,
18522        stage: bool,
18523        ranges: Vec<Range<Anchor>>,
18524        cx: &mut Context<Self>,
18525    ) {
18526        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18527        cx.spawn(async move |this, cx| {
18528            task.await?;
18529            this.update(cx, |this, cx| {
18530                let snapshot = this.buffer.read(cx).snapshot(cx);
18531                let chunk_by = this
18532                    .diff_hunks_in_ranges(&ranges, &snapshot)
18533                    .chunk_by(|hunk| hunk.buffer_id);
18534                for (buffer_id, hunks) in &chunk_by {
18535                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18536                }
18537            })
18538        })
18539        .detach_and_log_err(cx);
18540    }
18541
18542    fn save_buffers_for_ranges_if_needed(
18543        &mut self,
18544        ranges: &[Range<Anchor>],
18545        cx: &mut Context<Editor>,
18546    ) -> Task<Result<()>> {
18547        let multibuffer = self.buffer.read(cx);
18548        let snapshot = multibuffer.read(cx);
18549        let buffer_ids: HashSet<_> = ranges
18550            .iter()
18551            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18552            .collect();
18553        drop(snapshot);
18554
18555        let mut buffers = HashSet::default();
18556        for buffer_id in buffer_ids {
18557            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18558                let buffer = buffer_entity.read(cx);
18559                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18560                {
18561                    buffers.insert(buffer_entity);
18562                }
18563            }
18564        }
18565
18566        if let Some(project) = &self.project {
18567            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18568        } else {
18569            Task::ready(Ok(()))
18570        }
18571    }
18572
18573    fn do_stage_or_unstage_and_next(
18574        &mut self,
18575        stage: bool,
18576        window: &mut Window,
18577        cx: &mut Context<Self>,
18578    ) {
18579        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18580
18581        if ranges.iter().any(|range| range.start != range.end) {
18582            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18583            return;
18584        }
18585
18586        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18587        let snapshot = self.snapshot(window, cx);
18588        let position = self.selections.newest::<Point>(cx).head();
18589        let mut row = snapshot
18590            .buffer_snapshot
18591            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18592            .find(|hunk| hunk.row_range.start.0 > position.row)
18593            .map(|hunk| hunk.row_range.start);
18594
18595        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18596        // Outside of the project diff editor, wrap around to the beginning.
18597        if !all_diff_hunks_expanded {
18598            row = row.or_else(|| {
18599                snapshot
18600                    .buffer_snapshot
18601                    .diff_hunks_in_range(Point::zero()..position)
18602                    .find(|hunk| hunk.row_range.end.0 < position.row)
18603                    .map(|hunk| hunk.row_range.start)
18604            });
18605        }
18606
18607        if let Some(row) = row {
18608            let destination = Point::new(row.0, 0);
18609            let autoscroll = Autoscroll::center();
18610
18611            self.unfold_ranges(&[destination..destination], false, false, cx);
18612            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18613                s.select_ranges([destination..destination]);
18614            });
18615        }
18616    }
18617
18618    fn do_stage_or_unstage(
18619        &self,
18620        stage: bool,
18621        buffer_id: BufferId,
18622        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18623        cx: &mut App,
18624    ) -> Option<()> {
18625        let project = self.project()?;
18626        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18627        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18628        let buffer_snapshot = buffer.read(cx).snapshot();
18629        let file_exists = buffer_snapshot
18630            .file()
18631            .is_some_and(|file| file.disk_state().exists());
18632        diff.update(cx, |diff, cx| {
18633            diff.stage_or_unstage_hunks(
18634                stage,
18635                &hunks
18636                    .map(|hunk| buffer_diff::DiffHunk {
18637                        buffer_range: hunk.buffer_range,
18638                        diff_base_byte_range: hunk.diff_base_byte_range,
18639                        secondary_status: hunk.secondary_status,
18640                        range: Point::zero()..Point::zero(), // unused
18641                    })
18642                    .collect::<Vec<_>>(),
18643                &buffer_snapshot,
18644                file_exists,
18645                cx,
18646            )
18647        });
18648        None
18649    }
18650
18651    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18652        let ranges: Vec<_> = self
18653            .selections
18654            .disjoint_anchors()
18655            .iter()
18656            .map(|s| s.range())
18657            .collect();
18658        self.buffer
18659            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18660    }
18661
18662    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18663        self.buffer.update(cx, |buffer, cx| {
18664            let ranges = vec![Anchor::min()..Anchor::max()];
18665            if !buffer.all_diff_hunks_expanded()
18666                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18667            {
18668                buffer.collapse_diff_hunks(ranges, cx);
18669                true
18670            } else {
18671                false
18672            }
18673        })
18674    }
18675
18676    fn toggle_diff_hunks_in_ranges(
18677        &mut self,
18678        ranges: Vec<Range<Anchor>>,
18679        cx: &mut Context<Editor>,
18680    ) {
18681        self.buffer.update(cx, |buffer, cx| {
18682            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18683            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18684        })
18685    }
18686
18687    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18688        self.buffer.update(cx, |buffer, cx| {
18689            let snapshot = buffer.snapshot(cx);
18690            let excerpt_id = range.end.excerpt_id;
18691            let point_range = range.to_point(&snapshot);
18692            let expand = !buffer.single_hunk_is_expanded(range, cx);
18693            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18694        })
18695    }
18696
18697    pub(crate) fn apply_all_diff_hunks(
18698        &mut self,
18699        _: &ApplyAllDiffHunks,
18700        window: &mut Window,
18701        cx: &mut Context<Self>,
18702    ) {
18703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18704
18705        let buffers = self.buffer.read(cx).all_buffers();
18706        for branch_buffer in buffers {
18707            branch_buffer.update(cx, |branch_buffer, cx| {
18708                branch_buffer.merge_into_base(Vec::new(), cx);
18709            });
18710        }
18711
18712        if let Some(project) = self.project.clone() {
18713            self.save(
18714                SaveOptions {
18715                    format: true,
18716                    autosave: false,
18717                },
18718                project,
18719                window,
18720                cx,
18721            )
18722            .detach_and_log_err(cx);
18723        }
18724    }
18725
18726    pub(crate) fn apply_selected_diff_hunks(
18727        &mut self,
18728        _: &ApplyDiffHunk,
18729        window: &mut Window,
18730        cx: &mut Context<Self>,
18731    ) {
18732        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18733        let snapshot = self.snapshot(window, cx);
18734        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18735        let mut ranges_by_buffer = HashMap::default();
18736        self.transact(window, cx, |editor, _window, cx| {
18737            for hunk in hunks {
18738                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18739                    ranges_by_buffer
18740                        .entry(buffer.clone())
18741                        .or_insert_with(Vec::new)
18742                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18743                }
18744            }
18745
18746            for (buffer, ranges) in ranges_by_buffer {
18747                buffer.update(cx, |buffer, cx| {
18748                    buffer.merge_into_base(ranges, cx);
18749                });
18750            }
18751        });
18752
18753        if let Some(project) = self.project.clone() {
18754            self.save(
18755                SaveOptions {
18756                    format: true,
18757                    autosave: false,
18758                },
18759                project,
18760                window,
18761                cx,
18762            )
18763            .detach_and_log_err(cx);
18764        }
18765    }
18766
18767    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18768        if hovered != self.gutter_hovered {
18769            self.gutter_hovered = hovered;
18770            cx.notify();
18771        }
18772    }
18773
18774    pub fn insert_blocks(
18775        &mut self,
18776        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18777        autoscroll: Option<Autoscroll>,
18778        cx: &mut Context<Self>,
18779    ) -> Vec<CustomBlockId> {
18780        let blocks = self
18781            .display_map
18782            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18783        if let Some(autoscroll) = autoscroll {
18784            self.request_autoscroll(autoscroll, cx);
18785        }
18786        cx.notify();
18787        blocks
18788    }
18789
18790    pub fn resize_blocks(
18791        &mut self,
18792        heights: HashMap<CustomBlockId, u32>,
18793        autoscroll: Option<Autoscroll>,
18794        cx: &mut Context<Self>,
18795    ) {
18796        self.display_map
18797            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18798        if let Some(autoscroll) = autoscroll {
18799            self.request_autoscroll(autoscroll, cx);
18800        }
18801        cx.notify();
18802    }
18803
18804    pub fn replace_blocks(
18805        &mut self,
18806        renderers: HashMap<CustomBlockId, RenderBlock>,
18807        autoscroll: Option<Autoscroll>,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.display_map
18811            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18812        if let Some(autoscroll) = autoscroll {
18813            self.request_autoscroll(autoscroll, cx);
18814        }
18815        cx.notify();
18816    }
18817
18818    pub fn remove_blocks(
18819        &mut self,
18820        block_ids: HashSet<CustomBlockId>,
18821        autoscroll: Option<Autoscroll>,
18822        cx: &mut Context<Self>,
18823    ) {
18824        self.display_map.update(cx, |display_map, cx| {
18825            display_map.remove_blocks(block_ids, cx)
18826        });
18827        if let Some(autoscroll) = autoscroll {
18828            self.request_autoscroll(autoscroll, cx);
18829        }
18830        cx.notify();
18831    }
18832
18833    pub fn row_for_block(
18834        &self,
18835        block_id: CustomBlockId,
18836        cx: &mut Context<Self>,
18837    ) -> Option<DisplayRow> {
18838        self.display_map
18839            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18840    }
18841
18842    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18843        self.focused_block = Some(focused_block);
18844    }
18845
18846    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18847        self.focused_block.take()
18848    }
18849
18850    pub fn insert_creases(
18851        &mut self,
18852        creases: impl IntoIterator<Item = Crease<Anchor>>,
18853        cx: &mut Context<Self>,
18854    ) -> Vec<CreaseId> {
18855        self.display_map
18856            .update(cx, |map, cx| map.insert_creases(creases, cx))
18857    }
18858
18859    pub fn remove_creases(
18860        &mut self,
18861        ids: impl IntoIterator<Item = CreaseId>,
18862        cx: &mut Context<Self>,
18863    ) -> Vec<(CreaseId, Range<Anchor>)> {
18864        self.display_map
18865            .update(cx, |map, cx| map.remove_creases(ids, cx))
18866    }
18867
18868    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18869        self.display_map
18870            .update(cx, |map, cx| map.snapshot(cx))
18871            .longest_row()
18872    }
18873
18874    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18875        self.display_map
18876            .update(cx, |map, cx| map.snapshot(cx))
18877            .max_point()
18878    }
18879
18880    pub fn text(&self, cx: &App) -> String {
18881        self.buffer.read(cx).read(cx).text()
18882    }
18883
18884    pub fn is_empty(&self, cx: &App) -> bool {
18885        self.buffer.read(cx).read(cx).is_empty()
18886    }
18887
18888    pub fn text_option(&self, cx: &App) -> Option<String> {
18889        let text = self.text(cx);
18890        let text = text.trim();
18891
18892        if text.is_empty() {
18893            return None;
18894        }
18895
18896        Some(text.to_string())
18897    }
18898
18899    pub fn set_text(
18900        &mut self,
18901        text: impl Into<Arc<str>>,
18902        window: &mut Window,
18903        cx: &mut Context<Self>,
18904    ) {
18905        self.transact(window, cx, |this, _, cx| {
18906            this.buffer
18907                .read(cx)
18908                .as_singleton()
18909                .expect("you can only call set_text on editors for singleton buffers")
18910                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18911        });
18912    }
18913
18914    pub fn display_text(&self, cx: &mut App) -> String {
18915        self.display_map
18916            .update(cx, |map, cx| map.snapshot(cx))
18917            .text()
18918    }
18919
18920    fn create_minimap(
18921        &self,
18922        minimap_settings: MinimapSettings,
18923        window: &mut Window,
18924        cx: &mut Context<Self>,
18925    ) -> Option<Entity<Self>> {
18926        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18927            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18928    }
18929
18930    fn initialize_new_minimap(
18931        &self,
18932        minimap_settings: MinimapSettings,
18933        window: &mut Window,
18934        cx: &mut Context<Self>,
18935    ) -> Entity<Self> {
18936        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18937
18938        let mut minimap = Editor::new_internal(
18939            EditorMode::Minimap {
18940                parent: cx.weak_entity(),
18941            },
18942            self.buffer.clone(),
18943            None,
18944            Some(self.display_map.clone()),
18945            window,
18946            cx,
18947        );
18948        minimap.scroll_manager.clone_state(&self.scroll_manager);
18949        minimap.set_text_style_refinement(TextStyleRefinement {
18950            font_size: Some(MINIMAP_FONT_SIZE),
18951            font_weight: Some(MINIMAP_FONT_WEIGHT),
18952            ..Default::default()
18953        });
18954        minimap.update_minimap_configuration(minimap_settings, cx);
18955        cx.new(|_| minimap)
18956    }
18957
18958    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18959        let current_line_highlight = minimap_settings
18960            .current_line_highlight
18961            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18962        self.set_current_line_highlight(Some(current_line_highlight));
18963    }
18964
18965    pub fn minimap(&self) -> Option<&Entity<Self>> {
18966        self.minimap
18967            .as_ref()
18968            .filter(|_| self.minimap_visibility.visible())
18969    }
18970
18971    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18972        let mut wrap_guides = smallvec![];
18973
18974        if self.show_wrap_guides == Some(false) {
18975            return wrap_guides;
18976        }
18977
18978        let settings = self.buffer.read(cx).language_settings(cx);
18979        if settings.show_wrap_guides {
18980            match self.soft_wrap_mode(cx) {
18981                SoftWrap::Column(soft_wrap) => {
18982                    wrap_guides.push((soft_wrap as usize, true));
18983                }
18984                SoftWrap::Bounded(soft_wrap) => {
18985                    wrap_guides.push((soft_wrap as usize, true));
18986                }
18987                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18988            }
18989            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18990        }
18991
18992        wrap_guides
18993    }
18994
18995    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18996        let settings = self.buffer.read(cx).language_settings(cx);
18997        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18998        match mode {
18999            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19000                SoftWrap::None
19001            }
19002            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19003            language_settings::SoftWrap::PreferredLineLength => {
19004                SoftWrap::Column(settings.preferred_line_length)
19005            }
19006            language_settings::SoftWrap::Bounded => {
19007                SoftWrap::Bounded(settings.preferred_line_length)
19008            }
19009        }
19010    }
19011
19012    pub fn set_soft_wrap_mode(
19013        &mut self,
19014        mode: language_settings::SoftWrap,
19015
19016        cx: &mut Context<Self>,
19017    ) {
19018        self.soft_wrap_mode_override = Some(mode);
19019        cx.notify();
19020    }
19021
19022    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19023        self.hard_wrap = hard_wrap;
19024        cx.notify();
19025    }
19026
19027    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19028        self.text_style_refinement = Some(style);
19029    }
19030
19031    /// called by the Element so we know what style we were most recently rendered with.
19032    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19033        // We intentionally do not inform the display map about the minimap style
19034        // so that wrapping is not recalculated and stays consistent for the editor
19035        // and its linked minimap.
19036        if !self.mode.is_minimap() {
19037            let font = style.text.font();
19038            let font_size = style.text.font_size.to_pixels(window.rem_size());
19039            let display_map = self
19040                .placeholder_display_map
19041                .as_ref()
19042                .filter(|_| self.is_empty(cx))
19043                .unwrap_or(&self.display_map);
19044
19045            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19046        }
19047        self.style = Some(style);
19048    }
19049
19050    pub fn style(&self) -> Option<&EditorStyle> {
19051        self.style.as_ref()
19052    }
19053
19054    // Called by the element. This method is not designed to be called outside of the editor
19055    // element's layout code because it does not notify when rewrapping is computed synchronously.
19056    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19057        if self.is_empty(cx) {
19058            self.placeholder_display_map
19059                .as_ref()
19060                .map_or(false, |display_map| {
19061                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19062                })
19063        } else {
19064            self.display_map
19065                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19066        }
19067    }
19068
19069    pub fn set_soft_wrap(&mut self) {
19070        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19071    }
19072
19073    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19074        if self.soft_wrap_mode_override.is_some() {
19075            self.soft_wrap_mode_override.take();
19076        } else {
19077            let soft_wrap = match self.soft_wrap_mode(cx) {
19078                SoftWrap::GitDiff => return,
19079                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19080                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19081                    language_settings::SoftWrap::None
19082                }
19083            };
19084            self.soft_wrap_mode_override = Some(soft_wrap);
19085        }
19086        cx.notify();
19087    }
19088
19089    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19090        let Some(workspace) = self.workspace() else {
19091            return;
19092        };
19093        let fs = workspace.read(cx).app_state().fs.clone();
19094        let current_show = TabBarSettings::get_global(cx).show;
19095        update_settings_file(fs, cx, move |setting, _| {
19096            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19097        });
19098    }
19099
19100    pub fn toggle_indent_guides(
19101        &mut self,
19102        _: &ToggleIndentGuides,
19103        _: &mut Window,
19104        cx: &mut Context<Self>,
19105    ) {
19106        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19107            self.buffer
19108                .read(cx)
19109                .language_settings(cx)
19110                .indent_guides
19111                .enabled
19112        });
19113        self.show_indent_guides = Some(!currently_enabled);
19114        cx.notify();
19115    }
19116
19117    fn should_show_indent_guides(&self) -> Option<bool> {
19118        self.show_indent_guides
19119    }
19120
19121    pub fn toggle_line_numbers(
19122        &mut self,
19123        _: &ToggleLineNumbers,
19124        _: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        let mut editor_settings = EditorSettings::get_global(cx).clone();
19128        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19129        EditorSettings::override_global(editor_settings, cx);
19130    }
19131
19132    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19133        if let Some(show_line_numbers) = self.show_line_numbers {
19134            return show_line_numbers;
19135        }
19136        EditorSettings::get_global(cx).gutter.line_numbers
19137    }
19138
19139    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19140        self.use_relative_line_numbers
19141            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19142    }
19143
19144    pub fn toggle_relative_line_numbers(
19145        &mut self,
19146        _: &ToggleRelativeLineNumbers,
19147        _: &mut Window,
19148        cx: &mut Context<Self>,
19149    ) {
19150        let is_relative = self.should_use_relative_line_numbers(cx);
19151        self.set_relative_line_number(Some(!is_relative), cx)
19152    }
19153
19154    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19155        self.use_relative_line_numbers = is_relative;
19156        cx.notify();
19157    }
19158
19159    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19160        self.show_gutter = show_gutter;
19161        cx.notify();
19162    }
19163
19164    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19165        self.show_scrollbars = ScrollbarAxes {
19166            horizontal: show,
19167            vertical: show,
19168        };
19169        cx.notify();
19170    }
19171
19172    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19173        self.show_scrollbars.vertical = show;
19174        cx.notify();
19175    }
19176
19177    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19178        self.show_scrollbars.horizontal = show;
19179        cx.notify();
19180    }
19181
19182    pub fn set_minimap_visibility(
19183        &mut self,
19184        minimap_visibility: MinimapVisibility,
19185        window: &mut Window,
19186        cx: &mut Context<Self>,
19187    ) {
19188        if self.minimap_visibility != minimap_visibility {
19189            if minimap_visibility.visible() && self.minimap.is_none() {
19190                let minimap_settings = EditorSettings::get_global(cx).minimap;
19191                self.minimap =
19192                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19193            }
19194            self.minimap_visibility = minimap_visibility;
19195            cx.notify();
19196        }
19197    }
19198
19199    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19200        self.set_show_scrollbars(false, cx);
19201        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19202    }
19203
19204    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19205        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19206    }
19207
19208    /// Normally the text in full mode and auto height editors is padded on the
19209    /// left side by roughly half a character width for improved hit testing.
19210    ///
19211    /// Use this method to disable this for cases where this is not wanted (e.g.
19212    /// if you want to align the editor text with some other text above or below)
19213    /// or if you want to add this padding to single-line editors.
19214    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19215        self.offset_content = offset_content;
19216        cx.notify();
19217    }
19218
19219    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19220        self.show_line_numbers = Some(show_line_numbers);
19221        cx.notify();
19222    }
19223
19224    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19225        self.disable_expand_excerpt_buttons = true;
19226        cx.notify();
19227    }
19228
19229    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19230        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19231        cx.notify();
19232    }
19233
19234    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19235        self.show_code_actions = Some(show_code_actions);
19236        cx.notify();
19237    }
19238
19239    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19240        self.show_runnables = Some(show_runnables);
19241        cx.notify();
19242    }
19243
19244    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19245        self.show_breakpoints = Some(show_breakpoints);
19246        cx.notify();
19247    }
19248
19249    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19250        if self.display_map.read(cx).masked != masked {
19251            self.display_map.update(cx, |map, _| map.masked = masked);
19252        }
19253        cx.notify()
19254    }
19255
19256    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19257        self.show_wrap_guides = Some(show_wrap_guides);
19258        cx.notify();
19259    }
19260
19261    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19262        self.show_indent_guides = Some(show_indent_guides);
19263        cx.notify();
19264    }
19265
19266    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19267        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19268            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19269                && let Some(dir) = file.abs_path(cx).parent()
19270            {
19271                return Some(dir.to_owned());
19272            }
19273        }
19274
19275        None
19276    }
19277
19278    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19279        self.active_excerpt(cx)?
19280            .1
19281            .read(cx)
19282            .file()
19283            .and_then(|f| f.as_local())
19284    }
19285
19286    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19287        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19288            let buffer = buffer.read(cx);
19289            if let Some(project_path) = buffer.project_path(cx) {
19290                let project = self.project()?.read(cx);
19291                project.absolute_path(&project_path, cx)
19292            } else {
19293                buffer
19294                    .file()
19295                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19296            }
19297        })
19298    }
19299
19300    pub fn reveal_in_finder(
19301        &mut self,
19302        _: &RevealInFileManager,
19303        _window: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) {
19306        if let Some(target) = self.target_file(cx) {
19307            cx.reveal_path(&target.abs_path(cx));
19308        }
19309    }
19310
19311    pub fn copy_path(
19312        &mut self,
19313        _: &zed_actions::workspace::CopyPath,
19314        _window: &mut Window,
19315        cx: &mut Context<Self>,
19316    ) {
19317        if let Some(path) = self.target_file_abs_path(cx)
19318            && let Some(path) = path.to_str()
19319        {
19320            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19321        } else {
19322            cx.propagate();
19323        }
19324    }
19325
19326    pub fn copy_relative_path(
19327        &mut self,
19328        _: &zed_actions::workspace::CopyRelativePath,
19329        _window: &mut Window,
19330        cx: &mut Context<Self>,
19331    ) {
19332        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19333            let project = self.project()?.read(cx);
19334            let path = buffer.read(cx).file()?.path();
19335            let path = path.display(project.path_style(cx));
19336            Some(path)
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        {
19414            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19415        }
19416    }
19417
19418    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19419        if let Some(file) = self.target_file(cx)
19420            && let Some(name) = file.path().file_name()
19421        {
19422            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19423        }
19424    }
19425
19426    pub fn toggle_git_blame(
19427        &mut self,
19428        _: &::git::Blame,
19429        window: &mut Window,
19430        cx: &mut Context<Self>,
19431    ) {
19432        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19433
19434        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19435            self.start_git_blame(true, window, cx);
19436        }
19437
19438        cx.notify();
19439    }
19440
19441    pub fn toggle_git_blame_inline(
19442        &mut self,
19443        _: &ToggleGitBlameInline,
19444        window: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        self.toggle_git_blame_inline_internal(true, window, cx);
19448        cx.notify();
19449    }
19450
19451    pub fn open_git_blame_commit(
19452        &mut self,
19453        _: &OpenGitBlameCommit,
19454        window: &mut Window,
19455        cx: &mut Context<Self>,
19456    ) {
19457        self.open_git_blame_commit_internal(window, cx);
19458    }
19459
19460    fn open_git_blame_commit_internal(
19461        &mut self,
19462        window: &mut Window,
19463        cx: &mut Context<Self>,
19464    ) -> Option<()> {
19465        let blame = self.blame.as_ref()?;
19466        let snapshot = self.snapshot(window, cx);
19467        let cursor = self.selections.newest::<Point>(cx).head();
19468        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19469        let (_, blame_entry) = blame
19470            .update(cx, |blame, cx| {
19471                blame
19472                    .blame_for_rows(
19473                        &[RowInfo {
19474                            buffer_id: Some(buffer.remote_id()),
19475                            buffer_row: Some(point.row),
19476                            ..Default::default()
19477                        }],
19478                        cx,
19479                    )
19480                    .next()
19481            })
19482            .flatten()?;
19483        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19484        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19485        let workspace = self.workspace()?.downgrade();
19486        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19487        None
19488    }
19489
19490    pub fn git_blame_inline_enabled(&self) -> bool {
19491        self.git_blame_inline_enabled
19492    }
19493
19494    pub fn toggle_selection_menu(
19495        &mut self,
19496        _: &ToggleSelectionMenu,
19497        _: &mut Window,
19498        cx: &mut Context<Self>,
19499    ) {
19500        self.show_selection_menu = self
19501            .show_selection_menu
19502            .map(|show_selections_menu| !show_selections_menu)
19503            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19504
19505        cx.notify();
19506    }
19507
19508    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19509        self.show_selection_menu
19510            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19511    }
19512
19513    fn start_git_blame(
19514        &mut self,
19515        user_triggered: bool,
19516        window: &mut Window,
19517        cx: &mut Context<Self>,
19518    ) {
19519        if let Some(project) = self.project() {
19520            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19521                && buffer.read(cx).file().is_none()
19522            {
19523                return;
19524            }
19525
19526            let focused = self.focus_handle(cx).contains_focused(window, cx);
19527
19528            let project = project.clone();
19529            let blame = cx
19530                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19531            self.blame_subscription =
19532                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19533            self.blame = Some(blame);
19534        }
19535    }
19536
19537    fn toggle_git_blame_inline_internal(
19538        &mut self,
19539        user_triggered: bool,
19540        window: &mut Window,
19541        cx: &mut Context<Self>,
19542    ) {
19543        if self.git_blame_inline_enabled {
19544            self.git_blame_inline_enabled = false;
19545            self.show_git_blame_inline = false;
19546            self.show_git_blame_inline_delay_task.take();
19547        } else {
19548            self.git_blame_inline_enabled = true;
19549            self.start_git_blame_inline(user_triggered, window, cx);
19550        }
19551
19552        cx.notify();
19553    }
19554
19555    fn start_git_blame_inline(
19556        &mut self,
19557        user_triggered: bool,
19558        window: &mut Window,
19559        cx: &mut Context<Self>,
19560    ) {
19561        self.start_git_blame(user_triggered, window, cx);
19562
19563        if ProjectSettings::get_global(cx)
19564            .git
19565            .inline_blame_delay()
19566            .is_some()
19567        {
19568            self.start_inline_blame_timer(window, cx);
19569        } else {
19570            self.show_git_blame_inline = true
19571        }
19572    }
19573
19574    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19575        self.blame.as_ref()
19576    }
19577
19578    pub fn show_git_blame_gutter(&self) -> bool {
19579        self.show_git_blame_gutter
19580    }
19581
19582    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19583        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19584    }
19585
19586    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19587        self.show_git_blame_inline
19588            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19589            && !self.newest_selection_head_on_empty_line(cx)
19590            && self.has_blame_entries(cx)
19591    }
19592
19593    fn has_blame_entries(&self, cx: &App) -> bool {
19594        self.blame()
19595            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19596    }
19597
19598    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19599        let cursor_anchor = self.selections.newest_anchor().head();
19600
19601        let snapshot = self.buffer.read(cx).snapshot(cx);
19602        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19603
19604        snapshot.line_len(buffer_row) == 0
19605    }
19606
19607    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19608        let buffer_and_selection = maybe!({
19609            let selection = self.selections.newest::<Point>(cx);
19610            let selection_range = selection.range();
19611
19612            let multi_buffer = self.buffer().read(cx);
19613            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19614            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19615
19616            let (buffer, range, _) = if selection.reversed {
19617                buffer_ranges.first()
19618            } else {
19619                buffer_ranges.last()
19620            }?;
19621
19622            let selection = text::ToPoint::to_point(&range.start, buffer).row
19623                ..text::ToPoint::to_point(&range.end, buffer).row;
19624            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19625        });
19626
19627        let Some((buffer, selection)) = buffer_and_selection else {
19628            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19629        };
19630
19631        let Some(project) = self.project() else {
19632            return Task::ready(Err(anyhow!("editor does not have project")));
19633        };
19634
19635        project.update(cx, |project, cx| {
19636            project.get_permalink_to_line(&buffer, selection, cx)
19637        })
19638    }
19639
19640    pub fn copy_permalink_to_line(
19641        &mut self,
19642        _: &CopyPermalinkToLine,
19643        window: &mut Window,
19644        cx: &mut Context<Self>,
19645    ) {
19646        let permalink_task = self.get_permalink_to_line(cx);
19647        let workspace = self.workspace();
19648
19649        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19650            Ok(permalink) => {
19651                cx.update(|_, cx| {
19652                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19653                })
19654                .ok();
19655            }
19656            Err(err) => {
19657                let message = format!("Failed to copy permalink: {err}");
19658
19659                anyhow::Result::<()>::Err(err).log_err();
19660
19661                if let Some(workspace) = workspace {
19662                    workspace
19663                        .update_in(cx, |workspace, _, cx| {
19664                            struct CopyPermalinkToLine;
19665
19666                            workspace.show_toast(
19667                                Toast::new(
19668                                    NotificationId::unique::<CopyPermalinkToLine>(),
19669                                    message,
19670                                ),
19671                                cx,
19672                            )
19673                        })
19674                        .ok();
19675                }
19676            }
19677        })
19678        .detach();
19679    }
19680
19681    pub fn copy_file_location(
19682        &mut self,
19683        _: &CopyFileLocation,
19684        _: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19688        if let Some(file) = self.target_file(cx) {
19689            let path = file.path().display(file.path_style(cx));
19690            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19691        }
19692    }
19693
19694    pub fn open_permalink_to_line(
19695        &mut self,
19696        _: &OpenPermalinkToLine,
19697        window: &mut Window,
19698        cx: &mut Context<Self>,
19699    ) {
19700        let permalink_task = self.get_permalink_to_line(cx);
19701        let workspace = self.workspace();
19702
19703        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19704            Ok(permalink) => {
19705                cx.update(|_, cx| {
19706                    cx.open_url(permalink.as_ref());
19707                })
19708                .ok();
19709            }
19710            Err(err) => {
19711                let message = format!("Failed to open permalink: {err}");
19712
19713                anyhow::Result::<()>::Err(err).log_err();
19714
19715                if let Some(workspace) = workspace {
19716                    workspace
19717                        .update(cx, |workspace, cx| {
19718                            struct OpenPermalinkToLine;
19719
19720                            workspace.show_toast(
19721                                Toast::new(
19722                                    NotificationId::unique::<OpenPermalinkToLine>(),
19723                                    message,
19724                                ),
19725                                cx,
19726                            )
19727                        })
19728                        .ok();
19729                }
19730            }
19731        })
19732        .detach();
19733    }
19734
19735    pub fn insert_uuid_v4(
19736        &mut self,
19737        _: &InsertUuidV4,
19738        window: &mut Window,
19739        cx: &mut Context<Self>,
19740    ) {
19741        self.insert_uuid(UuidVersion::V4, window, cx);
19742    }
19743
19744    pub fn insert_uuid_v7(
19745        &mut self,
19746        _: &InsertUuidV7,
19747        window: &mut Window,
19748        cx: &mut Context<Self>,
19749    ) {
19750        self.insert_uuid(UuidVersion::V7, window, cx);
19751    }
19752
19753    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19755        self.transact(window, cx, |this, window, cx| {
19756            let edits = this
19757                .selections
19758                .all::<Point>(cx)
19759                .into_iter()
19760                .map(|selection| {
19761                    let uuid = match version {
19762                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19763                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19764                    };
19765
19766                    (selection.range(), uuid.to_string())
19767                });
19768            this.edit(edits, cx);
19769            this.refresh_edit_prediction(true, false, window, cx);
19770        });
19771    }
19772
19773    pub fn open_selections_in_multibuffer(
19774        &mut self,
19775        _: &OpenSelectionsInMultibuffer,
19776        window: &mut Window,
19777        cx: &mut Context<Self>,
19778    ) {
19779        let multibuffer = self.buffer.read(cx);
19780
19781        let Some(buffer) = multibuffer.as_singleton() else {
19782            return;
19783        };
19784
19785        let Some(workspace) = self.workspace() else {
19786            return;
19787        };
19788
19789        let title = multibuffer.title(cx).to_string();
19790
19791        let locations = self
19792            .selections
19793            .all_anchors(cx)
19794            .iter()
19795            .map(|selection| {
19796                (
19797                    buffer.clone(),
19798                    (selection.start.text_anchor..selection.end.text_anchor)
19799                        .to_point(buffer.read(cx)),
19800                )
19801            })
19802            .into_group_map();
19803
19804        cx.spawn_in(window, async move |_, cx| {
19805            workspace.update_in(cx, |workspace, window, cx| {
19806                Self::open_locations_in_multibuffer(
19807                    workspace,
19808                    locations,
19809                    format!("Selections for '{title}'"),
19810                    false,
19811                    MultibufferSelectionMode::All,
19812                    window,
19813                    cx,
19814                );
19815            })
19816        })
19817        .detach();
19818    }
19819
19820    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19821    /// last highlight added will be used.
19822    ///
19823    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19824    pub fn highlight_rows<T: 'static>(
19825        &mut self,
19826        range: Range<Anchor>,
19827        color: Hsla,
19828        options: RowHighlightOptions,
19829        cx: &mut Context<Self>,
19830    ) {
19831        let snapshot = self.buffer().read(cx).snapshot(cx);
19832        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19833        let ix = row_highlights.binary_search_by(|highlight| {
19834            Ordering::Equal
19835                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19836                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19837        });
19838
19839        if let Err(mut ix) = ix {
19840            let index = post_inc(&mut self.highlight_order);
19841
19842            // If this range intersects with the preceding highlight, then merge it with
19843            // the preceding highlight. Otherwise insert a new highlight.
19844            let mut merged = false;
19845            if ix > 0 {
19846                let prev_highlight = &mut row_highlights[ix - 1];
19847                if prev_highlight
19848                    .range
19849                    .end
19850                    .cmp(&range.start, &snapshot)
19851                    .is_ge()
19852                {
19853                    ix -= 1;
19854                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19855                        prev_highlight.range.end = range.end;
19856                    }
19857                    merged = true;
19858                    prev_highlight.index = index;
19859                    prev_highlight.color = color;
19860                    prev_highlight.options = options;
19861                }
19862            }
19863
19864            if !merged {
19865                row_highlights.insert(
19866                    ix,
19867                    RowHighlight {
19868                        range,
19869                        index,
19870                        color,
19871                        options,
19872                        type_id: TypeId::of::<T>(),
19873                    },
19874                );
19875            }
19876
19877            // If any of the following highlights intersect with this one, merge them.
19878            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19879                let highlight = &row_highlights[ix];
19880                if next_highlight
19881                    .range
19882                    .start
19883                    .cmp(&highlight.range.end, &snapshot)
19884                    .is_le()
19885                {
19886                    if next_highlight
19887                        .range
19888                        .end
19889                        .cmp(&highlight.range.end, &snapshot)
19890                        .is_gt()
19891                    {
19892                        row_highlights[ix].range.end = next_highlight.range.end;
19893                    }
19894                    row_highlights.remove(ix + 1);
19895                } else {
19896                    break;
19897                }
19898            }
19899        }
19900    }
19901
19902    /// Remove any highlighted row ranges of the given type that intersect the
19903    /// given ranges.
19904    pub fn remove_highlighted_rows<T: 'static>(
19905        &mut self,
19906        ranges_to_remove: Vec<Range<Anchor>>,
19907        cx: &mut Context<Self>,
19908    ) {
19909        let snapshot = self.buffer().read(cx).snapshot(cx);
19910        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19911        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19912        row_highlights.retain(|highlight| {
19913            while let Some(range_to_remove) = ranges_to_remove.peek() {
19914                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19915                    Ordering::Less | Ordering::Equal => {
19916                        ranges_to_remove.next();
19917                    }
19918                    Ordering::Greater => {
19919                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19920                            Ordering::Less | Ordering::Equal => {
19921                                return false;
19922                            }
19923                            Ordering::Greater => break,
19924                        }
19925                    }
19926                }
19927            }
19928
19929            true
19930        })
19931    }
19932
19933    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19934    pub fn clear_row_highlights<T: 'static>(&mut self) {
19935        self.highlighted_rows.remove(&TypeId::of::<T>());
19936    }
19937
19938    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19939    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19940        self.highlighted_rows
19941            .get(&TypeId::of::<T>())
19942            .map_or(&[] as &[_], |vec| vec.as_slice())
19943            .iter()
19944            .map(|highlight| (highlight.range.clone(), highlight.color))
19945    }
19946
19947    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19948    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19949    /// Allows to ignore certain kinds of highlights.
19950    pub fn highlighted_display_rows(
19951        &self,
19952        window: &mut Window,
19953        cx: &mut App,
19954    ) -> BTreeMap<DisplayRow, LineHighlight> {
19955        let snapshot = self.snapshot(window, cx);
19956        let mut used_highlight_orders = HashMap::default();
19957        self.highlighted_rows
19958            .iter()
19959            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19960            .fold(
19961                BTreeMap::<DisplayRow, LineHighlight>::new(),
19962                |mut unique_rows, highlight| {
19963                    let start = highlight.range.start.to_display_point(&snapshot);
19964                    let end = highlight.range.end.to_display_point(&snapshot);
19965                    let start_row = start.row().0;
19966                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19967                        && end.column() == 0
19968                    {
19969                        end.row().0.saturating_sub(1)
19970                    } else {
19971                        end.row().0
19972                    };
19973                    for row in start_row..=end_row {
19974                        let used_index =
19975                            used_highlight_orders.entry(row).or_insert(highlight.index);
19976                        if highlight.index >= *used_index {
19977                            *used_index = highlight.index;
19978                            unique_rows.insert(
19979                                DisplayRow(row),
19980                                LineHighlight {
19981                                    include_gutter: highlight.options.include_gutter,
19982                                    border: None,
19983                                    background: highlight.color.into(),
19984                                    type_id: Some(highlight.type_id),
19985                                },
19986                            );
19987                        }
19988                    }
19989                    unique_rows
19990                },
19991            )
19992    }
19993
19994    pub fn highlighted_display_row_for_autoscroll(
19995        &self,
19996        snapshot: &DisplaySnapshot,
19997    ) -> Option<DisplayRow> {
19998        self.highlighted_rows
19999            .values()
20000            .flat_map(|highlighted_rows| highlighted_rows.iter())
20001            .filter_map(|highlight| {
20002                if highlight.options.autoscroll {
20003                    Some(highlight.range.start.to_display_point(snapshot).row())
20004                } else {
20005                    None
20006                }
20007            })
20008            .min()
20009    }
20010
20011    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20012        self.highlight_background::<SearchWithinRange>(
20013            ranges,
20014            |colors| colors.colors().editor_document_highlight_read_background,
20015            cx,
20016        )
20017    }
20018
20019    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20020        self.breadcrumb_header = Some(new_header);
20021    }
20022
20023    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20024        self.clear_background_highlights::<SearchWithinRange>(cx);
20025    }
20026
20027    pub fn highlight_background<T: 'static>(
20028        &mut self,
20029        ranges: &[Range<Anchor>],
20030        color_fetcher: fn(&Theme) -> Hsla,
20031        cx: &mut Context<Self>,
20032    ) {
20033        self.background_highlights.insert(
20034            HighlightKey::Type(TypeId::of::<T>()),
20035            (color_fetcher, Arc::from(ranges)),
20036        );
20037        self.scrollbar_marker_state.dirty = true;
20038        cx.notify();
20039    }
20040
20041    pub fn highlight_background_key<T: 'static>(
20042        &mut self,
20043        key: usize,
20044        ranges: &[Range<Anchor>],
20045        color_fetcher: fn(&Theme) -> Hsla,
20046        cx: &mut Context<Self>,
20047    ) {
20048        self.background_highlights.insert(
20049            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20050            (color_fetcher, Arc::from(ranges)),
20051        );
20052        self.scrollbar_marker_state.dirty = true;
20053        cx.notify();
20054    }
20055
20056    pub fn clear_background_highlights<T: 'static>(
20057        &mut self,
20058        cx: &mut Context<Self>,
20059    ) -> Option<BackgroundHighlight> {
20060        let text_highlights = self
20061            .background_highlights
20062            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20063        if !text_highlights.1.is_empty() {
20064            self.scrollbar_marker_state.dirty = true;
20065            cx.notify();
20066        }
20067        Some(text_highlights)
20068    }
20069
20070    pub fn highlight_gutter<T: 'static>(
20071        &mut self,
20072        ranges: impl Into<Vec<Range<Anchor>>>,
20073        color_fetcher: fn(&App) -> Hsla,
20074        cx: &mut Context<Self>,
20075    ) {
20076        self.gutter_highlights
20077            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20078        cx.notify();
20079    }
20080
20081    pub fn clear_gutter_highlights<T: 'static>(
20082        &mut self,
20083        cx: &mut Context<Self>,
20084    ) -> Option<GutterHighlight> {
20085        cx.notify();
20086        self.gutter_highlights.remove(&TypeId::of::<T>())
20087    }
20088
20089    pub fn insert_gutter_highlight<T: 'static>(
20090        &mut self,
20091        range: Range<Anchor>,
20092        color_fetcher: fn(&App) -> Hsla,
20093        cx: &mut Context<Self>,
20094    ) {
20095        let snapshot = self.buffer().read(cx).snapshot(cx);
20096        let mut highlights = self
20097            .gutter_highlights
20098            .remove(&TypeId::of::<T>())
20099            .map(|(_, highlights)| highlights)
20100            .unwrap_or_default();
20101        let ix = highlights.binary_search_by(|highlight| {
20102            Ordering::Equal
20103                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20104                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20105        });
20106        if let Err(ix) = ix {
20107            highlights.insert(ix, range);
20108        }
20109        self.gutter_highlights
20110            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20111    }
20112
20113    pub fn remove_gutter_highlights<T: 'static>(
20114        &mut self,
20115        ranges_to_remove: Vec<Range<Anchor>>,
20116        cx: &mut Context<Self>,
20117    ) {
20118        let snapshot = self.buffer().read(cx).snapshot(cx);
20119        let Some((color_fetcher, mut gutter_highlights)) =
20120            self.gutter_highlights.remove(&TypeId::of::<T>())
20121        else {
20122            return;
20123        };
20124        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20125        gutter_highlights.retain(|highlight| {
20126            while let Some(range_to_remove) = ranges_to_remove.peek() {
20127                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20128                    Ordering::Less | Ordering::Equal => {
20129                        ranges_to_remove.next();
20130                    }
20131                    Ordering::Greater => {
20132                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20133                            Ordering::Less | Ordering::Equal => {
20134                                return false;
20135                            }
20136                            Ordering::Greater => break,
20137                        }
20138                    }
20139                }
20140            }
20141
20142            true
20143        });
20144        self.gutter_highlights
20145            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20146    }
20147
20148    #[cfg(feature = "test-support")]
20149    pub fn all_text_highlights(
20150        &self,
20151        window: &mut Window,
20152        cx: &mut Context<Self>,
20153    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20154        let snapshot = self.snapshot(window, cx);
20155        self.display_map.update(cx, |display_map, _| {
20156            display_map
20157                .all_text_highlights()
20158                .map(|highlight| {
20159                    let (style, ranges) = highlight.as_ref();
20160                    (
20161                        *style,
20162                        ranges
20163                            .iter()
20164                            .map(|range| range.clone().to_display_points(&snapshot))
20165                            .collect(),
20166                    )
20167                })
20168                .collect()
20169        })
20170    }
20171
20172    #[cfg(feature = "test-support")]
20173    pub fn all_text_background_highlights(
20174        &self,
20175        window: &mut Window,
20176        cx: &mut Context<Self>,
20177    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20178        let snapshot = self.snapshot(window, cx);
20179        let buffer = &snapshot.buffer_snapshot;
20180        let start = buffer.anchor_before(0);
20181        let end = buffer.anchor_after(buffer.len());
20182        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20183    }
20184
20185    #[cfg(any(test, feature = "test-support"))]
20186    pub fn sorted_background_highlights_in_range(
20187        &self,
20188        search_range: Range<Anchor>,
20189        display_snapshot: &DisplaySnapshot,
20190        theme: &Theme,
20191    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20192        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20193        res.sort_by(|a, b| {
20194            a.0.start
20195                .cmp(&b.0.start)
20196                .then_with(|| a.0.end.cmp(&b.0.end))
20197                .then_with(|| a.1.cmp(&b.1))
20198        });
20199        res
20200    }
20201
20202    #[cfg(feature = "test-support")]
20203    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20204        let snapshot = self.buffer().read(cx).snapshot(cx);
20205
20206        let highlights = self
20207            .background_highlights
20208            .get(&HighlightKey::Type(TypeId::of::<
20209                items::BufferSearchHighlights,
20210            >()));
20211
20212        if let Some((_color, ranges)) = highlights {
20213            ranges
20214                .iter()
20215                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20216                .collect_vec()
20217        } else {
20218            vec![]
20219        }
20220    }
20221
20222    fn document_highlights_for_position<'a>(
20223        &'a self,
20224        position: Anchor,
20225        buffer: &'a MultiBufferSnapshot,
20226    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20227        let read_highlights = self
20228            .background_highlights
20229            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20230            .map(|h| &h.1);
20231        let write_highlights = self
20232            .background_highlights
20233            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20234            .map(|h| &h.1);
20235        let left_position = position.bias_left(buffer);
20236        let right_position = position.bias_right(buffer);
20237        read_highlights
20238            .into_iter()
20239            .chain(write_highlights)
20240            .flat_map(move |ranges| {
20241                let start_ix = match ranges.binary_search_by(|probe| {
20242                    let cmp = probe.end.cmp(&left_position, buffer);
20243                    if cmp.is_ge() {
20244                        Ordering::Greater
20245                    } else {
20246                        Ordering::Less
20247                    }
20248                }) {
20249                    Ok(i) | Err(i) => i,
20250                };
20251
20252                ranges[start_ix..]
20253                    .iter()
20254                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20255            })
20256    }
20257
20258    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20259        self.background_highlights
20260            .get(&HighlightKey::Type(TypeId::of::<T>()))
20261            .is_some_and(|(_, highlights)| !highlights.is_empty())
20262    }
20263
20264    /// Returns all background highlights for a given range.
20265    ///
20266    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20267    pub fn background_highlights_in_range(
20268        &self,
20269        search_range: Range<Anchor>,
20270        display_snapshot: &DisplaySnapshot,
20271        theme: &Theme,
20272    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20273        let mut results = Vec::new();
20274        for (color_fetcher, ranges) in self.background_highlights.values() {
20275            let color = color_fetcher(theme);
20276            let start_ix = match ranges.binary_search_by(|probe| {
20277                let cmp = probe
20278                    .end
20279                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20280                if cmp.is_gt() {
20281                    Ordering::Greater
20282                } else {
20283                    Ordering::Less
20284                }
20285            }) {
20286                Ok(i) | Err(i) => i,
20287            };
20288            for range in &ranges[start_ix..] {
20289                if range
20290                    .start
20291                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20292                    .is_ge()
20293                {
20294                    break;
20295                }
20296
20297                let start = range.start.to_display_point(display_snapshot);
20298                let end = range.end.to_display_point(display_snapshot);
20299                results.push((start..end, color))
20300            }
20301        }
20302        results
20303    }
20304
20305    pub fn gutter_highlights_in_range(
20306        &self,
20307        search_range: Range<Anchor>,
20308        display_snapshot: &DisplaySnapshot,
20309        cx: &App,
20310    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20311        let mut results = Vec::new();
20312        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20313            let color = color_fetcher(cx);
20314            let start_ix = match ranges.binary_search_by(|probe| {
20315                let cmp = probe
20316                    .end
20317                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20318                if cmp.is_gt() {
20319                    Ordering::Greater
20320                } else {
20321                    Ordering::Less
20322                }
20323            }) {
20324                Ok(i) | Err(i) => i,
20325            };
20326            for range in &ranges[start_ix..] {
20327                if range
20328                    .start
20329                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20330                    .is_ge()
20331                {
20332                    break;
20333                }
20334
20335                let start = range.start.to_display_point(display_snapshot);
20336                let end = range.end.to_display_point(display_snapshot);
20337                results.push((start..end, color))
20338            }
20339        }
20340        results
20341    }
20342
20343    /// Get the text ranges corresponding to the redaction query
20344    pub fn redacted_ranges(
20345        &self,
20346        search_range: Range<Anchor>,
20347        display_snapshot: &DisplaySnapshot,
20348        cx: &App,
20349    ) -> Vec<Range<DisplayPoint>> {
20350        display_snapshot
20351            .buffer_snapshot
20352            .redacted_ranges(search_range, |file| {
20353                if let Some(file) = file {
20354                    file.is_private()
20355                        && EditorSettings::get(
20356                            Some(SettingsLocation {
20357                                worktree_id: file.worktree_id(cx),
20358                                path: file.path().as_ref(),
20359                            }),
20360                            cx,
20361                        )
20362                        .redact_private_values
20363                } else {
20364                    false
20365                }
20366            })
20367            .map(|range| {
20368                range.start.to_display_point(display_snapshot)
20369                    ..range.end.to_display_point(display_snapshot)
20370            })
20371            .collect()
20372    }
20373
20374    pub fn highlight_text_key<T: 'static>(
20375        &mut self,
20376        key: usize,
20377        ranges: Vec<Range<Anchor>>,
20378        style: HighlightStyle,
20379        cx: &mut Context<Self>,
20380    ) {
20381        self.display_map.update(cx, |map, _| {
20382            map.highlight_text(
20383                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20384                ranges,
20385                style,
20386            );
20387        });
20388        cx.notify();
20389    }
20390
20391    pub fn highlight_text<T: 'static>(
20392        &mut self,
20393        ranges: Vec<Range<Anchor>>,
20394        style: HighlightStyle,
20395        cx: &mut Context<Self>,
20396    ) {
20397        self.display_map.update(cx, |map, _| {
20398            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20399        });
20400        cx.notify();
20401    }
20402
20403    pub(crate) fn highlight_inlays<T: 'static>(
20404        &mut self,
20405        highlights: Vec<InlayHighlight>,
20406        style: HighlightStyle,
20407        cx: &mut Context<Self>,
20408    ) {
20409        self.display_map.update(cx, |map, _| {
20410            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20411        });
20412        cx.notify();
20413    }
20414
20415    pub fn text_highlights<'a, T: 'static>(
20416        &'a self,
20417        cx: &'a App,
20418    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20419        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20420    }
20421
20422    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20423        let cleared = self
20424            .display_map
20425            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20426        if cleared {
20427            cx.notify();
20428        }
20429    }
20430
20431    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20432        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20433            && self.focus_handle.is_focused(window)
20434    }
20435
20436    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20437        self.show_cursor_when_unfocused = is_enabled;
20438        cx.notify();
20439    }
20440
20441    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20442        cx.notify();
20443    }
20444
20445    fn on_debug_session_event(
20446        &mut self,
20447        _session: Entity<Session>,
20448        event: &SessionEvent,
20449        cx: &mut Context<Self>,
20450    ) {
20451        if let SessionEvent::InvalidateInlineValue = event {
20452            self.refresh_inline_values(cx);
20453        }
20454    }
20455
20456    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20457        let Some(project) = self.project.clone() else {
20458            return;
20459        };
20460
20461        if !self.inline_value_cache.enabled {
20462            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20463            self.splice_inlays(&inlays, Vec::new(), cx);
20464            return;
20465        }
20466
20467        let current_execution_position = self
20468            .highlighted_rows
20469            .get(&TypeId::of::<ActiveDebugLine>())
20470            .and_then(|lines| lines.last().map(|line| line.range.end));
20471
20472        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20473            let inline_values = editor
20474                .update(cx, |editor, cx| {
20475                    let Some(current_execution_position) = current_execution_position else {
20476                        return Some(Task::ready(Ok(Vec::new())));
20477                    };
20478
20479                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20480                        let snapshot = buffer.snapshot(cx);
20481
20482                        let excerpt = snapshot.excerpt_containing(
20483                            current_execution_position..current_execution_position,
20484                        )?;
20485
20486                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20487                    })?;
20488
20489                    let range =
20490                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20491
20492                    project.inline_values(buffer, range, cx)
20493                })
20494                .ok()
20495                .flatten()?
20496                .await
20497                .context("refreshing debugger inlays")
20498                .log_err()?;
20499
20500            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20501
20502            for (buffer_id, inline_value) in inline_values
20503                .into_iter()
20504                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20505            {
20506                buffer_inline_values
20507                    .entry(buffer_id)
20508                    .or_default()
20509                    .push(inline_value);
20510            }
20511
20512            editor
20513                .update(cx, |editor, cx| {
20514                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20515                    let mut new_inlays = Vec::default();
20516
20517                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20518                        let buffer_id = buffer_snapshot.remote_id();
20519                        buffer_inline_values
20520                            .get(&buffer_id)
20521                            .into_iter()
20522                            .flatten()
20523                            .for_each(|hint| {
20524                                let inlay = Inlay::debugger(
20525                                    post_inc(&mut editor.next_inlay_id),
20526                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20527                                    hint.text(),
20528                                );
20529                                if !inlay.text.chars().contains(&'\n') {
20530                                    new_inlays.push(inlay);
20531                                }
20532                            });
20533                    }
20534
20535                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20536                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20537
20538                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20539                })
20540                .ok()?;
20541            Some(())
20542        });
20543    }
20544
20545    fn on_buffer_event(
20546        &mut self,
20547        multibuffer: &Entity<MultiBuffer>,
20548        event: &multi_buffer::Event,
20549        window: &mut Window,
20550        cx: &mut Context<Self>,
20551    ) {
20552        match event {
20553            multi_buffer::Event::Edited {
20554                singleton_buffer_edited,
20555                edited_buffer,
20556            } => {
20557                self.scrollbar_marker_state.dirty = true;
20558                self.active_indent_guides_state.dirty = true;
20559                self.refresh_active_diagnostics(cx);
20560                self.refresh_code_actions(window, cx);
20561                self.refresh_selected_text_highlights(true, window, cx);
20562                self.refresh_single_line_folds(window, cx);
20563                refresh_matching_bracket_highlights(self, window, cx);
20564                if self.has_active_edit_prediction() {
20565                    self.update_visible_edit_prediction(window, cx);
20566                }
20567                if let Some(project) = self.project.as_ref()
20568                    && let Some(edited_buffer) = edited_buffer
20569                {
20570                    project.update(cx, |project, cx| {
20571                        self.registered_buffers
20572                            .entry(edited_buffer.read(cx).remote_id())
20573                            .or_insert_with(|| {
20574                                project.register_buffer_with_language_servers(edited_buffer, cx)
20575                            });
20576                    });
20577                }
20578                cx.emit(EditorEvent::BufferEdited);
20579                cx.emit(SearchEvent::MatchesInvalidated);
20580
20581                if let Some(buffer) = edited_buffer {
20582                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20583                }
20584
20585                if *singleton_buffer_edited {
20586                    if let Some(buffer) = edited_buffer
20587                        && buffer.read(cx).file().is_none()
20588                    {
20589                        cx.emit(EditorEvent::TitleChanged);
20590                    }
20591                    if let Some(project) = &self.project {
20592                        #[allow(clippy::mutable_key_type)]
20593                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20594                            multibuffer
20595                                .all_buffers()
20596                                .into_iter()
20597                                .filter_map(|buffer| {
20598                                    buffer.update(cx, |buffer, cx| {
20599                                        let language = buffer.language()?;
20600                                        let should_discard = project.update(cx, |project, cx| {
20601                                            project.is_local()
20602                                                && !project.has_language_servers_for(buffer, cx)
20603                                        });
20604                                        should_discard.not().then_some(language.clone())
20605                                    })
20606                                })
20607                                .collect::<HashSet<_>>()
20608                        });
20609                        if !languages_affected.is_empty() {
20610                            self.refresh_inlay_hints(
20611                                InlayHintRefreshReason::BufferEdited(languages_affected),
20612                                cx,
20613                            );
20614                        }
20615                    }
20616                }
20617
20618                let Some(project) = &self.project else { return };
20619                let (telemetry, is_via_ssh) = {
20620                    let project = project.read(cx);
20621                    let telemetry = project.client().telemetry().clone();
20622                    let is_via_ssh = project.is_via_remote_server();
20623                    (telemetry, is_via_ssh)
20624                };
20625                refresh_linked_ranges(self, window, cx);
20626                telemetry.log_edit_event("editor", is_via_ssh);
20627            }
20628            multi_buffer::Event::ExcerptsAdded {
20629                buffer,
20630                predecessor,
20631                excerpts,
20632            } => {
20633                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20634                let buffer_id = buffer.read(cx).remote_id();
20635                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20636                    && let Some(project) = &self.project
20637                {
20638                    update_uncommitted_diff_for_buffer(
20639                        cx.entity(),
20640                        project,
20641                        [buffer.clone()],
20642                        self.buffer.clone(),
20643                        cx,
20644                    )
20645                    .detach();
20646                }
20647                if self.active_diagnostics != ActiveDiagnostic::All {
20648                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20649                }
20650                cx.emit(EditorEvent::ExcerptsAdded {
20651                    buffer: buffer.clone(),
20652                    predecessor: *predecessor,
20653                    excerpts: excerpts.clone(),
20654                });
20655                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20656            }
20657            multi_buffer::Event::ExcerptsRemoved {
20658                ids,
20659                removed_buffer_ids,
20660            } => {
20661                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20662                let buffer = self.buffer.read(cx);
20663                self.registered_buffers
20664                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20665                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20666                cx.emit(EditorEvent::ExcerptsRemoved {
20667                    ids: ids.clone(),
20668                    removed_buffer_ids: removed_buffer_ids.clone(),
20669                });
20670            }
20671            multi_buffer::Event::ExcerptsEdited {
20672                excerpt_ids,
20673                buffer_ids,
20674            } => {
20675                self.display_map.update(cx, |map, cx| {
20676                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20677                });
20678                cx.emit(EditorEvent::ExcerptsEdited {
20679                    ids: excerpt_ids.clone(),
20680                });
20681            }
20682            multi_buffer::Event::ExcerptsExpanded { ids } => {
20683                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20684                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20685            }
20686            multi_buffer::Event::Reparsed(buffer_id) => {
20687                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20688                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20689
20690                cx.emit(EditorEvent::Reparsed(*buffer_id));
20691            }
20692            multi_buffer::Event::DiffHunksToggled => {
20693                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20694            }
20695            multi_buffer::Event::LanguageChanged(buffer_id) => {
20696                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20697                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20698                cx.emit(EditorEvent::Reparsed(*buffer_id));
20699                cx.notify();
20700            }
20701            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20702            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20703            multi_buffer::Event::FileHandleChanged
20704            | multi_buffer::Event::Reloaded
20705            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20706            multi_buffer::Event::DiagnosticsUpdated => {
20707                self.update_diagnostics_state(window, cx);
20708            }
20709            _ => {}
20710        };
20711    }
20712
20713    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20714        if !self.diagnostics_enabled() {
20715            return;
20716        }
20717        self.refresh_active_diagnostics(cx);
20718        self.refresh_inline_diagnostics(true, window, cx);
20719        self.scrollbar_marker_state.dirty = true;
20720        cx.notify();
20721    }
20722
20723    pub fn start_temporary_diff_override(&mut self) {
20724        self.load_diff_task.take();
20725        self.temporary_diff_override = true;
20726    }
20727
20728    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20729        self.temporary_diff_override = false;
20730        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20731        self.buffer.update(cx, |buffer, cx| {
20732            buffer.set_all_diff_hunks_collapsed(cx);
20733        });
20734
20735        if let Some(project) = self.project.clone() {
20736            self.load_diff_task = Some(
20737                update_uncommitted_diff_for_buffer(
20738                    cx.entity(),
20739                    &project,
20740                    self.buffer.read(cx).all_buffers(),
20741                    self.buffer.clone(),
20742                    cx,
20743                )
20744                .shared(),
20745            );
20746        }
20747    }
20748
20749    fn on_display_map_changed(
20750        &mut self,
20751        _: Entity<DisplayMap>,
20752        _: &mut Window,
20753        cx: &mut Context<Self>,
20754    ) {
20755        cx.notify();
20756    }
20757
20758    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20759        if self.diagnostics_enabled() {
20760            let new_severity = EditorSettings::get_global(cx)
20761                .diagnostics_max_severity
20762                .unwrap_or(DiagnosticSeverity::Hint);
20763            self.set_max_diagnostics_severity(new_severity, cx);
20764        }
20765        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20766        self.update_edit_prediction_settings(cx);
20767        self.refresh_edit_prediction(true, false, window, cx);
20768        self.refresh_inline_values(cx);
20769        self.refresh_inlay_hints(
20770            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20771                self.selections.newest_anchor().head(),
20772                &self.buffer.read(cx).snapshot(cx),
20773                cx,
20774            )),
20775            cx,
20776        );
20777
20778        let old_cursor_shape = self.cursor_shape;
20779        let old_show_breadcrumbs = self.show_breadcrumbs;
20780
20781        {
20782            let editor_settings = EditorSettings::get_global(cx);
20783            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20784            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20785            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20786            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20787        }
20788
20789        if old_cursor_shape != self.cursor_shape {
20790            cx.emit(EditorEvent::CursorShapeChanged);
20791        }
20792
20793        if old_show_breadcrumbs != self.show_breadcrumbs {
20794            cx.emit(EditorEvent::BreadcrumbsChanged);
20795        }
20796
20797        let project_settings = ProjectSettings::get_global(cx);
20798        self.serialize_dirty_buffers =
20799            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20800
20801        if self.mode.is_full() {
20802            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20803            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20804            if self.show_inline_diagnostics != show_inline_diagnostics {
20805                self.show_inline_diagnostics = show_inline_diagnostics;
20806                self.refresh_inline_diagnostics(false, window, cx);
20807            }
20808
20809            if self.git_blame_inline_enabled != inline_blame_enabled {
20810                self.toggle_git_blame_inline_internal(false, window, cx);
20811            }
20812
20813            let minimap_settings = EditorSettings::get_global(cx).minimap;
20814            if self.minimap_visibility != MinimapVisibility::Disabled {
20815                if self.minimap_visibility.settings_visibility()
20816                    != minimap_settings.minimap_enabled()
20817                {
20818                    self.set_minimap_visibility(
20819                        MinimapVisibility::for_mode(self.mode(), cx),
20820                        window,
20821                        cx,
20822                    );
20823                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20824                    minimap_entity.update(cx, |minimap_editor, cx| {
20825                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20826                    })
20827                }
20828            }
20829        }
20830
20831        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20832            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20833        }) {
20834            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20835                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20836            }
20837            self.refresh_colors(false, None, window, cx);
20838        }
20839
20840        cx.notify();
20841    }
20842
20843    pub fn set_searchable(&mut self, searchable: bool) {
20844        self.searchable = searchable;
20845    }
20846
20847    pub fn searchable(&self) -> bool {
20848        self.searchable
20849    }
20850
20851    fn open_proposed_changes_editor(
20852        &mut self,
20853        _: &OpenProposedChangesEditor,
20854        window: &mut Window,
20855        cx: &mut Context<Self>,
20856    ) {
20857        let Some(workspace) = self.workspace() else {
20858            cx.propagate();
20859            return;
20860        };
20861
20862        let selections = self.selections.all::<usize>(cx);
20863        let multi_buffer = self.buffer.read(cx);
20864        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20865        let mut new_selections_by_buffer = HashMap::default();
20866        for selection in selections {
20867            for (buffer, range, _) in
20868                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20869            {
20870                let mut range = range.to_point(buffer);
20871                range.start.column = 0;
20872                range.end.column = buffer.line_len(range.end.row);
20873                new_selections_by_buffer
20874                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20875                    .or_insert(Vec::new())
20876                    .push(range)
20877            }
20878        }
20879
20880        let proposed_changes_buffers = new_selections_by_buffer
20881            .into_iter()
20882            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20883            .collect::<Vec<_>>();
20884        let proposed_changes_editor = cx.new(|cx| {
20885            ProposedChangesEditor::new(
20886                "Proposed changes",
20887                proposed_changes_buffers,
20888                self.project.clone(),
20889                window,
20890                cx,
20891            )
20892        });
20893
20894        window.defer(cx, move |window, cx| {
20895            workspace.update(cx, |workspace, cx| {
20896                workspace.active_pane().update(cx, |pane, cx| {
20897                    pane.add_item(
20898                        Box::new(proposed_changes_editor),
20899                        true,
20900                        true,
20901                        None,
20902                        window,
20903                        cx,
20904                    );
20905                });
20906            });
20907        });
20908    }
20909
20910    pub fn open_excerpts_in_split(
20911        &mut self,
20912        _: &OpenExcerptsSplit,
20913        window: &mut Window,
20914        cx: &mut Context<Self>,
20915    ) {
20916        self.open_excerpts_common(None, true, window, cx)
20917    }
20918
20919    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20920        self.open_excerpts_common(None, false, window, cx)
20921    }
20922
20923    fn open_excerpts_common(
20924        &mut self,
20925        jump_data: Option<JumpData>,
20926        split: bool,
20927        window: &mut Window,
20928        cx: &mut Context<Self>,
20929    ) {
20930        let Some(workspace) = self.workspace() else {
20931            cx.propagate();
20932            return;
20933        };
20934
20935        if self.buffer.read(cx).is_singleton() {
20936            cx.propagate();
20937            return;
20938        }
20939
20940        let mut new_selections_by_buffer = HashMap::default();
20941        match &jump_data {
20942            Some(JumpData::MultiBufferPoint {
20943                excerpt_id,
20944                position,
20945                anchor,
20946                line_offset_from_top,
20947            }) => {
20948                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20949                if let Some(buffer) = multi_buffer_snapshot
20950                    .buffer_id_for_excerpt(*excerpt_id)
20951                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20952                {
20953                    let buffer_snapshot = buffer.read(cx).snapshot();
20954                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20955                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20956                    } else {
20957                        buffer_snapshot.clip_point(*position, Bias::Left)
20958                    };
20959                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20960                    new_selections_by_buffer.insert(
20961                        buffer,
20962                        (
20963                            vec![jump_to_offset..jump_to_offset],
20964                            Some(*line_offset_from_top),
20965                        ),
20966                    );
20967                }
20968            }
20969            Some(JumpData::MultiBufferRow {
20970                row,
20971                line_offset_from_top,
20972            }) => {
20973                let point = MultiBufferPoint::new(row.0, 0);
20974                if let Some((buffer, buffer_point, _)) =
20975                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20976                {
20977                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20978                    new_selections_by_buffer
20979                        .entry(buffer)
20980                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20981                        .0
20982                        .push(buffer_offset..buffer_offset)
20983                }
20984            }
20985            None => {
20986                let selections = self.selections.all::<usize>(cx);
20987                let multi_buffer = self.buffer.read(cx);
20988                for selection in selections {
20989                    for (snapshot, range, _, anchor) in multi_buffer
20990                        .snapshot(cx)
20991                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20992                    {
20993                        if let Some(anchor) = anchor {
20994                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20995                            else {
20996                                continue;
20997                            };
20998                            let offset = text::ToOffset::to_offset(
20999                                &anchor.text_anchor,
21000                                &buffer_handle.read(cx).snapshot(),
21001                            );
21002                            let range = offset..offset;
21003                            new_selections_by_buffer
21004                                .entry(buffer_handle)
21005                                .or_insert((Vec::new(), None))
21006                                .0
21007                                .push(range)
21008                        } else {
21009                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21010                            else {
21011                                continue;
21012                            };
21013                            new_selections_by_buffer
21014                                .entry(buffer_handle)
21015                                .or_insert((Vec::new(), None))
21016                                .0
21017                                .push(range)
21018                        }
21019                    }
21020                }
21021            }
21022        }
21023
21024        new_selections_by_buffer
21025            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21026
21027        if new_selections_by_buffer.is_empty() {
21028            return;
21029        }
21030
21031        // We defer the pane interaction because we ourselves are a workspace item
21032        // and activating a new item causes the pane to call a method on us reentrantly,
21033        // which panics if we're on the stack.
21034        window.defer(cx, move |window, cx| {
21035            workspace.update(cx, |workspace, cx| {
21036                let pane = if split {
21037                    workspace.adjacent_pane(window, cx)
21038                } else {
21039                    workspace.active_pane().clone()
21040                };
21041
21042                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21043                    let editor = buffer
21044                        .read(cx)
21045                        .file()
21046                        .is_none()
21047                        .then(|| {
21048                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21049                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21050                            // Instead, we try to activate the existing editor in the pane first.
21051                            let (editor, pane_item_index) =
21052                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21053                                    let editor = item.downcast::<Editor>()?;
21054                                    let singleton_buffer =
21055                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21056                                    if singleton_buffer == buffer {
21057                                        Some((editor, i))
21058                                    } else {
21059                                        None
21060                                    }
21061                                })?;
21062                            pane.update(cx, |pane, cx| {
21063                                pane.activate_item(pane_item_index, true, true, window, cx)
21064                            });
21065                            Some(editor)
21066                        })
21067                        .flatten()
21068                        .unwrap_or_else(|| {
21069                            workspace.open_project_item::<Self>(
21070                                pane.clone(),
21071                                buffer,
21072                                true,
21073                                true,
21074                                window,
21075                                cx,
21076                            )
21077                        });
21078
21079                    editor.update(cx, |editor, cx| {
21080                        let autoscroll = match scroll_offset {
21081                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21082                            None => Autoscroll::newest(),
21083                        };
21084                        let nav_history = editor.nav_history.take();
21085                        editor.change_selections(
21086                            SelectionEffects::scroll(autoscroll),
21087                            window,
21088                            cx,
21089                            |s| {
21090                                s.select_ranges(ranges);
21091                            },
21092                        );
21093                        editor.nav_history = nav_history;
21094                    });
21095                }
21096            })
21097        });
21098    }
21099
21100    // For now, don't allow opening excerpts in buffers that aren't backed by
21101    // regular project files.
21102    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21103        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21104    }
21105
21106    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21107        let snapshot = self.buffer.read(cx).read(cx);
21108        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21109        Some(
21110            ranges
21111                .iter()
21112                .map(move |range| {
21113                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21114                })
21115                .collect(),
21116        )
21117    }
21118
21119    fn selection_replacement_ranges(
21120        &self,
21121        range: Range<OffsetUtf16>,
21122        cx: &mut App,
21123    ) -> Vec<Range<OffsetUtf16>> {
21124        let selections = self.selections.all::<OffsetUtf16>(cx);
21125        let newest_selection = selections
21126            .iter()
21127            .max_by_key(|selection| selection.id)
21128            .unwrap();
21129        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21130        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21131        let snapshot = self.buffer.read(cx).read(cx);
21132        selections
21133            .into_iter()
21134            .map(|mut selection| {
21135                selection.start.0 =
21136                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21137                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21138                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21139                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21140            })
21141            .collect()
21142    }
21143
21144    fn report_editor_event(
21145        &self,
21146        reported_event: ReportEditorEvent,
21147        file_extension: Option<String>,
21148        cx: &App,
21149    ) {
21150        if cfg!(any(test, feature = "test-support")) {
21151            return;
21152        }
21153
21154        let Some(project) = &self.project else { return };
21155
21156        // If None, we are in a file without an extension
21157        let file = self
21158            .buffer
21159            .read(cx)
21160            .as_singleton()
21161            .and_then(|b| b.read(cx).file());
21162        let file_extension = file_extension.or(file
21163            .as_ref()
21164            .and_then(|file| Path::new(file.file_name(cx)).extension())
21165            .and_then(|e| e.to_str())
21166            .map(|a| a.to_string()));
21167
21168        let vim_mode = vim_enabled(cx);
21169
21170        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21171        let copilot_enabled = edit_predictions_provider
21172            == language::language_settings::EditPredictionProvider::Copilot;
21173        let copilot_enabled_for_language = self
21174            .buffer
21175            .read(cx)
21176            .language_settings(cx)
21177            .show_edit_predictions;
21178
21179        let project = project.read(cx);
21180        let event_type = reported_event.event_type();
21181
21182        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21183            telemetry::event!(
21184                event_type,
21185                type = if auto_saved {"autosave"} else {"manual"},
21186                file_extension,
21187                vim_mode,
21188                copilot_enabled,
21189                copilot_enabled_for_language,
21190                edit_predictions_provider,
21191                is_via_ssh = project.is_via_remote_server(),
21192            );
21193        } else {
21194            telemetry::event!(
21195                event_type,
21196                file_extension,
21197                vim_mode,
21198                copilot_enabled,
21199                copilot_enabled_for_language,
21200                edit_predictions_provider,
21201                is_via_ssh = project.is_via_remote_server(),
21202            );
21203        };
21204    }
21205
21206    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21207    /// with each line being an array of {text, highlight} objects.
21208    fn copy_highlight_json(
21209        &mut self,
21210        _: &CopyHighlightJson,
21211        window: &mut Window,
21212        cx: &mut Context<Self>,
21213    ) {
21214        #[derive(Serialize)]
21215        struct Chunk<'a> {
21216            text: String,
21217            highlight: Option<&'a str>,
21218        }
21219
21220        let snapshot = self.buffer.read(cx).snapshot(cx);
21221        let range = self
21222            .selected_text_range(false, window, cx)
21223            .and_then(|selection| {
21224                if selection.range.is_empty() {
21225                    None
21226                } else {
21227                    Some(selection.range)
21228                }
21229            })
21230            .unwrap_or_else(|| 0..snapshot.len());
21231
21232        let chunks = snapshot.chunks(range, true);
21233        let mut lines = Vec::new();
21234        let mut line: VecDeque<Chunk> = VecDeque::new();
21235
21236        let Some(style) = self.style.as_ref() else {
21237            return;
21238        };
21239
21240        for chunk in chunks {
21241            let highlight = chunk
21242                .syntax_highlight_id
21243                .and_then(|id| id.name(&style.syntax));
21244            let mut chunk_lines = chunk.text.split('\n').peekable();
21245            while let Some(text) = chunk_lines.next() {
21246                let mut merged_with_last_token = false;
21247                if let Some(last_token) = line.back_mut()
21248                    && last_token.highlight == highlight
21249                {
21250                    last_token.text.push_str(text);
21251                    merged_with_last_token = true;
21252                }
21253
21254                if !merged_with_last_token {
21255                    line.push_back(Chunk {
21256                        text: text.into(),
21257                        highlight,
21258                    });
21259                }
21260
21261                if chunk_lines.peek().is_some() {
21262                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21263                        line.pop_front();
21264                    }
21265                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21266                        line.pop_back();
21267                    }
21268
21269                    lines.push(mem::take(&mut line));
21270                }
21271            }
21272        }
21273
21274        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21275            return;
21276        };
21277        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21278    }
21279
21280    pub fn open_context_menu(
21281        &mut self,
21282        _: &OpenContextMenu,
21283        window: &mut Window,
21284        cx: &mut Context<Self>,
21285    ) {
21286        self.request_autoscroll(Autoscroll::newest(), cx);
21287        let position = self.selections.newest_display(cx).start;
21288        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21289    }
21290
21291    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21292        &self.inlay_hint_cache
21293    }
21294
21295    pub fn replay_insert_event(
21296        &mut self,
21297        text: &str,
21298        relative_utf16_range: Option<Range<isize>>,
21299        window: &mut Window,
21300        cx: &mut Context<Self>,
21301    ) {
21302        if !self.input_enabled {
21303            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21304            return;
21305        }
21306        if let Some(relative_utf16_range) = relative_utf16_range {
21307            let selections = self.selections.all::<OffsetUtf16>(cx);
21308            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21309                let new_ranges = selections.into_iter().map(|range| {
21310                    let start = OffsetUtf16(
21311                        range
21312                            .head()
21313                            .0
21314                            .saturating_add_signed(relative_utf16_range.start),
21315                    );
21316                    let end = OffsetUtf16(
21317                        range
21318                            .head()
21319                            .0
21320                            .saturating_add_signed(relative_utf16_range.end),
21321                    );
21322                    start..end
21323                });
21324                s.select_ranges(new_ranges);
21325            });
21326        }
21327
21328        self.handle_input(text, window, cx);
21329    }
21330
21331    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21332        let Some(provider) = self.semantics_provider.as_ref() else {
21333            return false;
21334        };
21335
21336        let mut supports = false;
21337        self.buffer().update(cx, |this, cx| {
21338            this.for_each_buffer(|buffer| {
21339                supports |= provider.supports_inlay_hints(buffer, cx);
21340            });
21341        });
21342
21343        supports
21344    }
21345
21346    pub fn is_focused(&self, window: &Window) -> bool {
21347        self.focus_handle.is_focused(window)
21348    }
21349
21350    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21351        cx.emit(EditorEvent::Focused);
21352
21353        if let Some(descendant) = self
21354            .last_focused_descendant
21355            .take()
21356            .and_then(|descendant| descendant.upgrade())
21357        {
21358            window.focus(&descendant);
21359        } else {
21360            if let Some(blame) = self.blame.as_ref() {
21361                blame.update(cx, GitBlame::focus)
21362            }
21363
21364            self.blink_manager.update(cx, BlinkManager::enable);
21365            self.show_cursor_names(window, cx);
21366            self.buffer.update(cx, |buffer, cx| {
21367                buffer.finalize_last_transaction(cx);
21368                if self.leader_id.is_none() {
21369                    buffer.set_active_selections(
21370                        &self.selections.disjoint_anchors_arc(),
21371                        self.selections.line_mode(),
21372                        self.cursor_shape,
21373                        cx,
21374                    );
21375                }
21376            });
21377        }
21378    }
21379
21380    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21381        cx.emit(EditorEvent::FocusedIn)
21382    }
21383
21384    fn handle_focus_out(
21385        &mut self,
21386        event: FocusOutEvent,
21387        _window: &mut Window,
21388        cx: &mut Context<Self>,
21389    ) {
21390        if event.blurred != self.focus_handle {
21391            self.last_focused_descendant = Some(event.blurred);
21392        }
21393        self.selection_drag_state = SelectionDragState::None;
21394        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21395    }
21396
21397    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21398        self.blink_manager.update(cx, BlinkManager::disable);
21399        self.buffer
21400            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21401
21402        if let Some(blame) = self.blame.as_ref() {
21403            blame.update(cx, GitBlame::blur)
21404        }
21405        if !self.hover_state.focused(window, cx) {
21406            hide_hover(self, cx);
21407        }
21408        if !self
21409            .context_menu
21410            .borrow()
21411            .as_ref()
21412            .is_some_and(|context_menu| context_menu.focused(window, cx))
21413        {
21414            self.hide_context_menu(window, cx);
21415        }
21416        self.discard_edit_prediction(false, cx);
21417        cx.emit(EditorEvent::Blurred);
21418        cx.notify();
21419    }
21420
21421    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21422        let mut pending: String = window
21423            .pending_input_keystrokes()
21424            .into_iter()
21425            .flatten()
21426            .filter_map(|keystroke| {
21427                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21428                    keystroke.key_char.clone()
21429                } else {
21430                    None
21431                }
21432            })
21433            .collect();
21434
21435        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21436            pending = "".to_string();
21437        }
21438
21439        let existing_pending = self
21440            .text_highlights::<PendingInput>(cx)
21441            .map(|(_, ranges)| ranges.to_vec());
21442        if existing_pending.is_none() && pending.is_empty() {
21443            return;
21444        }
21445        let transaction =
21446            self.transact(window, cx, |this, window, cx| {
21447                let selections = this.selections.all::<usize>(cx);
21448                let edits = selections
21449                    .iter()
21450                    .map(|selection| (selection.end..selection.end, pending.clone()));
21451                this.edit(edits, cx);
21452                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21453                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21454                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21455                    }));
21456                });
21457                if let Some(existing_ranges) = existing_pending {
21458                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21459                    this.edit(edits, cx);
21460                }
21461            });
21462
21463        let snapshot = self.snapshot(window, cx);
21464        let ranges = self
21465            .selections
21466            .all::<usize>(cx)
21467            .into_iter()
21468            .map(|selection| {
21469                snapshot.buffer_snapshot.anchor_after(selection.end)
21470                    ..snapshot
21471                        .buffer_snapshot
21472                        .anchor_before(selection.end + pending.len())
21473            })
21474            .collect();
21475
21476        if pending.is_empty() {
21477            self.clear_highlights::<PendingInput>(cx);
21478        } else {
21479            self.highlight_text::<PendingInput>(
21480                ranges,
21481                HighlightStyle {
21482                    underline: Some(UnderlineStyle {
21483                        thickness: px(1.),
21484                        color: None,
21485                        wavy: false,
21486                    }),
21487                    ..Default::default()
21488                },
21489                cx,
21490            );
21491        }
21492
21493        self.ime_transaction = self.ime_transaction.or(transaction);
21494        if let Some(transaction) = self.ime_transaction {
21495            self.buffer.update(cx, |buffer, cx| {
21496                buffer.group_until_transaction(transaction, cx);
21497            });
21498        }
21499
21500        if self.text_highlights::<PendingInput>(cx).is_none() {
21501            self.ime_transaction.take();
21502        }
21503    }
21504
21505    pub fn register_action_renderer(
21506        &mut self,
21507        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21508    ) -> Subscription {
21509        let id = self.next_editor_action_id.post_inc();
21510        self.editor_actions
21511            .borrow_mut()
21512            .insert(id, Box::new(listener));
21513
21514        let editor_actions = self.editor_actions.clone();
21515        Subscription::new(move || {
21516            editor_actions.borrow_mut().remove(&id);
21517        })
21518    }
21519
21520    pub fn register_action<A: Action>(
21521        &mut self,
21522        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21523    ) -> Subscription {
21524        let id = self.next_editor_action_id.post_inc();
21525        let listener = Arc::new(listener);
21526        self.editor_actions.borrow_mut().insert(
21527            id,
21528            Box::new(move |_, window, _| {
21529                let listener = listener.clone();
21530                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21531                    let action = action.downcast_ref().unwrap();
21532                    if phase == DispatchPhase::Bubble {
21533                        listener(action, window, cx)
21534                    }
21535                })
21536            }),
21537        );
21538
21539        let editor_actions = self.editor_actions.clone();
21540        Subscription::new(move || {
21541            editor_actions.borrow_mut().remove(&id);
21542        })
21543    }
21544
21545    pub fn file_header_size(&self) -> u32 {
21546        FILE_HEADER_HEIGHT
21547    }
21548
21549    pub fn restore(
21550        &mut self,
21551        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21552        window: &mut Window,
21553        cx: &mut Context<Self>,
21554    ) {
21555        let workspace = self.workspace();
21556        let project = self.project();
21557        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21558            let mut tasks = Vec::new();
21559            for (buffer_id, changes) in revert_changes {
21560                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21561                    buffer.update(cx, |buffer, cx| {
21562                        buffer.edit(
21563                            changes
21564                                .into_iter()
21565                                .map(|(range, text)| (range, text.to_string())),
21566                            None,
21567                            cx,
21568                        );
21569                    });
21570
21571                    if let Some(project) =
21572                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21573                    {
21574                        project.update(cx, |project, cx| {
21575                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21576                        })
21577                    }
21578                }
21579            }
21580            tasks
21581        });
21582        cx.spawn_in(window, async move |_, cx| {
21583            for (buffer, task) in save_tasks {
21584                let result = task.await;
21585                if result.is_err() {
21586                    let Some(path) = buffer
21587                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21588                        .ok()
21589                    else {
21590                        continue;
21591                    };
21592                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21593                        let Some(task) = cx
21594                            .update_window_entity(workspace, |workspace, window, cx| {
21595                                workspace
21596                                    .open_path_preview(path, None, false, false, false, window, cx)
21597                            })
21598                            .ok()
21599                        else {
21600                            continue;
21601                        };
21602                        task.await.log_err();
21603                    }
21604                }
21605            }
21606        })
21607        .detach();
21608        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21609            selections.refresh()
21610        });
21611    }
21612
21613    pub fn to_pixel_point(
21614        &self,
21615        source: multi_buffer::Anchor,
21616        editor_snapshot: &EditorSnapshot,
21617        window: &mut Window,
21618    ) -> Option<gpui::Point<Pixels>> {
21619        let source_point = source.to_display_point(editor_snapshot);
21620        self.display_to_pixel_point(source_point, editor_snapshot, window)
21621    }
21622
21623    pub fn display_to_pixel_point(
21624        &self,
21625        source: DisplayPoint,
21626        editor_snapshot: &EditorSnapshot,
21627        window: &mut Window,
21628    ) -> Option<gpui::Point<Pixels>> {
21629        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21630        let text_layout_details = self.text_layout_details(window);
21631        let scroll_top = text_layout_details
21632            .scroll_anchor
21633            .scroll_position(editor_snapshot)
21634            .y;
21635
21636        if source.row().as_f32() < scroll_top.floor() {
21637            return None;
21638        }
21639        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21640        let source_y = line_height * (source.row().as_f32() - scroll_top);
21641        Some(gpui::Point::new(source_x, source_y))
21642    }
21643
21644    pub fn has_visible_completions_menu(&self) -> bool {
21645        !self.edit_prediction_preview_is_active()
21646            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21647                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21648            })
21649    }
21650
21651    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21652        if self.mode.is_minimap() {
21653            return;
21654        }
21655        self.addons
21656            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21657    }
21658
21659    pub fn unregister_addon<T: Addon>(&mut self) {
21660        self.addons.remove(&std::any::TypeId::of::<T>());
21661    }
21662
21663    pub fn addon<T: Addon>(&self) -> Option<&T> {
21664        let type_id = std::any::TypeId::of::<T>();
21665        self.addons
21666            .get(&type_id)
21667            .and_then(|item| item.to_any().downcast_ref::<T>())
21668    }
21669
21670    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21671        let type_id = std::any::TypeId::of::<T>();
21672        self.addons
21673            .get_mut(&type_id)
21674            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21675    }
21676
21677    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21678        let text_layout_details = self.text_layout_details(window);
21679        let style = &text_layout_details.editor_style;
21680        let font_id = window.text_system().resolve_font(&style.text.font());
21681        let font_size = style.text.font_size.to_pixels(window.rem_size());
21682        let line_height = style.text.line_height_in_pixels(window.rem_size());
21683        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21684        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21685
21686        CharacterDimensions {
21687            em_width,
21688            em_advance,
21689            line_height,
21690        }
21691    }
21692
21693    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21694        self.load_diff_task.clone()
21695    }
21696
21697    fn read_metadata_from_db(
21698        &mut self,
21699        item_id: u64,
21700        workspace_id: WorkspaceId,
21701        window: &mut Window,
21702        cx: &mut Context<Editor>,
21703    ) {
21704        if self.is_singleton(cx)
21705            && !self.mode.is_minimap()
21706            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21707        {
21708            let buffer_snapshot = OnceCell::new();
21709
21710            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21711                && !folds.is_empty()
21712            {
21713                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21714                self.fold_ranges(
21715                    folds
21716                        .into_iter()
21717                        .map(|(start, end)| {
21718                            snapshot.clip_offset(start, Bias::Left)
21719                                ..snapshot.clip_offset(end, Bias::Right)
21720                        })
21721                        .collect(),
21722                    false,
21723                    window,
21724                    cx,
21725                );
21726            }
21727
21728            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21729                && !selections.is_empty()
21730            {
21731                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21732                // skip adding the initial selection to selection history
21733                self.selection_history.mode = SelectionHistoryMode::Skipping;
21734                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21735                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21736                        snapshot.clip_offset(start, Bias::Left)
21737                            ..snapshot.clip_offset(end, Bias::Right)
21738                    }));
21739                });
21740                self.selection_history.mode = SelectionHistoryMode::Normal;
21741            };
21742        }
21743
21744        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21745    }
21746
21747    fn update_lsp_data(
21748        &mut self,
21749        ignore_cache: bool,
21750        for_buffer: Option<BufferId>,
21751        window: &mut Window,
21752        cx: &mut Context<'_, Self>,
21753    ) {
21754        self.pull_diagnostics(for_buffer, window, cx);
21755        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21756    }
21757}
21758
21759fn edit_for_markdown_paste<'a>(
21760    buffer: &MultiBufferSnapshot,
21761    range: Range<usize>,
21762    to_insert: &'a str,
21763    url: Option<url::Url>,
21764) -> (Range<usize>, Cow<'a, str>) {
21765    if url.is_none() {
21766        return (range, Cow::Borrowed(to_insert));
21767    };
21768
21769    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21770
21771    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21772        Cow::Borrowed(to_insert)
21773    } else {
21774        Cow::Owned(format!("[{old_text}]({to_insert})"))
21775    };
21776    (range, new_text)
21777}
21778
21779fn vim_enabled(cx: &App) -> bool {
21780    vim_mode_setting::VimModeSetting::try_get(cx)
21781        .map(|vim_mode| vim_mode.0)
21782        .unwrap_or(false)
21783}
21784
21785fn process_completion_for_edit(
21786    completion: &Completion,
21787    intent: CompletionIntent,
21788    buffer: &Entity<Buffer>,
21789    cursor_position: &text::Anchor,
21790    cx: &mut Context<Editor>,
21791) -> CompletionEdit {
21792    let buffer = buffer.read(cx);
21793    let buffer_snapshot = buffer.snapshot();
21794    let (snippet, new_text) = if completion.is_snippet() {
21795        // Workaround for typescript language server issues so that methods don't expand within
21796        // strings and functions with type expressions. The previous point is used because the query
21797        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21798        let mut snippet_source = completion.new_text.clone();
21799        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21800        previous_point.column = previous_point.column.saturating_sub(1);
21801        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21802            && scope.prefers_label_for_snippet_in_completion()
21803            && let Some(label) = completion.label()
21804            && matches!(
21805                completion.kind(),
21806                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21807            )
21808        {
21809            snippet_source = label;
21810        }
21811        match Snippet::parse(&snippet_source).log_err() {
21812            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21813            None => (None, completion.new_text.clone()),
21814        }
21815    } else {
21816        (None, completion.new_text.clone())
21817    };
21818
21819    let mut range_to_replace = {
21820        let replace_range = &completion.replace_range;
21821        if let CompletionSource::Lsp {
21822            insert_range: Some(insert_range),
21823            ..
21824        } = &completion.source
21825        {
21826            debug_assert_eq!(
21827                insert_range.start, replace_range.start,
21828                "insert_range and replace_range should start at the same position"
21829            );
21830            debug_assert!(
21831                insert_range
21832                    .start
21833                    .cmp(cursor_position, &buffer_snapshot)
21834                    .is_le(),
21835                "insert_range should start before or at cursor position"
21836            );
21837            debug_assert!(
21838                replace_range
21839                    .start
21840                    .cmp(cursor_position, &buffer_snapshot)
21841                    .is_le(),
21842                "replace_range should start before or at cursor position"
21843            );
21844
21845            let should_replace = match intent {
21846                CompletionIntent::CompleteWithInsert => false,
21847                CompletionIntent::CompleteWithReplace => true,
21848                CompletionIntent::Complete | CompletionIntent::Compose => {
21849                    let insert_mode =
21850                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21851                            .completions
21852                            .lsp_insert_mode;
21853                    match insert_mode {
21854                        LspInsertMode::Insert => false,
21855                        LspInsertMode::Replace => true,
21856                        LspInsertMode::ReplaceSubsequence => {
21857                            let mut text_to_replace = buffer.chars_for_range(
21858                                buffer.anchor_before(replace_range.start)
21859                                    ..buffer.anchor_after(replace_range.end),
21860                            );
21861                            let mut current_needle = text_to_replace.next();
21862                            for haystack_ch in completion.label.text.chars() {
21863                                if let Some(needle_ch) = current_needle
21864                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21865                                {
21866                                    current_needle = text_to_replace.next();
21867                                }
21868                            }
21869                            current_needle.is_none()
21870                        }
21871                        LspInsertMode::ReplaceSuffix => {
21872                            if replace_range
21873                                .end
21874                                .cmp(cursor_position, &buffer_snapshot)
21875                                .is_gt()
21876                            {
21877                                let range_after_cursor = *cursor_position..replace_range.end;
21878                                let text_after_cursor = buffer
21879                                    .text_for_range(
21880                                        buffer.anchor_before(range_after_cursor.start)
21881                                            ..buffer.anchor_after(range_after_cursor.end),
21882                                    )
21883                                    .collect::<String>()
21884                                    .to_ascii_lowercase();
21885                                completion
21886                                    .label
21887                                    .text
21888                                    .to_ascii_lowercase()
21889                                    .ends_with(&text_after_cursor)
21890                            } else {
21891                                true
21892                            }
21893                        }
21894                    }
21895                }
21896            };
21897
21898            if should_replace {
21899                replace_range.clone()
21900            } else {
21901                insert_range.clone()
21902            }
21903        } else {
21904            replace_range.clone()
21905        }
21906    };
21907
21908    if range_to_replace
21909        .end
21910        .cmp(cursor_position, &buffer_snapshot)
21911        .is_lt()
21912    {
21913        range_to_replace.end = *cursor_position;
21914    }
21915
21916    CompletionEdit {
21917        new_text,
21918        replace_range: range_to_replace.to_offset(buffer),
21919        snippet,
21920    }
21921}
21922
21923struct CompletionEdit {
21924    new_text: String,
21925    replace_range: Range<usize>,
21926    snippet: Option<Snippet>,
21927}
21928
21929fn insert_extra_newline_brackets(
21930    buffer: &MultiBufferSnapshot,
21931    range: Range<usize>,
21932    language: &language::LanguageScope,
21933) -> bool {
21934    let leading_whitespace_len = buffer
21935        .reversed_chars_at(range.start)
21936        .take_while(|c| c.is_whitespace() && *c != '\n')
21937        .map(|c| c.len_utf8())
21938        .sum::<usize>();
21939    let trailing_whitespace_len = buffer
21940        .chars_at(range.end)
21941        .take_while(|c| c.is_whitespace() && *c != '\n')
21942        .map(|c| c.len_utf8())
21943        .sum::<usize>();
21944    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21945
21946    language.brackets().any(|(pair, enabled)| {
21947        let pair_start = pair.start.trim_end();
21948        let pair_end = pair.end.trim_start();
21949
21950        enabled
21951            && pair.newline
21952            && buffer.contains_str_at(range.end, pair_end)
21953            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21954    })
21955}
21956
21957fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21958    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21959        [(buffer, range, _)] => (*buffer, range.clone()),
21960        _ => return false,
21961    };
21962    let pair = {
21963        let mut result: Option<BracketMatch> = None;
21964
21965        for pair in buffer
21966            .all_bracket_ranges(range.clone())
21967            .filter(move |pair| {
21968                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21969            })
21970        {
21971            let len = pair.close_range.end - pair.open_range.start;
21972
21973            if let Some(existing) = &result {
21974                let existing_len = existing.close_range.end - existing.open_range.start;
21975                if len > existing_len {
21976                    continue;
21977                }
21978            }
21979
21980            result = Some(pair);
21981        }
21982
21983        result
21984    };
21985    let Some(pair) = pair else {
21986        return false;
21987    };
21988    pair.newline_only
21989        && buffer
21990            .chars_for_range(pair.open_range.end..range.start)
21991            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21992            .all(|c| c.is_whitespace() && c != '\n')
21993}
21994
21995fn update_uncommitted_diff_for_buffer(
21996    editor: Entity<Editor>,
21997    project: &Entity<Project>,
21998    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21999    buffer: Entity<MultiBuffer>,
22000    cx: &mut App,
22001) -> Task<()> {
22002    let mut tasks = Vec::new();
22003    project.update(cx, |project, cx| {
22004        for buffer in buffers {
22005            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22006                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22007            }
22008        }
22009    });
22010    cx.spawn(async move |cx| {
22011        let diffs = future::join_all(tasks).await;
22012        if editor
22013            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22014            .unwrap_or(false)
22015        {
22016            return;
22017        }
22018
22019        buffer
22020            .update(cx, |buffer, cx| {
22021                for diff in diffs.into_iter().flatten() {
22022                    buffer.add_diff(diff, cx);
22023                }
22024            })
22025            .ok();
22026    })
22027}
22028
22029fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22030    let tab_size = tab_size.get() as usize;
22031    let mut width = offset;
22032
22033    for ch in text.chars() {
22034        width += if ch == '\t' {
22035            tab_size - (width % tab_size)
22036        } else {
22037            1
22038        };
22039    }
22040
22041    width - offset
22042}
22043
22044#[cfg(test)]
22045mod tests {
22046    use super::*;
22047
22048    #[test]
22049    fn test_string_size_with_expanded_tabs() {
22050        let nz = |val| NonZeroU32::new(val).unwrap();
22051        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22052        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22053        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22054        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22055        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22056        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22057        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22058        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22059    }
22060}
22061
22062/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22063struct WordBreakingTokenizer<'a> {
22064    input: &'a str,
22065}
22066
22067impl<'a> WordBreakingTokenizer<'a> {
22068    fn new(input: &'a str) -> Self {
22069        Self { input }
22070    }
22071}
22072
22073fn is_char_ideographic(ch: char) -> bool {
22074    use unicode_script::Script::*;
22075    use unicode_script::UnicodeScript;
22076    matches!(ch.script(), Han | Tangut | Yi)
22077}
22078
22079fn is_grapheme_ideographic(text: &str) -> bool {
22080    text.chars().any(is_char_ideographic)
22081}
22082
22083fn is_grapheme_whitespace(text: &str) -> bool {
22084    text.chars().any(|x| x.is_whitespace())
22085}
22086
22087fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22088    text.chars()
22089        .next()
22090        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22091}
22092
22093#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22094enum WordBreakToken<'a> {
22095    Word { token: &'a str, grapheme_len: usize },
22096    InlineWhitespace { token: &'a str, grapheme_len: usize },
22097    Newline,
22098}
22099
22100impl<'a> Iterator for WordBreakingTokenizer<'a> {
22101    /// Yields a span, the count of graphemes in the token, and whether it was
22102    /// whitespace. Note that it also breaks at word boundaries.
22103    type Item = WordBreakToken<'a>;
22104
22105    fn next(&mut self) -> Option<Self::Item> {
22106        use unicode_segmentation::UnicodeSegmentation;
22107        if self.input.is_empty() {
22108            return None;
22109        }
22110
22111        let mut iter = self.input.graphemes(true).peekable();
22112        let mut offset = 0;
22113        let mut grapheme_len = 0;
22114        if let Some(first_grapheme) = iter.next() {
22115            let is_newline = first_grapheme == "\n";
22116            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22117            offset += first_grapheme.len();
22118            grapheme_len += 1;
22119            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22120                if let Some(grapheme) = iter.peek().copied()
22121                    && should_stay_with_preceding_ideograph(grapheme)
22122                {
22123                    offset += grapheme.len();
22124                    grapheme_len += 1;
22125                }
22126            } else {
22127                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22128                let mut next_word_bound = words.peek().copied();
22129                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22130                    next_word_bound = words.next();
22131                }
22132                while let Some(grapheme) = iter.peek().copied() {
22133                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22134                        break;
22135                    };
22136                    if is_grapheme_whitespace(grapheme) != is_whitespace
22137                        || (grapheme == "\n") != is_newline
22138                    {
22139                        break;
22140                    };
22141                    offset += grapheme.len();
22142                    grapheme_len += 1;
22143                    iter.next();
22144                }
22145            }
22146            let token = &self.input[..offset];
22147            self.input = &self.input[offset..];
22148            if token == "\n" {
22149                Some(WordBreakToken::Newline)
22150            } else if is_whitespace {
22151                Some(WordBreakToken::InlineWhitespace {
22152                    token,
22153                    grapheme_len,
22154                })
22155            } else {
22156                Some(WordBreakToken::Word {
22157                    token,
22158                    grapheme_len,
22159                })
22160            }
22161        } else {
22162            None
22163        }
22164    }
22165}
22166
22167#[test]
22168fn test_word_breaking_tokenizer() {
22169    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22170        ("", &[]),
22171        ("  ", &[whitespace("  ", 2)]),
22172        ("Ʒ", &[word("Ʒ", 1)]),
22173        ("Ǽ", &[word("Ǽ", 1)]),
22174        ("", &[word("", 1)]),
22175        ("⋑⋑", &[word("⋑⋑", 2)]),
22176        (
22177            "原理,进而",
22178            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22179        ),
22180        (
22181            "hello world",
22182            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22183        ),
22184        (
22185            "hello, world",
22186            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22187        ),
22188        (
22189            "  hello world",
22190            &[
22191                whitespace("  ", 2),
22192                word("hello", 5),
22193                whitespace(" ", 1),
22194                word("world", 5),
22195            ],
22196        ),
22197        (
22198            "这是什么 \n 钢笔",
22199            &[
22200                word("", 1),
22201                word("", 1),
22202                word("", 1),
22203                word("", 1),
22204                whitespace(" ", 1),
22205                newline(),
22206                whitespace(" ", 1),
22207                word("", 1),
22208                word("", 1),
22209            ],
22210        ),
22211        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22212    ];
22213
22214    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22215        WordBreakToken::Word {
22216            token,
22217            grapheme_len,
22218        }
22219    }
22220
22221    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22222        WordBreakToken::InlineWhitespace {
22223            token,
22224            grapheme_len,
22225        }
22226    }
22227
22228    fn newline() -> WordBreakToken<'static> {
22229        WordBreakToken::Newline
22230    }
22231
22232    for (input, result) in tests {
22233        assert_eq!(
22234            WordBreakingTokenizer::new(input)
22235                .collect::<Vec<_>>()
22236                .as_slice(),
22237            *result,
22238        );
22239    }
22240}
22241
22242fn wrap_with_prefix(
22243    first_line_prefix: String,
22244    subsequent_lines_prefix: String,
22245    unwrapped_text: String,
22246    wrap_column: usize,
22247    tab_size: NonZeroU32,
22248    preserve_existing_whitespace: bool,
22249) -> String {
22250    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22251    let subsequent_lines_prefix_len =
22252        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22253    let mut wrapped_text = String::new();
22254    let mut current_line = first_line_prefix;
22255    let mut is_first_line = true;
22256
22257    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22258    let mut current_line_len = first_line_prefix_len;
22259    let mut in_whitespace = false;
22260    for token in tokenizer {
22261        let have_preceding_whitespace = in_whitespace;
22262        match token {
22263            WordBreakToken::Word {
22264                token,
22265                grapheme_len,
22266            } => {
22267                in_whitespace = false;
22268                let current_prefix_len = if is_first_line {
22269                    first_line_prefix_len
22270                } else {
22271                    subsequent_lines_prefix_len
22272                };
22273                if current_line_len + grapheme_len > wrap_column
22274                    && current_line_len != current_prefix_len
22275                {
22276                    wrapped_text.push_str(current_line.trim_end());
22277                    wrapped_text.push('\n');
22278                    is_first_line = false;
22279                    current_line = subsequent_lines_prefix.clone();
22280                    current_line_len = subsequent_lines_prefix_len;
22281                }
22282                current_line.push_str(token);
22283                current_line_len += grapheme_len;
22284            }
22285            WordBreakToken::InlineWhitespace {
22286                mut token,
22287                mut grapheme_len,
22288            } => {
22289                in_whitespace = true;
22290                if have_preceding_whitespace && !preserve_existing_whitespace {
22291                    continue;
22292                }
22293                if !preserve_existing_whitespace {
22294                    token = " ";
22295                    grapheme_len = 1;
22296                }
22297                let current_prefix_len = if is_first_line {
22298                    first_line_prefix_len
22299                } else {
22300                    subsequent_lines_prefix_len
22301                };
22302                if current_line_len + grapheme_len > wrap_column {
22303                    wrapped_text.push_str(current_line.trim_end());
22304                    wrapped_text.push('\n');
22305                    is_first_line = false;
22306                    current_line = subsequent_lines_prefix.clone();
22307                    current_line_len = subsequent_lines_prefix_len;
22308                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22309                    current_line.push_str(token);
22310                    current_line_len += grapheme_len;
22311                }
22312            }
22313            WordBreakToken::Newline => {
22314                in_whitespace = true;
22315                let current_prefix_len = if is_first_line {
22316                    first_line_prefix_len
22317                } else {
22318                    subsequent_lines_prefix_len
22319                };
22320                if preserve_existing_whitespace {
22321                    wrapped_text.push_str(current_line.trim_end());
22322                    wrapped_text.push('\n');
22323                    is_first_line = false;
22324                    current_line = subsequent_lines_prefix.clone();
22325                    current_line_len = subsequent_lines_prefix_len;
22326                } else if have_preceding_whitespace {
22327                    continue;
22328                } else if current_line_len + 1 > wrap_column
22329                    && current_line_len != current_prefix_len
22330                {
22331                    wrapped_text.push_str(current_line.trim_end());
22332                    wrapped_text.push('\n');
22333                    is_first_line = false;
22334                    current_line = subsequent_lines_prefix.clone();
22335                    current_line_len = subsequent_lines_prefix_len;
22336                } else if current_line_len != current_prefix_len {
22337                    current_line.push(' ');
22338                    current_line_len += 1;
22339                }
22340            }
22341        }
22342    }
22343
22344    if !current_line.is_empty() {
22345        wrapped_text.push_str(&current_line);
22346    }
22347    wrapped_text
22348}
22349
22350#[test]
22351fn test_wrap_with_prefix() {
22352    assert_eq!(
22353        wrap_with_prefix(
22354            "# ".to_string(),
22355            "# ".to_string(),
22356            "abcdefg".to_string(),
22357            4,
22358            NonZeroU32::new(4).unwrap(),
22359            false,
22360        ),
22361        "# abcdefg"
22362    );
22363    assert_eq!(
22364        wrap_with_prefix(
22365            "".to_string(),
22366            "".to_string(),
22367            "\thello world".to_string(),
22368            8,
22369            NonZeroU32::new(4).unwrap(),
22370            false,
22371        ),
22372        "hello\nworld"
22373    );
22374    assert_eq!(
22375        wrap_with_prefix(
22376            "// ".to_string(),
22377            "// ".to_string(),
22378            "xx \nyy zz aa bb cc".to_string(),
22379            12,
22380            NonZeroU32::new(4).unwrap(),
22381            false,
22382        ),
22383        "// xx yy zz\n// aa bb cc"
22384    );
22385    assert_eq!(
22386        wrap_with_prefix(
22387            String::new(),
22388            String::new(),
22389            "这是什么 \n 钢笔".to_string(),
22390            3,
22391            NonZeroU32::new(4).unwrap(),
22392            false,
22393        ),
22394        "这是什\n么 钢\n"
22395    );
22396}
22397
22398pub trait CollaborationHub {
22399    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22400    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22401    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22402}
22403
22404impl CollaborationHub for Entity<Project> {
22405    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22406        self.read(cx).collaborators()
22407    }
22408
22409    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22410        self.read(cx).user_store().read(cx).participant_indices()
22411    }
22412
22413    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22414        let this = self.read(cx);
22415        let user_ids = this.collaborators().values().map(|c| c.user_id);
22416        this.user_store().read(cx).participant_names(user_ids, cx)
22417    }
22418}
22419
22420pub trait SemanticsProvider {
22421    fn hover(
22422        &self,
22423        buffer: &Entity<Buffer>,
22424        position: text::Anchor,
22425        cx: &mut App,
22426    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22427
22428    fn inline_values(
22429        &self,
22430        buffer_handle: Entity<Buffer>,
22431        range: Range<text::Anchor>,
22432        cx: &mut App,
22433    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22434
22435    fn inlay_hints(
22436        &self,
22437        buffer_handle: Entity<Buffer>,
22438        range: Range<text::Anchor>,
22439        cx: &mut App,
22440    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22441
22442    fn resolve_inlay_hint(
22443        &self,
22444        hint: InlayHint,
22445        buffer_handle: Entity<Buffer>,
22446        server_id: LanguageServerId,
22447        cx: &mut App,
22448    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22449
22450    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22451
22452    fn document_highlights(
22453        &self,
22454        buffer: &Entity<Buffer>,
22455        position: text::Anchor,
22456        cx: &mut App,
22457    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22458
22459    fn definitions(
22460        &self,
22461        buffer: &Entity<Buffer>,
22462        position: text::Anchor,
22463        kind: GotoDefinitionKind,
22464        cx: &mut App,
22465    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22466
22467    fn range_for_rename(
22468        &self,
22469        buffer: &Entity<Buffer>,
22470        position: text::Anchor,
22471        cx: &mut App,
22472    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22473
22474    fn perform_rename(
22475        &self,
22476        buffer: &Entity<Buffer>,
22477        position: text::Anchor,
22478        new_name: String,
22479        cx: &mut App,
22480    ) -> Option<Task<Result<ProjectTransaction>>>;
22481}
22482
22483pub trait CompletionProvider {
22484    fn completions(
22485        &self,
22486        excerpt_id: ExcerptId,
22487        buffer: &Entity<Buffer>,
22488        buffer_position: text::Anchor,
22489        trigger: CompletionContext,
22490        window: &mut Window,
22491        cx: &mut Context<Editor>,
22492    ) -> Task<Result<Vec<CompletionResponse>>>;
22493
22494    fn resolve_completions(
22495        &self,
22496        _buffer: Entity<Buffer>,
22497        _completion_indices: Vec<usize>,
22498        _completions: Rc<RefCell<Box<[Completion]>>>,
22499        _cx: &mut Context<Editor>,
22500    ) -> Task<Result<bool>> {
22501        Task::ready(Ok(false))
22502    }
22503
22504    fn apply_additional_edits_for_completion(
22505        &self,
22506        _buffer: Entity<Buffer>,
22507        _completions: Rc<RefCell<Box<[Completion]>>>,
22508        _completion_index: usize,
22509        _push_to_history: bool,
22510        _cx: &mut Context<Editor>,
22511    ) -> Task<Result<Option<language::Transaction>>> {
22512        Task::ready(Ok(None))
22513    }
22514
22515    fn is_completion_trigger(
22516        &self,
22517        buffer: &Entity<Buffer>,
22518        position: language::Anchor,
22519        text: &str,
22520        trigger_in_words: bool,
22521        menu_is_open: bool,
22522        cx: &mut Context<Editor>,
22523    ) -> bool;
22524
22525    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22526
22527    fn sort_completions(&self) -> bool {
22528        true
22529    }
22530
22531    fn filter_completions(&self) -> bool {
22532        true
22533    }
22534}
22535
22536pub trait CodeActionProvider {
22537    fn id(&self) -> Arc<str>;
22538
22539    fn code_actions(
22540        &self,
22541        buffer: &Entity<Buffer>,
22542        range: Range<text::Anchor>,
22543        window: &mut Window,
22544        cx: &mut App,
22545    ) -> Task<Result<Vec<CodeAction>>>;
22546
22547    fn apply_code_action(
22548        &self,
22549        buffer_handle: Entity<Buffer>,
22550        action: CodeAction,
22551        excerpt_id: ExcerptId,
22552        push_to_history: bool,
22553        window: &mut Window,
22554        cx: &mut App,
22555    ) -> Task<Result<ProjectTransaction>>;
22556}
22557
22558impl CodeActionProvider for Entity<Project> {
22559    fn id(&self) -> Arc<str> {
22560        "project".into()
22561    }
22562
22563    fn code_actions(
22564        &self,
22565        buffer: &Entity<Buffer>,
22566        range: Range<text::Anchor>,
22567        _window: &mut Window,
22568        cx: &mut App,
22569    ) -> Task<Result<Vec<CodeAction>>> {
22570        self.update(cx, |project, cx| {
22571            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22572            let code_actions = project.code_actions(buffer, range, None, cx);
22573            cx.background_spawn(async move {
22574                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22575                Ok(code_lens_actions
22576                    .context("code lens fetch")?
22577                    .into_iter()
22578                    .flatten()
22579                    .chain(
22580                        code_actions
22581                            .context("code action fetch")?
22582                            .into_iter()
22583                            .flatten(),
22584                    )
22585                    .collect())
22586            })
22587        })
22588    }
22589
22590    fn apply_code_action(
22591        &self,
22592        buffer_handle: Entity<Buffer>,
22593        action: CodeAction,
22594        _excerpt_id: ExcerptId,
22595        push_to_history: bool,
22596        _window: &mut Window,
22597        cx: &mut App,
22598    ) -> Task<Result<ProjectTransaction>> {
22599        self.update(cx, |project, cx| {
22600            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22601        })
22602    }
22603}
22604
22605fn snippet_completions(
22606    project: &Project,
22607    buffer: &Entity<Buffer>,
22608    buffer_position: text::Anchor,
22609    cx: &mut App,
22610) -> Task<Result<CompletionResponse>> {
22611    let languages = buffer.read(cx).languages_at(buffer_position);
22612    let snippet_store = project.snippets().read(cx);
22613
22614    let scopes: Vec<_> = languages
22615        .iter()
22616        .filter_map(|language| {
22617            let language_name = language.lsp_id();
22618            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22619
22620            if snippets.is_empty() {
22621                None
22622            } else {
22623                Some((language.default_scope(), snippets))
22624            }
22625        })
22626        .collect();
22627
22628    if scopes.is_empty() {
22629        return Task::ready(Ok(CompletionResponse {
22630            completions: vec![],
22631            display_options: CompletionDisplayOptions::default(),
22632            is_incomplete: false,
22633        }));
22634    }
22635
22636    let snapshot = buffer.read(cx).text_snapshot();
22637    let chars: String = snapshot
22638        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22639        .collect();
22640    let executor = cx.background_executor().clone();
22641
22642    cx.background_spawn(async move {
22643        let mut is_incomplete = false;
22644        let mut completions: Vec<Completion> = Vec::new();
22645        for (scope, snippets) in scopes.into_iter() {
22646            let classifier =
22647                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22648            let mut last_word = chars
22649                .chars()
22650                .take_while(|c| classifier.is_word(*c))
22651                .collect::<String>();
22652            last_word = last_word.chars().rev().collect();
22653
22654            if last_word.is_empty() {
22655                return Ok(CompletionResponse {
22656                    completions: vec![],
22657                    display_options: CompletionDisplayOptions::default(),
22658                    is_incomplete: true,
22659                });
22660            }
22661
22662            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22663            let to_lsp = |point: &text::Anchor| {
22664                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22665                point_to_lsp(end)
22666            };
22667            let lsp_end = to_lsp(&buffer_position);
22668
22669            let candidates = snippets
22670                .iter()
22671                .enumerate()
22672                .flat_map(|(ix, snippet)| {
22673                    snippet
22674                        .prefix
22675                        .iter()
22676                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22677                })
22678                .collect::<Vec<StringMatchCandidate>>();
22679
22680            const MAX_RESULTS: usize = 100;
22681            let mut matches = fuzzy::match_strings(
22682                &candidates,
22683                &last_word,
22684                last_word.chars().any(|c| c.is_uppercase()),
22685                true,
22686                MAX_RESULTS,
22687                &Default::default(),
22688                executor.clone(),
22689            )
22690            .await;
22691
22692            if matches.len() >= MAX_RESULTS {
22693                is_incomplete = true;
22694            }
22695
22696            // Remove all candidates where the query's start does not match the start of any word in the candidate
22697            if let Some(query_start) = last_word.chars().next() {
22698                matches.retain(|string_match| {
22699                    split_words(&string_match.string).any(|word| {
22700                        // Check that the first codepoint of the word as lowercase matches the first
22701                        // codepoint of the query as lowercase
22702                        word.chars()
22703                            .flat_map(|codepoint| codepoint.to_lowercase())
22704                            .zip(query_start.to_lowercase())
22705                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22706                    })
22707                });
22708            }
22709
22710            let matched_strings = matches
22711                .into_iter()
22712                .map(|m| m.string)
22713                .collect::<HashSet<_>>();
22714
22715            completions.extend(snippets.iter().filter_map(|snippet| {
22716                let matching_prefix = snippet
22717                    .prefix
22718                    .iter()
22719                    .find(|prefix| matched_strings.contains(*prefix))?;
22720                let start = as_offset - last_word.len();
22721                let start = snapshot.anchor_before(start);
22722                let range = start..buffer_position;
22723                let lsp_start = to_lsp(&start);
22724                let lsp_range = lsp::Range {
22725                    start: lsp_start,
22726                    end: lsp_end,
22727                };
22728                Some(Completion {
22729                    replace_range: range,
22730                    new_text: snippet.body.clone(),
22731                    source: CompletionSource::Lsp {
22732                        insert_range: None,
22733                        server_id: LanguageServerId(usize::MAX),
22734                        resolved: true,
22735                        lsp_completion: Box::new(lsp::CompletionItem {
22736                            label: snippet.prefix.first().unwrap().clone(),
22737                            kind: Some(CompletionItemKind::SNIPPET),
22738                            label_details: snippet.description.as_ref().map(|description| {
22739                                lsp::CompletionItemLabelDetails {
22740                                    detail: Some(description.clone()),
22741                                    description: None,
22742                                }
22743                            }),
22744                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22745                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22746                                lsp::InsertReplaceEdit {
22747                                    new_text: snippet.body.clone(),
22748                                    insert: lsp_range,
22749                                    replace: lsp_range,
22750                                },
22751                            )),
22752                            filter_text: Some(snippet.body.clone()),
22753                            sort_text: Some(char::MAX.to_string()),
22754                            ..lsp::CompletionItem::default()
22755                        }),
22756                        lsp_defaults: None,
22757                    },
22758                    label: CodeLabel {
22759                        text: matching_prefix.clone(),
22760                        runs: Vec::new(),
22761                        filter_range: 0..matching_prefix.len(),
22762                    },
22763                    icon_path: None,
22764                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22765                        single_line: snippet.name.clone().into(),
22766                        plain_text: snippet
22767                            .description
22768                            .clone()
22769                            .map(|description| description.into()),
22770                    }),
22771                    insert_text_mode: None,
22772                    confirm: None,
22773                })
22774            }))
22775        }
22776
22777        Ok(CompletionResponse {
22778            completions,
22779            display_options: CompletionDisplayOptions::default(),
22780            is_incomplete,
22781        })
22782    })
22783}
22784
22785impl CompletionProvider for Entity<Project> {
22786    fn completions(
22787        &self,
22788        _excerpt_id: ExcerptId,
22789        buffer: &Entity<Buffer>,
22790        buffer_position: text::Anchor,
22791        options: CompletionContext,
22792        _window: &mut Window,
22793        cx: &mut Context<Editor>,
22794    ) -> Task<Result<Vec<CompletionResponse>>> {
22795        self.update(cx, |project, cx| {
22796            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22797            let project_completions = project.completions(buffer, buffer_position, options, cx);
22798            cx.background_spawn(async move {
22799                let mut responses = project_completions.await?;
22800                let snippets = snippets.await?;
22801                if !snippets.completions.is_empty() {
22802                    responses.push(snippets);
22803                }
22804                Ok(responses)
22805            })
22806        })
22807    }
22808
22809    fn resolve_completions(
22810        &self,
22811        buffer: Entity<Buffer>,
22812        completion_indices: Vec<usize>,
22813        completions: Rc<RefCell<Box<[Completion]>>>,
22814        cx: &mut Context<Editor>,
22815    ) -> Task<Result<bool>> {
22816        self.update(cx, |project, cx| {
22817            project.lsp_store().update(cx, |lsp_store, cx| {
22818                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22819            })
22820        })
22821    }
22822
22823    fn apply_additional_edits_for_completion(
22824        &self,
22825        buffer: Entity<Buffer>,
22826        completions: Rc<RefCell<Box<[Completion]>>>,
22827        completion_index: usize,
22828        push_to_history: bool,
22829        cx: &mut Context<Editor>,
22830    ) -> Task<Result<Option<language::Transaction>>> {
22831        self.update(cx, |project, cx| {
22832            project.lsp_store().update(cx, |lsp_store, cx| {
22833                lsp_store.apply_additional_edits_for_completion(
22834                    buffer,
22835                    completions,
22836                    completion_index,
22837                    push_to_history,
22838                    cx,
22839                )
22840            })
22841        })
22842    }
22843
22844    fn is_completion_trigger(
22845        &self,
22846        buffer: &Entity<Buffer>,
22847        position: language::Anchor,
22848        text: &str,
22849        trigger_in_words: bool,
22850        menu_is_open: bool,
22851        cx: &mut Context<Editor>,
22852    ) -> bool {
22853        let mut chars = text.chars();
22854        let char = if let Some(char) = chars.next() {
22855            char
22856        } else {
22857            return false;
22858        };
22859        if chars.next().is_some() {
22860            return false;
22861        }
22862
22863        let buffer = buffer.read(cx);
22864        let snapshot = buffer.snapshot();
22865        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22866            return false;
22867        }
22868        let classifier = snapshot
22869            .char_classifier_at(position)
22870            .scope_context(Some(CharScopeContext::Completion));
22871        if trigger_in_words && classifier.is_word(char) {
22872            return true;
22873        }
22874
22875        buffer.completion_triggers().contains(text)
22876    }
22877}
22878
22879impl SemanticsProvider for Entity<Project> {
22880    fn hover(
22881        &self,
22882        buffer: &Entity<Buffer>,
22883        position: text::Anchor,
22884        cx: &mut App,
22885    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22886        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22887    }
22888
22889    fn document_highlights(
22890        &self,
22891        buffer: &Entity<Buffer>,
22892        position: text::Anchor,
22893        cx: &mut App,
22894    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22895        Some(self.update(cx, |project, cx| {
22896            project.document_highlights(buffer, position, cx)
22897        }))
22898    }
22899
22900    fn definitions(
22901        &self,
22902        buffer: &Entity<Buffer>,
22903        position: text::Anchor,
22904        kind: GotoDefinitionKind,
22905        cx: &mut App,
22906    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22907        Some(self.update(cx, |project, cx| match kind {
22908            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22909            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22910            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22911            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22912        }))
22913    }
22914
22915    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22916        self.update(cx, |project, cx| {
22917            if project
22918                .active_debug_session(cx)
22919                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22920            {
22921                return true;
22922            }
22923
22924            buffer.update(cx, |buffer, cx| {
22925                project.any_language_server_supports_inlay_hints(buffer, cx)
22926            })
22927        })
22928    }
22929
22930    fn inline_values(
22931        &self,
22932        buffer_handle: Entity<Buffer>,
22933        range: Range<text::Anchor>,
22934        cx: &mut App,
22935    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22936        self.update(cx, |project, cx| {
22937            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22938
22939            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22940        })
22941    }
22942
22943    fn inlay_hints(
22944        &self,
22945        buffer_handle: Entity<Buffer>,
22946        range: Range<text::Anchor>,
22947        cx: &mut App,
22948    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22949        Some(self.update(cx, |project, cx| {
22950            project.inlay_hints(buffer_handle, range, cx)
22951        }))
22952    }
22953
22954    fn resolve_inlay_hint(
22955        &self,
22956        hint: InlayHint,
22957        buffer_handle: Entity<Buffer>,
22958        server_id: LanguageServerId,
22959        cx: &mut App,
22960    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22961        Some(self.update(cx, |project, cx| {
22962            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22963        }))
22964    }
22965
22966    fn range_for_rename(
22967        &self,
22968        buffer: &Entity<Buffer>,
22969        position: text::Anchor,
22970        cx: &mut App,
22971    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22972        Some(self.update(cx, |project, cx| {
22973            let buffer = buffer.clone();
22974            let task = project.prepare_rename(buffer.clone(), position, cx);
22975            cx.spawn(async move |_, cx| {
22976                Ok(match task.await? {
22977                    PrepareRenameResponse::Success(range) => Some(range),
22978                    PrepareRenameResponse::InvalidPosition => None,
22979                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22980                        // Fallback on using TreeSitter info to determine identifier range
22981                        buffer.read_with(cx, |buffer, _| {
22982                            let snapshot = buffer.snapshot();
22983                            let (range, kind) = snapshot.surrounding_word(position, None);
22984                            if kind != Some(CharKind::Word) {
22985                                return None;
22986                            }
22987                            Some(
22988                                snapshot.anchor_before(range.start)
22989                                    ..snapshot.anchor_after(range.end),
22990                            )
22991                        })?
22992                    }
22993                })
22994            })
22995        }))
22996    }
22997
22998    fn perform_rename(
22999        &self,
23000        buffer: &Entity<Buffer>,
23001        position: text::Anchor,
23002        new_name: String,
23003        cx: &mut App,
23004    ) -> Option<Task<Result<ProjectTransaction>>> {
23005        Some(self.update(cx, |project, cx| {
23006            project.perform_rename(buffer.clone(), position, new_name, cx)
23007        }))
23008    }
23009}
23010
23011fn inlay_hint_settings(
23012    location: Anchor,
23013    snapshot: &MultiBufferSnapshot,
23014    cx: &mut Context<Editor>,
23015) -> InlayHintSettings {
23016    let file = snapshot.file_at(location);
23017    let language = snapshot.language_at(location).map(|l| l.name());
23018    language_settings(language, file, cx).inlay_hints
23019}
23020
23021fn consume_contiguous_rows(
23022    contiguous_row_selections: &mut Vec<Selection<Point>>,
23023    selection: &Selection<Point>,
23024    display_map: &DisplaySnapshot,
23025    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23026) -> (MultiBufferRow, MultiBufferRow) {
23027    contiguous_row_selections.push(selection.clone());
23028    let start_row = starting_row(selection, display_map);
23029    let mut end_row = ending_row(selection, display_map);
23030
23031    while let Some(next_selection) = selections.peek() {
23032        if next_selection.start.row <= end_row.0 {
23033            end_row = ending_row(next_selection, display_map);
23034            contiguous_row_selections.push(selections.next().unwrap().clone());
23035        } else {
23036            break;
23037        }
23038    }
23039    (start_row, end_row)
23040}
23041
23042fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23043    if selection.start.column > 0 {
23044        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23045    } else {
23046        MultiBufferRow(selection.start.row)
23047    }
23048}
23049
23050fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23051    if next_selection.end.column > 0 || next_selection.is_empty() {
23052        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23053    } else {
23054        MultiBufferRow(next_selection.end.row)
23055    }
23056}
23057
23058impl EditorSnapshot {
23059    pub fn remote_selections_in_range<'a>(
23060        &'a self,
23061        range: &'a Range<Anchor>,
23062        collaboration_hub: &dyn CollaborationHub,
23063        cx: &'a App,
23064    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23065        let participant_names = collaboration_hub.user_names(cx);
23066        let participant_indices = collaboration_hub.user_participant_indices(cx);
23067        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23068        let collaborators_by_replica_id = collaborators_by_peer_id
23069            .values()
23070            .map(|collaborator| (collaborator.replica_id, collaborator))
23071            .collect::<HashMap<_, _>>();
23072        self.buffer_snapshot
23073            .selections_in_range(range, false)
23074            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23075                if replica_id == AGENT_REPLICA_ID {
23076                    Some(RemoteSelection {
23077                        replica_id,
23078                        selection,
23079                        cursor_shape,
23080                        line_mode,
23081                        collaborator_id: CollaboratorId::Agent,
23082                        user_name: Some("Agent".into()),
23083                        color: cx.theme().players().agent(),
23084                    })
23085                } else {
23086                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23087                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23088                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23089                    Some(RemoteSelection {
23090                        replica_id,
23091                        selection,
23092                        cursor_shape,
23093                        line_mode,
23094                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23095                        user_name,
23096                        color: if let Some(index) = participant_index {
23097                            cx.theme().players().color_for_participant(index.0)
23098                        } else {
23099                            cx.theme().players().absent()
23100                        },
23101                    })
23102                }
23103            })
23104    }
23105
23106    pub fn hunks_for_ranges(
23107        &self,
23108        ranges: impl IntoIterator<Item = Range<Point>>,
23109    ) -> Vec<MultiBufferDiffHunk> {
23110        let mut hunks = Vec::new();
23111        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23112            HashMap::default();
23113        for query_range in ranges {
23114            let query_rows =
23115                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23116            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23117                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23118            ) {
23119                // Include deleted hunks that are adjacent to the query range, because
23120                // otherwise they would be missed.
23121                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23122                if hunk.status().is_deleted() {
23123                    intersects_range |= hunk.row_range.start == query_rows.end;
23124                    intersects_range |= hunk.row_range.end == query_rows.start;
23125                }
23126                if intersects_range {
23127                    if !processed_buffer_rows
23128                        .entry(hunk.buffer_id)
23129                        .or_default()
23130                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23131                    {
23132                        continue;
23133                    }
23134                    hunks.push(hunk);
23135                }
23136            }
23137        }
23138
23139        hunks
23140    }
23141
23142    fn display_diff_hunks_for_rows<'a>(
23143        &'a self,
23144        display_rows: Range<DisplayRow>,
23145        folded_buffers: &'a HashSet<BufferId>,
23146    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23147        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23148        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23149
23150        self.buffer_snapshot
23151            .diff_hunks_in_range(buffer_start..buffer_end)
23152            .filter_map(|hunk| {
23153                if folded_buffers.contains(&hunk.buffer_id) {
23154                    return None;
23155                }
23156
23157                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23158                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23159
23160                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23161                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23162
23163                let display_hunk = if hunk_display_start.column() != 0 {
23164                    DisplayDiffHunk::Folded {
23165                        display_row: hunk_display_start.row(),
23166                    }
23167                } else {
23168                    let mut end_row = hunk_display_end.row();
23169                    if hunk_display_end.column() > 0 {
23170                        end_row.0 += 1;
23171                    }
23172                    let is_created_file = hunk.is_created_file();
23173                    DisplayDiffHunk::Unfolded {
23174                        status: hunk.status(),
23175                        diff_base_byte_range: hunk.diff_base_byte_range,
23176                        display_row_range: hunk_display_start.row()..end_row,
23177                        multi_buffer_range: Anchor::range_in_buffer(
23178                            hunk.excerpt_id,
23179                            hunk.buffer_id,
23180                            hunk.buffer_range,
23181                        ),
23182                        is_created_file,
23183                    }
23184                };
23185
23186                Some(display_hunk)
23187            })
23188    }
23189
23190    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23191        self.display_snapshot.buffer_snapshot.language_at(position)
23192    }
23193
23194    pub fn is_focused(&self) -> bool {
23195        self.is_focused
23196    }
23197
23198    pub fn placeholder_text(&self) -> Option<String> {
23199        self.placeholder_display_snapshot
23200            .as_ref()
23201            .map(|display_map| display_map.text())
23202    }
23203
23204    pub fn scroll_position(&self) -> gpui::Point<f32> {
23205        self.scroll_anchor.scroll_position(&self.display_snapshot)
23206    }
23207
23208    fn gutter_dimensions(
23209        &self,
23210        font_id: FontId,
23211        font_size: Pixels,
23212        max_line_number_width: Pixels,
23213        cx: &App,
23214    ) -> Option<GutterDimensions> {
23215        if !self.show_gutter {
23216            return None;
23217        }
23218
23219        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23220        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23221
23222        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23223            matches!(
23224                ProjectSettings::get_global(cx).git.git_gutter,
23225                GitGutterSetting::TrackedFiles
23226            )
23227        });
23228        let gutter_settings = EditorSettings::get_global(cx).gutter;
23229        let show_line_numbers = self
23230            .show_line_numbers
23231            .unwrap_or(gutter_settings.line_numbers);
23232        let line_gutter_width = if show_line_numbers {
23233            // Avoid flicker-like gutter resizes when the line number gains another digit by
23234            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23235            let min_width_for_number_on_gutter =
23236                ch_advance * gutter_settings.min_line_number_digits as f32;
23237            max_line_number_width.max(min_width_for_number_on_gutter)
23238        } else {
23239            0.0.into()
23240        };
23241
23242        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23243        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23244
23245        let git_blame_entries_width =
23246            self.git_blame_gutter_max_author_length
23247                .map(|max_author_length| {
23248                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23249                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23250
23251                    /// The number of characters to dedicate to gaps and margins.
23252                    const SPACING_WIDTH: usize = 4;
23253
23254                    let max_char_count = max_author_length.min(renderer.max_author_length())
23255                        + ::git::SHORT_SHA_LENGTH
23256                        + MAX_RELATIVE_TIMESTAMP.len()
23257                        + SPACING_WIDTH;
23258
23259                    ch_advance * max_char_count
23260                });
23261
23262        let is_singleton = self.buffer_snapshot.is_singleton();
23263
23264        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23265        left_padding += if !is_singleton {
23266            ch_width * 4.0
23267        } else if show_runnables || show_breakpoints {
23268            ch_width * 3.0
23269        } else if show_git_gutter && show_line_numbers {
23270            ch_width * 2.0
23271        } else if show_git_gutter || show_line_numbers {
23272            ch_width
23273        } else {
23274            px(0.)
23275        };
23276
23277        let shows_folds = is_singleton && gutter_settings.folds;
23278
23279        let right_padding = if shows_folds && show_line_numbers {
23280            ch_width * 4.0
23281        } else if shows_folds || (!is_singleton && show_line_numbers) {
23282            ch_width * 3.0
23283        } else if show_line_numbers {
23284            ch_width
23285        } else {
23286            px(0.)
23287        };
23288
23289        Some(GutterDimensions {
23290            left_padding,
23291            right_padding,
23292            width: line_gutter_width + left_padding + right_padding,
23293            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23294            git_blame_entries_width,
23295        })
23296    }
23297
23298    pub fn render_crease_toggle(
23299        &self,
23300        buffer_row: MultiBufferRow,
23301        row_contains_cursor: bool,
23302        editor: Entity<Editor>,
23303        window: &mut Window,
23304        cx: &mut App,
23305    ) -> Option<AnyElement> {
23306        let folded = self.is_line_folded(buffer_row);
23307        let mut is_foldable = false;
23308
23309        if let Some(crease) = self
23310            .crease_snapshot
23311            .query_row(buffer_row, &self.buffer_snapshot)
23312        {
23313            is_foldable = true;
23314            match crease {
23315                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23316                    if let Some(render_toggle) = render_toggle {
23317                        let toggle_callback =
23318                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23319                                if folded {
23320                                    editor.update(cx, |editor, cx| {
23321                                        editor.fold_at(buffer_row, window, cx)
23322                                    });
23323                                } else {
23324                                    editor.update(cx, |editor, cx| {
23325                                        editor.unfold_at(buffer_row, window, cx)
23326                                    });
23327                                }
23328                            });
23329                        return Some((render_toggle)(
23330                            buffer_row,
23331                            folded,
23332                            toggle_callback,
23333                            window,
23334                            cx,
23335                        ));
23336                    }
23337                }
23338            }
23339        }
23340
23341        is_foldable |= self.starts_indent(buffer_row);
23342
23343        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23344            Some(
23345                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23346                    .toggle_state(folded)
23347                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23348                        if folded {
23349                            this.unfold_at(buffer_row, window, cx);
23350                        } else {
23351                            this.fold_at(buffer_row, window, cx);
23352                        }
23353                    }))
23354                    .into_any_element(),
23355            )
23356        } else {
23357            None
23358        }
23359    }
23360
23361    pub fn render_crease_trailer(
23362        &self,
23363        buffer_row: MultiBufferRow,
23364        window: &mut Window,
23365        cx: &mut App,
23366    ) -> Option<AnyElement> {
23367        let folded = self.is_line_folded(buffer_row);
23368        if let Crease::Inline { render_trailer, .. } = self
23369            .crease_snapshot
23370            .query_row(buffer_row, &self.buffer_snapshot)?
23371        {
23372            let render_trailer = render_trailer.as_ref()?;
23373            Some(render_trailer(buffer_row, folded, window, cx))
23374        } else {
23375            None
23376        }
23377    }
23378}
23379
23380impl Deref for EditorSnapshot {
23381    type Target = DisplaySnapshot;
23382
23383    fn deref(&self) -> &Self::Target {
23384        &self.display_snapshot
23385    }
23386}
23387
23388#[derive(Clone, Debug, PartialEq, Eq)]
23389pub enum EditorEvent {
23390    InputIgnored {
23391        text: Arc<str>,
23392    },
23393    InputHandled {
23394        utf16_range_to_replace: Option<Range<isize>>,
23395        text: Arc<str>,
23396    },
23397    ExcerptsAdded {
23398        buffer: Entity<Buffer>,
23399        predecessor: ExcerptId,
23400        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23401    },
23402    ExcerptsRemoved {
23403        ids: Vec<ExcerptId>,
23404        removed_buffer_ids: Vec<BufferId>,
23405    },
23406    BufferFoldToggled {
23407        ids: Vec<ExcerptId>,
23408        folded: bool,
23409    },
23410    ExcerptsEdited {
23411        ids: Vec<ExcerptId>,
23412    },
23413    ExcerptsExpanded {
23414        ids: Vec<ExcerptId>,
23415    },
23416    BufferEdited,
23417    Edited {
23418        transaction_id: clock::Lamport,
23419    },
23420    Reparsed(BufferId),
23421    Focused,
23422    FocusedIn,
23423    Blurred,
23424    DirtyChanged,
23425    Saved,
23426    TitleChanged,
23427    SelectionsChanged {
23428        local: bool,
23429    },
23430    ScrollPositionChanged {
23431        local: bool,
23432        autoscroll: bool,
23433    },
23434    TransactionUndone {
23435        transaction_id: clock::Lamport,
23436    },
23437    TransactionBegun {
23438        transaction_id: clock::Lamport,
23439    },
23440    CursorShapeChanged,
23441    BreadcrumbsChanged,
23442    PushedToNavHistory {
23443        anchor: Anchor,
23444        is_deactivate: bool,
23445    },
23446}
23447
23448impl EventEmitter<EditorEvent> for Editor {}
23449
23450impl Focusable for Editor {
23451    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23452        self.focus_handle.clone()
23453    }
23454}
23455
23456impl Render for Editor {
23457    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23458        let settings = ThemeSettings::get_global(cx);
23459
23460        let mut text_style = match self.mode {
23461            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23462                color: cx.theme().colors().editor_foreground,
23463                font_family: settings.ui_font.family.clone(),
23464                font_features: settings.ui_font.features.clone(),
23465                font_fallbacks: settings.ui_font.fallbacks.clone(),
23466                font_size: rems(0.875).into(),
23467                font_weight: settings.ui_font.weight,
23468                line_height: relative(settings.buffer_line_height.value()),
23469                ..Default::default()
23470            },
23471            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23472                color: cx.theme().colors().editor_foreground,
23473                font_family: settings.buffer_font.family.clone(),
23474                font_features: settings.buffer_font.features.clone(),
23475                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23476                font_size: settings.buffer_font_size(cx).into(),
23477                font_weight: settings.buffer_font.weight,
23478                line_height: relative(settings.buffer_line_height.value()),
23479                ..Default::default()
23480            },
23481        };
23482        if let Some(text_style_refinement) = &self.text_style_refinement {
23483            text_style.refine(text_style_refinement)
23484        }
23485
23486        let background = match self.mode {
23487            EditorMode::SingleLine => cx.theme().system().transparent,
23488            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23489            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23490            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23491        };
23492
23493        EditorElement::new(
23494            &cx.entity(),
23495            EditorStyle {
23496                background,
23497                border: cx.theme().colors().border,
23498                local_player: cx.theme().players().local(),
23499                text: text_style,
23500                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23501                syntax: cx.theme().syntax().clone(),
23502                status: cx.theme().status().clone(),
23503                inlay_hints_style: make_inlay_hints_style(cx),
23504                edit_prediction_styles: make_suggestion_styles(cx),
23505                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23506                show_underlines: self.diagnostics_enabled(),
23507            },
23508        )
23509    }
23510}
23511
23512impl EntityInputHandler for Editor {
23513    fn text_for_range(
23514        &mut self,
23515        range_utf16: Range<usize>,
23516        adjusted_range: &mut Option<Range<usize>>,
23517        _: &mut Window,
23518        cx: &mut Context<Self>,
23519    ) -> Option<String> {
23520        let snapshot = self.buffer.read(cx).read(cx);
23521        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23522        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23523        if (start.0..end.0) != range_utf16 {
23524            adjusted_range.replace(start.0..end.0);
23525        }
23526        Some(snapshot.text_for_range(start..end).collect())
23527    }
23528
23529    fn selected_text_range(
23530        &mut self,
23531        ignore_disabled_input: bool,
23532        _: &mut Window,
23533        cx: &mut Context<Self>,
23534    ) -> Option<UTF16Selection> {
23535        // Prevent the IME menu from appearing when holding down an alphabetic key
23536        // while input is disabled.
23537        if !ignore_disabled_input && !self.input_enabled {
23538            return None;
23539        }
23540
23541        let selection = self.selections.newest::<OffsetUtf16>(cx);
23542        let range = selection.range();
23543
23544        Some(UTF16Selection {
23545            range: range.start.0..range.end.0,
23546            reversed: selection.reversed,
23547        })
23548    }
23549
23550    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23551        let snapshot = self.buffer.read(cx).read(cx);
23552        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23553        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23554    }
23555
23556    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23557        self.clear_highlights::<InputComposition>(cx);
23558        self.ime_transaction.take();
23559    }
23560
23561    fn replace_text_in_range(
23562        &mut self,
23563        range_utf16: Option<Range<usize>>,
23564        text: &str,
23565        window: &mut Window,
23566        cx: &mut Context<Self>,
23567    ) {
23568        if !self.input_enabled {
23569            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23570            return;
23571        }
23572
23573        self.transact(window, cx, |this, window, cx| {
23574            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23575                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23576                Some(this.selection_replacement_ranges(range_utf16, cx))
23577            } else {
23578                this.marked_text_ranges(cx)
23579            };
23580
23581            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23582                let newest_selection_id = this.selections.newest_anchor().id;
23583                this.selections
23584                    .all::<OffsetUtf16>(cx)
23585                    .iter()
23586                    .zip(ranges_to_replace.iter())
23587                    .find_map(|(selection, range)| {
23588                        if selection.id == newest_selection_id {
23589                            Some(
23590                                (range.start.0 as isize - selection.head().0 as isize)
23591                                    ..(range.end.0 as isize - selection.head().0 as isize),
23592                            )
23593                        } else {
23594                            None
23595                        }
23596                    })
23597            });
23598
23599            cx.emit(EditorEvent::InputHandled {
23600                utf16_range_to_replace: range_to_replace,
23601                text: text.into(),
23602            });
23603
23604            if let Some(new_selected_ranges) = new_selected_ranges {
23605                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23606                    selections.select_ranges(new_selected_ranges)
23607                });
23608                this.backspace(&Default::default(), window, cx);
23609            }
23610
23611            this.handle_input(text, window, cx);
23612        });
23613
23614        if let Some(transaction) = self.ime_transaction {
23615            self.buffer.update(cx, |buffer, cx| {
23616                buffer.group_until_transaction(transaction, cx);
23617            });
23618        }
23619
23620        self.unmark_text(window, cx);
23621    }
23622
23623    fn replace_and_mark_text_in_range(
23624        &mut self,
23625        range_utf16: Option<Range<usize>>,
23626        text: &str,
23627        new_selected_range_utf16: Option<Range<usize>>,
23628        window: &mut Window,
23629        cx: &mut Context<Self>,
23630    ) {
23631        if !self.input_enabled {
23632            return;
23633        }
23634
23635        let transaction = self.transact(window, cx, |this, window, cx| {
23636            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23637                let snapshot = this.buffer.read(cx).read(cx);
23638                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23639                    for marked_range in &mut marked_ranges {
23640                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23641                        marked_range.start.0 += relative_range_utf16.start;
23642                        marked_range.start =
23643                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23644                        marked_range.end =
23645                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23646                    }
23647                }
23648                Some(marked_ranges)
23649            } else if let Some(range_utf16) = range_utf16 {
23650                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23651                Some(this.selection_replacement_ranges(range_utf16, cx))
23652            } else {
23653                None
23654            };
23655
23656            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23657                let newest_selection_id = this.selections.newest_anchor().id;
23658                this.selections
23659                    .all::<OffsetUtf16>(cx)
23660                    .iter()
23661                    .zip(ranges_to_replace.iter())
23662                    .find_map(|(selection, range)| {
23663                        if selection.id == newest_selection_id {
23664                            Some(
23665                                (range.start.0 as isize - selection.head().0 as isize)
23666                                    ..(range.end.0 as isize - selection.head().0 as isize),
23667                            )
23668                        } else {
23669                            None
23670                        }
23671                    })
23672            });
23673
23674            cx.emit(EditorEvent::InputHandled {
23675                utf16_range_to_replace: range_to_replace,
23676                text: text.into(),
23677            });
23678
23679            if let Some(ranges) = ranges_to_replace {
23680                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23681                    s.select_ranges(ranges)
23682                });
23683            }
23684
23685            let marked_ranges = {
23686                let snapshot = this.buffer.read(cx).read(cx);
23687                this.selections
23688                    .disjoint_anchors_arc()
23689                    .iter()
23690                    .map(|selection| {
23691                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23692                    })
23693                    .collect::<Vec<_>>()
23694            };
23695
23696            if text.is_empty() {
23697                this.unmark_text(window, cx);
23698            } else {
23699                this.highlight_text::<InputComposition>(
23700                    marked_ranges.clone(),
23701                    HighlightStyle {
23702                        underline: Some(UnderlineStyle {
23703                            thickness: px(1.),
23704                            color: None,
23705                            wavy: false,
23706                        }),
23707                        ..Default::default()
23708                    },
23709                    cx,
23710                );
23711            }
23712
23713            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23714            let use_autoclose = this.use_autoclose;
23715            let use_auto_surround = this.use_auto_surround;
23716            this.set_use_autoclose(false);
23717            this.set_use_auto_surround(false);
23718            this.handle_input(text, window, cx);
23719            this.set_use_autoclose(use_autoclose);
23720            this.set_use_auto_surround(use_auto_surround);
23721
23722            if let Some(new_selected_range) = new_selected_range_utf16 {
23723                let snapshot = this.buffer.read(cx).read(cx);
23724                let new_selected_ranges = marked_ranges
23725                    .into_iter()
23726                    .map(|marked_range| {
23727                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23728                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23729                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23730                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23731                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23732                    })
23733                    .collect::<Vec<_>>();
23734
23735                drop(snapshot);
23736                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23737                    selections.select_ranges(new_selected_ranges)
23738                });
23739            }
23740        });
23741
23742        self.ime_transaction = self.ime_transaction.or(transaction);
23743        if let Some(transaction) = self.ime_transaction {
23744            self.buffer.update(cx, |buffer, cx| {
23745                buffer.group_until_transaction(transaction, cx);
23746            });
23747        }
23748
23749        if self.text_highlights::<InputComposition>(cx).is_none() {
23750            self.ime_transaction.take();
23751        }
23752    }
23753
23754    fn bounds_for_range(
23755        &mut self,
23756        range_utf16: Range<usize>,
23757        element_bounds: gpui::Bounds<Pixels>,
23758        window: &mut Window,
23759        cx: &mut Context<Self>,
23760    ) -> Option<gpui::Bounds<Pixels>> {
23761        let text_layout_details = self.text_layout_details(window);
23762        let CharacterDimensions {
23763            em_width,
23764            em_advance,
23765            line_height,
23766        } = self.character_dimensions(window);
23767
23768        let snapshot = self.snapshot(window, cx);
23769        let scroll_position = snapshot.scroll_position();
23770        let scroll_left = scroll_position.x * em_advance;
23771
23772        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23773        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23774            + self.gutter_dimensions.full_width();
23775        let y = line_height * (start.row().as_f32() - scroll_position.y);
23776
23777        Some(Bounds {
23778            origin: element_bounds.origin + point(x, y),
23779            size: size(em_width, line_height),
23780        })
23781    }
23782
23783    fn character_index_for_point(
23784        &mut self,
23785        point: gpui::Point<Pixels>,
23786        _window: &mut Window,
23787        _cx: &mut Context<Self>,
23788    ) -> Option<usize> {
23789        let position_map = self.last_position_map.as_ref()?;
23790        if !position_map.text_hitbox.contains(&point) {
23791            return None;
23792        }
23793        let display_point = position_map.point_for_position(point).previous_valid;
23794        let anchor = position_map
23795            .snapshot
23796            .display_point_to_anchor(display_point, Bias::Left);
23797        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23798        Some(utf16_offset.0)
23799    }
23800}
23801
23802trait SelectionExt {
23803    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23804    fn spanned_rows(
23805        &self,
23806        include_end_if_at_line_start: bool,
23807        map: &DisplaySnapshot,
23808    ) -> Range<MultiBufferRow>;
23809}
23810
23811impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23812    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23813        let start = self
23814            .start
23815            .to_point(&map.buffer_snapshot)
23816            .to_display_point(map);
23817        let end = self
23818            .end
23819            .to_point(&map.buffer_snapshot)
23820            .to_display_point(map);
23821        if self.reversed {
23822            end..start
23823        } else {
23824            start..end
23825        }
23826    }
23827
23828    fn spanned_rows(
23829        &self,
23830        include_end_if_at_line_start: bool,
23831        map: &DisplaySnapshot,
23832    ) -> Range<MultiBufferRow> {
23833        let start = self.start.to_point(&map.buffer_snapshot);
23834        let mut end = self.end.to_point(&map.buffer_snapshot);
23835        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23836            end.row -= 1;
23837        }
23838
23839        let buffer_start = map.prev_line_boundary(start).0;
23840        let buffer_end = map.next_line_boundary(end).0;
23841        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23842    }
23843}
23844
23845impl<T: InvalidationRegion> InvalidationStack<T> {
23846    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23847    where
23848        S: Clone + ToOffset,
23849    {
23850        while let Some(region) = self.last() {
23851            let all_selections_inside_invalidation_ranges =
23852                if selections.len() == region.ranges().len() {
23853                    selections
23854                        .iter()
23855                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23856                        .all(|(selection, invalidation_range)| {
23857                            let head = selection.head().to_offset(buffer);
23858                            invalidation_range.start <= head && invalidation_range.end >= head
23859                        })
23860                } else {
23861                    false
23862                };
23863
23864            if all_selections_inside_invalidation_ranges {
23865                break;
23866            } else {
23867                self.pop();
23868            }
23869        }
23870    }
23871}
23872
23873impl<T> Default for InvalidationStack<T> {
23874    fn default() -> Self {
23875        Self(Default::default())
23876    }
23877}
23878
23879impl<T> Deref for InvalidationStack<T> {
23880    type Target = Vec<T>;
23881
23882    fn deref(&self) -> &Self::Target {
23883        &self.0
23884    }
23885}
23886
23887impl<T> DerefMut for InvalidationStack<T> {
23888    fn deref_mut(&mut self) -> &mut Self::Target {
23889        &mut self.0
23890    }
23891}
23892
23893impl InvalidationRegion for SnippetState {
23894    fn ranges(&self) -> &[Range<Anchor>] {
23895        &self.ranges[self.active_index]
23896    }
23897}
23898
23899fn edit_prediction_edit_text(
23900    current_snapshot: &BufferSnapshot,
23901    edits: &[(Range<Anchor>, String)],
23902    edit_preview: &EditPreview,
23903    include_deletions: bool,
23904    cx: &App,
23905) -> HighlightedText {
23906    let edits = edits
23907        .iter()
23908        .map(|(anchor, text)| {
23909            (
23910                anchor.start.text_anchor..anchor.end.text_anchor,
23911                text.clone(),
23912            )
23913        })
23914        .collect::<Vec<_>>();
23915
23916    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23917}
23918
23919fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23920    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23921    // Just show the raw edit text with basic styling
23922    let mut text = String::new();
23923    let mut highlights = Vec::new();
23924
23925    let insertion_highlight_style = HighlightStyle {
23926        color: Some(cx.theme().colors().text),
23927        ..Default::default()
23928    };
23929
23930    for (_, edit_text) in edits {
23931        let start_offset = text.len();
23932        text.push_str(edit_text);
23933        let end_offset = text.len();
23934
23935        if start_offset < end_offset {
23936            highlights.push((start_offset..end_offset, insertion_highlight_style));
23937        }
23938    }
23939
23940    HighlightedText {
23941        text: text.into(),
23942        highlights,
23943    }
23944}
23945
23946pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23947    match severity {
23948        lsp::DiagnosticSeverity::ERROR => colors.error,
23949        lsp::DiagnosticSeverity::WARNING => colors.warning,
23950        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23951        lsp::DiagnosticSeverity::HINT => colors.info,
23952        _ => colors.ignored,
23953    }
23954}
23955
23956pub fn styled_runs_for_code_label<'a>(
23957    label: &'a CodeLabel,
23958    syntax_theme: &'a theme::SyntaxTheme,
23959) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23960    let fade_out = HighlightStyle {
23961        fade_out: Some(0.35),
23962        ..Default::default()
23963    };
23964
23965    let mut prev_end = label.filter_range.end;
23966    label
23967        .runs
23968        .iter()
23969        .enumerate()
23970        .flat_map(move |(ix, (range, highlight_id))| {
23971            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23972                style
23973            } else {
23974                return Default::default();
23975            };
23976            let muted_style = style.highlight(fade_out);
23977
23978            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23979            if range.start >= label.filter_range.end {
23980                if range.start > prev_end {
23981                    runs.push((prev_end..range.start, fade_out));
23982                }
23983                runs.push((range.clone(), muted_style));
23984            } else if range.end <= label.filter_range.end {
23985                runs.push((range.clone(), style));
23986            } else {
23987                runs.push((range.start..label.filter_range.end, style));
23988                runs.push((label.filter_range.end..range.end, muted_style));
23989            }
23990            prev_end = cmp::max(prev_end, range.end);
23991
23992            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23993                runs.push((prev_end..label.text.len(), fade_out));
23994            }
23995
23996            runs
23997        })
23998}
23999
24000pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24001    let mut prev_index = 0;
24002    let mut prev_codepoint: Option<char> = None;
24003    text.char_indices()
24004        .chain([(text.len(), '\0')])
24005        .filter_map(move |(index, codepoint)| {
24006            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24007            let is_boundary = index == text.len()
24008                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24009                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24010            if is_boundary {
24011                let chunk = &text[prev_index..index];
24012                prev_index = index;
24013                Some(chunk)
24014            } else {
24015                None
24016            }
24017        })
24018}
24019
24020pub trait RangeToAnchorExt: Sized {
24021    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24022
24023    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24024        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24025        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24026    }
24027}
24028
24029impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24030    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24031        let start_offset = self.start.to_offset(snapshot);
24032        let end_offset = self.end.to_offset(snapshot);
24033        if start_offset == end_offset {
24034            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24035        } else {
24036            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24037        }
24038    }
24039}
24040
24041pub trait RowExt {
24042    fn as_f32(&self) -> f32;
24043
24044    fn next_row(&self) -> Self;
24045
24046    fn previous_row(&self) -> Self;
24047
24048    fn minus(&self, other: Self) -> u32;
24049}
24050
24051impl RowExt for DisplayRow {
24052    fn as_f32(&self) -> f32 {
24053        self.0 as f32
24054    }
24055
24056    fn next_row(&self) -> Self {
24057        Self(self.0 + 1)
24058    }
24059
24060    fn previous_row(&self) -> Self {
24061        Self(self.0.saturating_sub(1))
24062    }
24063
24064    fn minus(&self, other: Self) -> u32 {
24065        self.0 - other.0
24066    }
24067}
24068
24069impl RowExt for MultiBufferRow {
24070    fn as_f32(&self) -> f32 {
24071        self.0 as f32
24072    }
24073
24074    fn next_row(&self) -> Self {
24075        Self(self.0 + 1)
24076    }
24077
24078    fn previous_row(&self) -> Self {
24079        Self(self.0.saturating_sub(1))
24080    }
24081
24082    fn minus(&self, other: Self) -> u32 {
24083        self.0 - other.0
24084    }
24085}
24086
24087trait RowRangeExt {
24088    type Row;
24089
24090    fn len(&self) -> usize;
24091
24092    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24093}
24094
24095impl RowRangeExt for Range<MultiBufferRow> {
24096    type Row = MultiBufferRow;
24097
24098    fn len(&self) -> usize {
24099        (self.end.0 - self.start.0) as usize
24100    }
24101
24102    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24103        (self.start.0..self.end.0).map(MultiBufferRow)
24104    }
24105}
24106
24107impl RowRangeExt for Range<DisplayRow> {
24108    type Row = DisplayRow;
24109
24110    fn len(&self) -> usize {
24111        (self.end.0 - self.start.0) as usize
24112    }
24113
24114    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24115        (self.start.0..self.end.0).map(DisplayRow)
24116    }
24117}
24118
24119/// If select range has more than one line, we
24120/// just point the cursor to range.start.
24121fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24122    if range.start.row == range.end.row {
24123        range
24124    } else {
24125        range.start..range.start
24126    }
24127}
24128pub struct KillRing(ClipboardItem);
24129impl Global for KillRing {}
24130
24131const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24132
24133enum BreakpointPromptEditAction {
24134    Log,
24135    Condition,
24136    HitCondition,
24137}
24138
24139struct BreakpointPromptEditor {
24140    pub(crate) prompt: Entity<Editor>,
24141    editor: WeakEntity<Editor>,
24142    breakpoint_anchor: Anchor,
24143    breakpoint: Breakpoint,
24144    edit_action: BreakpointPromptEditAction,
24145    block_ids: HashSet<CustomBlockId>,
24146    editor_margins: Arc<Mutex<EditorMargins>>,
24147    _subscriptions: Vec<Subscription>,
24148}
24149
24150impl BreakpointPromptEditor {
24151    const MAX_LINES: u8 = 4;
24152
24153    fn new(
24154        editor: WeakEntity<Editor>,
24155        breakpoint_anchor: Anchor,
24156        breakpoint: Breakpoint,
24157        edit_action: BreakpointPromptEditAction,
24158        window: &mut Window,
24159        cx: &mut Context<Self>,
24160    ) -> Self {
24161        let base_text = match edit_action {
24162            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24163            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24164            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24165        }
24166        .map(|msg| msg.to_string())
24167        .unwrap_or_default();
24168
24169        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24170        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24171
24172        let prompt = cx.new(|cx| {
24173            let mut prompt = Editor::new(
24174                EditorMode::AutoHeight {
24175                    min_lines: 1,
24176                    max_lines: Some(Self::MAX_LINES as usize),
24177                },
24178                buffer,
24179                None,
24180                window,
24181                cx,
24182            );
24183            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24184            prompt.set_show_cursor_when_unfocused(false, cx);
24185            prompt.set_placeholder_text(
24186                match edit_action {
24187                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24188                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24189                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24190                },
24191                window,
24192                cx,
24193            );
24194
24195            prompt
24196        });
24197
24198        Self {
24199            prompt,
24200            editor,
24201            breakpoint_anchor,
24202            breakpoint,
24203            edit_action,
24204            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24205            block_ids: Default::default(),
24206            _subscriptions: vec![],
24207        }
24208    }
24209
24210    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24211        self.block_ids.extend(block_ids)
24212    }
24213
24214    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24215        if let Some(editor) = self.editor.upgrade() {
24216            let message = self
24217                .prompt
24218                .read(cx)
24219                .buffer
24220                .read(cx)
24221                .as_singleton()
24222                .expect("A multi buffer in breakpoint prompt isn't possible")
24223                .read(cx)
24224                .as_rope()
24225                .to_string();
24226
24227            editor.update(cx, |editor, cx| {
24228                editor.edit_breakpoint_at_anchor(
24229                    self.breakpoint_anchor,
24230                    self.breakpoint.clone(),
24231                    match self.edit_action {
24232                        BreakpointPromptEditAction::Log => {
24233                            BreakpointEditAction::EditLogMessage(message.into())
24234                        }
24235                        BreakpointPromptEditAction::Condition => {
24236                            BreakpointEditAction::EditCondition(message.into())
24237                        }
24238                        BreakpointPromptEditAction::HitCondition => {
24239                            BreakpointEditAction::EditHitCondition(message.into())
24240                        }
24241                    },
24242                    cx,
24243                );
24244
24245                editor.remove_blocks(self.block_ids.clone(), None, cx);
24246                cx.focus_self(window);
24247            });
24248        }
24249    }
24250
24251    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24252        self.editor
24253            .update(cx, |editor, cx| {
24254                editor.remove_blocks(self.block_ids.clone(), None, cx);
24255                window.focus(&editor.focus_handle);
24256            })
24257            .log_err();
24258    }
24259
24260    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24261        let settings = ThemeSettings::get_global(cx);
24262        let text_style = TextStyle {
24263            color: if self.prompt.read(cx).read_only(cx) {
24264                cx.theme().colors().text_disabled
24265            } else {
24266                cx.theme().colors().text
24267            },
24268            font_family: settings.buffer_font.family.clone(),
24269            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24270            font_size: settings.buffer_font_size(cx).into(),
24271            font_weight: settings.buffer_font.weight,
24272            line_height: relative(settings.buffer_line_height.value()),
24273            ..Default::default()
24274        };
24275        EditorElement::new(
24276            &self.prompt,
24277            EditorStyle {
24278                background: cx.theme().colors().editor_background,
24279                local_player: cx.theme().players().local(),
24280                text: text_style,
24281                ..Default::default()
24282            },
24283        )
24284    }
24285}
24286
24287impl Render for BreakpointPromptEditor {
24288    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24289        let editor_margins = *self.editor_margins.lock();
24290        let gutter_dimensions = editor_margins.gutter;
24291        h_flex()
24292            .key_context("Editor")
24293            .bg(cx.theme().colors().editor_background)
24294            .border_y_1()
24295            .border_color(cx.theme().status().info_border)
24296            .size_full()
24297            .py(window.line_height() / 2.5)
24298            .on_action(cx.listener(Self::confirm))
24299            .on_action(cx.listener(Self::cancel))
24300            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24301            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24302    }
24303}
24304
24305impl Focusable for BreakpointPromptEditor {
24306    fn focus_handle(&self, cx: &App) -> FocusHandle {
24307        self.prompt.focus_handle(cx)
24308    }
24309}
24310
24311fn all_edits_insertions_or_deletions(
24312    edits: &Vec<(Range<Anchor>, String)>,
24313    snapshot: &MultiBufferSnapshot,
24314) -> bool {
24315    let mut all_insertions = true;
24316    let mut all_deletions = true;
24317
24318    for (range, new_text) in edits.iter() {
24319        let range_is_empty = range.to_offset(snapshot).is_empty();
24320        let text_is_empty = new_text.is_empty();
24321
24322        if range_is_empty != text_is_empty {
24323            if range_is_empty {
24324                all_deletions = false;
24325            } else {
24326                all_insertions = false;
24327            }
24328        } else {
24329            return false;
24330        }
24331
24332        if !all_insertions && !all_deletions {
24333            return false;
24334        }
24335    }
24336    all_insertions || all_deletions
24337}
24338
24339struct MissingEditPredictionKeybindingTooltip;
24340
24341impl Render for MissingEditPredictionKeybindingTooltip {
24342    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24343        ui::tooltip_container(window, cx, |container, _, cx| {
24344            container
24345                .flex_shrink_0()
24346                .max_w_80()
24347                .min_h(rems_from_px(124.))
24348                .justify_between()
24349                .child(
24350                    v_flex()
24351                        .flex_1()
24352                        .text_ui_sm(cx)
24353                        .child(Label::new("Conflict with Accept Keybinding"))
24354                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24355                )
24356                .child(
24357                    h_flex()
24358                        .pb_1()
24359                        .gap_1()
24360                        .items_end()
24361                        .w_full()
24362                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24363                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24364                        }))
24365                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24366                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24367                        })),
24368                )
24369        })
24370    }
24371}
24372
24373#[derive(Debug, Clone, Copy, PartialEq)]
24374pub struct LineHighlight {
24375    pub background: Background,
24376    pub border: Option<gpui::Hsla>,
24377    pub include_gutter: bool,
24378    pub type_id: Option<TypeId>,
24379}
24380
24381struct LineManipulationResult {
24382    pub new_text: String,
24383    pub line_count_before: usize,
24384    pub line_count_after: usize,
24385}
24386
24387fn render_diff_hunk_controls(
24388    row: u32,
24389    status: &DiffHunkStatus,
24390    hunk_range: Range<Anchor>,
24391    is_created_file: bool,
24392    line_height: Pixels,
24393    editor: &Entity<Editor>,
24394    _window: &mut Window,
24395    cx: &mut App,
24396) -> AnyElement {
24397    h_flex()
24398        .h(line_height)
24399        .mr_1()
24400        .gap_1()
24401        .px_0p5()
24402        .pb_1()
24403        .border_x_1()
24404        .border_b_1()
24405        .border_color(cx.theme().colors().border_variant)
24406        .rounded_b_lg()
24407        .bg(cx.theme().colors().editor_background)
24408        .gap_1()
24409        .block_mouse_except_scroll()
24410        .shadow_md()
24411        .child(if status.has_secondary_hunk() {
24412            Button::new(("stage", row as u64), "Stage")
24413                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24414                .tooltip({
24415                    let focus_handle = editor.focus_handle(cx);
24416                    move |window, cx| {
24417                        Tooltip::for_action_in(
24418                            "Stage Hunk",
24419                            &::git::ToggleStaged,
24420                            &focus_handle,
24421                            window,
24422                            cx,
24423                        )
24424                    }
24425                })
24426                .on_click({
24427                    let editor = editor.clone();
24428                    move |_event, _window, cx| {
24429                        editor.update(cx, |editor, cx| {
24430                            editor.stage_or_unstage_diff_hunks(
24431                                true,
24432                                vec![hunk_range.start..hunk_range.start],
24433                                cx,
24434                            );
24435                        });
24436                    }
24437                })
24438        } else {
24439            Button::new(("unstage", row as u64), "Unstage")
24440                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24441                .tooltip({
24442                    let focus_handle = editor.focus_handle(cx);
24443                    move |window, cx| {
24444                        Tooltip::for_action_in(
24445                            "Unstage Hunk",
24446                            &::git::ToggleStaged,
24447                            &focus_handle,
24448                            window,
24449                            cx,
24450                        )
24451                    }
24452                })
24453                .on_click({
24454                    let editor = editor.clone();
24455                    move |_event, _window, cx| {
24456                        editor.update(cx, |editor, cx| {
24457                            editor.stage_or_unstage_diff_hunks(
24458                                false,
24459                                vec![hunk_range.start..hunk_range.start],
24460                                cx,
24461                            );
24462                        });
24463                    }
24464                })
24465        })
24466        .child(
24467            Button::new(("restore", row as u64), "Restore")
24468                .tooltip({
24469                    let focus_handle = editor.focus_handle(cx);
24470                    move |window, cx| {
24471                        Tooltip::for_action_in(
24472                            "Restore Hunk",
24473                            &::git::Restore,
24474                            &focus_handle,
24475                            window,
24476                            cx,
24477                        )
24478                    }
24479                })
24480                .on_click({
24481                    let editor = editor.clone();
24482                    move |_event, window, cx| {
24483                        editor.update(cx, |editor, cx| {
24484                            let snapshot = editor.snapshot(window, cx);
24485                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24486                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24487                        });
24488                    }
24489                })
24490                .disabled(is_created_file),
24491        )
24492        .when(
24493            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24494            |el| {
24495                el.child(
24496                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24497                        .shape(IconButtonShape::Square)
24498                        .icon_size(IconSize::Small)
24499                        // .disabled(!has_multiple_hunks)
24500                        .tooltip({
24501                            let focus_handle = editor.focus_handle(cx);
24502                            move |window, cx| {
24503                                Tooltip::for_action_in(
24504                                    "Next Hunk",
24505                                    &GoToHunk,
24506                                    &focus_handle,
24507                                    window,
24508                                    cx,
24509                                )
24510                            }
24511                        })
24512                        .on_click({
24513                            let editor = editor.clone();
24514                            move |_event, window, cx| {
24515                                editor.update(cx, |editor, cx| {
24516                                    let snapshot = editor.snapshot(window, cx);
24517                                    let position =
24518                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24519                                    editor.go_to_hunk_before_or_after_position(
24520                                        &snapshot,
24521                                        position,
24522                                        Direction::Next,
24523                                        window,
24524                                        cx,
24525                                    );
24526                                    editor.expand_selected_diff_hunks(cx);
24527                                });
24528                            }
24529                        }),
24530                )
24531                .child(
24532                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24533                        .shape(IconButtonShape::Square)
24534                        .icon_size(IconSize::Small)
24535                        // .disabled(!has_multiple_hunks)
24536                        .tooltip({
24537                            let focus_handle = editor.focus_handle(cx);
24538                            move |window, cx| {
24539                                Tooltip::for_action_in(
24540                                    "Previous Hunk",
24541                                    &GoToPreviousHunk,
24542                                    &focus_handle,
24543                                    window,
24544                                    cx,
24545                                )
24546                            }
24547                        })
24548                        .on_click({
24549                            let editor = editor.clone();
24550                            move |_event, window, cx| {
24551                                editor.update(cx, |editor, cx| {
24552                                    let snapshot = editor.snapshot(window, cx);
24553                                    let point =
24554                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24555                                    editor.go_to_hunk_before_or_after_position(
24556                                        &snapshot,
24557                                        point,
24558                                        Direction::Prev,
24559                                        window,
24560                                        cx,
24561                                    );
24562                                    editor.expand_selected_diff_hunks(cx);
24563                                });
24564                            }
24565                        }),
24566                )
24567            },
24568        )
24569        .into_any_element()
24570}
24571
24572pub fn multibuffer_context_lines(cx: &App) -> u32 {
24573    EditorSettings::try_get(cx)
24574        .map(|settings| settings.excerpt_context_lines)
24575        .unwrap_or(2)
24576        .min(32)
24577}