editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(usize),
  283    DebuggerValue(usize),
  284    // LSP
  285    Hint(usize),
  286    Color(usize),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> usize {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    HighlightStyle {
  596        color: Some(cx.theme().status().hint),
  597        background_color: show_background.then(|| cx.theme().status().hint_background),
  598        ..HighlightStyle::default()
  599    }
  600}
  601
  602pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, String)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    Move {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Range<Anchor>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn to_any(&self) -> &dyn std::any::Any;
  863
  864    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  865        None
  866    }
  867}
  868
  869struct ChangeLocation {
  870    current: Option<Vec<Anchor>>,
  871    original: Vec<Anchor>,
  872}
  873impl ChangeLocation {
  874    fn locations(&self) -> &[Anchor] {
  875        self.current.as_ref().unwrap_or(&self.original)
  876    }
  877}
  878
  879/// A set of caret positions, registered when the editor was edited.
  880pub struct ChangeList {
  881    changes: Vec<ChangeLocation>,
  882    /// Currently "selected" change.
  883    position: Option<usize>,
  884}
  885
  886impl ChangeList {
  887    pub fn new() -> Self {
  888        Self {
  889            changes: Vec::new(),
  890            position: None,
  891        }
  892    }
  893
  894    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  895    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  896    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  897        if self.changes.is_empty() {
  898            return None;
  899        }
  900
  901        let prev = self.position.unwrap_or(self.changes.len());
  902        let next = if direction == Direction::Prev {
  903            prev.saturating_sub(count)
  904        } else {
  905            (prev + count).min(self.changes.len() - 1)
  906        };
  907        self.position = Some(next);
  908        self.changes.get(next).map(|change| change.locations())
  909    }
  910
  911    /// Adds a new change to the list, resetting the change list position.
  912    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  913        self.position.take();
  914        if let Some(last) = self.changes.last_mut()
  915            && group
  916        {
  917            last.current = Some(new_positions)
  918        } else {
  919            self.changes.push(ChangeLocation {
  920                original: new_positions,
  921                current: None,
  922            });
  923        }
  924    }
  925
  926    pub fn last(&self) -> Option<&[Anchor]> {
  927        self.changes.last().map(|change| change.locations())
  928    }
  929
  930    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.original.as_slice())
  932    }
  933
  934    pub fn invert_last_group(&mut self) {
  935        if let Some(last) = self.changes.last_mut()
  936            && let Some(current) = last.current.as_mut()
  937        {
  938            mem::swap(&mut last.original, current);
  939        }
  940    }
  941}
  942
  943#[derive(Clone)]
  944struct InlineBlamePopoverState {
  945    scroll_handle: ScrollHandle,
  946    commit_message: Option<ParsedCommitMessage>,
  947    markdown: Entity<Markdown>,
  948}
  949
  950struct InlineBlamePopover {
  951    position: gpui::Point<Pixels>,
  952    hide_task: Option<Task<()>>,
  953    popover_bounds: Option<Bounds<Pixels>>,
  954    popover_state: InlineBlamePopoverState,
  955    keyboard_grace: bool,
  956}
  957
  958enum SelectionDragState {
  959    /// State when no drag related activity is detected.
  960    None,
  961    /// State when the mouse is down on a selection that is about to be dragged.
  962    ReadyToDrag {
  963        selection: Selection<Anchor>,
  964        click_position: gpui::Point<Pixels>,
  965        mouse_down_time: Instant,
  966    },
  967    /// State when the mouse is dragging the selection in the editor.
  968    Dragging {
  969        selection: Selection<Anchor>,
  970        drop_cursor: Selection<Anchor>,
  971        hide_drop_cursor: bool,
  972    },
  973}
  974
  975enum ColumnarSelectionState {
  976    FromMouse {
  977        selection_tail: Anchor,
  978        display_point: Option<DisplayPoint>,
  979    },
  980    FromSelection {
  981        selection_tail: Anchor,
  982    },
  983}
  984
  985/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  986/// a breakpoint on them.
  987#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  988struct PhantomBreakpointIndicator {
  989    display_row: DisplayRow,
  990    /// There's a small debounce between hovering over the line and showing the indicator.
  991    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  992    is_active: bool,
  993    collides_with_existing_breakpoint: bool,
  994}
  995
  996/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  997///
  998/// See the [module level documentation](self) for more information.
  999pub struct Editor {
 1000    focus_handle: FocusHandle,
 1001    last_focused_descendant: Option<WeakFocusHandle>,
 1002    /// The text buffer being edited
 1003    buffer: Entity<MultiBuffer>,
 1004    /// Map of how text in the buffer should be displayed.
 1005    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1006    pub display_map: Entity<DisplayMap>,
 1007    placeholder_display_map: Option<Entity<DisplayMap>>,
 1008    pub selections: SelectionsCollection,
 1009    pub scroll_manager: ScrollManager,
 1010    /// When inline assist editors are linked, they all render cursors because
 1011    /// typing enters text into each of them, even the ones that aren't focused.
 1012    pub(crate) show_cursor_when_unfocused: bool,
 1013    columnar_selection_state: Option<ColumnarSelectionState>,
 1014    add_selections_state: Option<AddSelectionsState>,
 1015    select_next_state: Option<SelectNextState>,
 1016    select_prev_state: Option<SelectNextState>,
 1017    selection_history: SelectionHistory,
 1018    defer_selection_effects: bool,
 1019    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1020    autoclose_regions: Vec<AutocloseRegion>,
 1021    snippet_stack: InvalidationStack<SnippetState>,
 1022    select_syntax_node_history: SelectSyntaxNodeHistory,
 1023    ime_transaction: Option<TransactionId>,
 1024    pub diagnostics_max_severity: DiagnosticSeverity,
 1025    active_diagnostics: ActiveDiagnostic,
 1026    show_inline_diagnostics: bool,
 1027    inline_diagnostics_update: Task<()>,
 1028    inline_diagnostics_enabled: bool,
 1029    diagnostics_enabled: bool,
 1030    word_completions_enabled: bool,
 1031    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1032    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1033    hard_wrap: Option<usize>,
 1034    project: Option<Entity<Project>>,
 1035    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1036    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1037    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1038    blink_manager: Entity<BlinkManager>,
 1039    show_cursor_names: bool,
 1040    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1041    pub show_local_selections: bool,
 1042    mode: EditorMode,
 1043    show_breadcrumbs: bool,
 1044    show_gutter: bool,
 1045    show_scrollbars: ScrollbarAxes,
 1046    minimap_visibility: MinimapVisibility,
 1047    offset_content: bool,
 1048    disable_expand_excerpt_buttons: bool,
 1049    show_line_numbers: Option<bool>,
 1050    use_relative_line_numbers: Option<bool>,
 1051    show_git_diff_gutter: Option<bool>,
 1052    show_code_actions: Option<bool>,
 1053    show_runnables: Option<bool>,
 1054    show_breakpoints: Option<bool>,
 1055    show_wrap_guides: Option<bool>,
 1056    show_indent_guides: Option<bool>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_edit_prediction: Option<EditPredictionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    edit_predictions_hidden_for_vim_mode: bool,
 1104    show_edit_predictions_override: Option<bool>,
 1105    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1178}
 1179
 1180#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1181enum NextScrollCursorCenterTopBottom {
 1182    #[default]
 1183    Center,
 1184    Top,
 1185    Bottom,
 1186}
 1187
 1188impl NextScrollCursorCenterTopBottom {
 1189    fn next(&self) -> Self {
 1190        match self {
 1191            Self::Center => Self::Top,
 1192            Self::Top => Self::Bottom,
 1193            Self::Bottom => Self::Center,
 1194        }
 1195    }
 1196}
 1197
 1198#[derive(Clone)]
 1199pub struct EditorSnapshot {
 1200    pub mode: EditorMode,
 1201    show_gutter: bool,
 1202    show_line_numbers: Option<bool>,
 1203    show_git_diff_gutter: Option<bool>,
 1204    show_code_actions: Option<bool>,
 1205    show_runnables: Option<bool>,
 1206    show_breakpoints: Option<bool>,
 1207    git_blame_gutter_max_author_length: Option<usize>,
 1208    pub display_snapshot: DisplaySnapshot,
 1209    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1210    is_focused: bool,
 1211    scroll_anchor: ScrollAnchor,
 1212    ongoing_scroll: OngoingScroll,
 1213    current_line_highlight: CurrentLineHighlight,
 1214    gutter_hovered: bool,
 1215}
 1216
 1217#[derive(Default, Debug, Clone, Copy)]
 1218pub struct GutterDimensions {
 1219    pub left_padding: Pixels,
 1220    pub right_padding: Pixels,
 1221    pub width: Pixels,
 1222    pub margin: Pixels,
 1223    pub git_blame_entries_width: Option<Pixels>,
 1224}
 1225
 1226impl GutterDimensions {
 1227    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1228        Self {
 1229            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1230            ..Default::default()
 1231        }
 1232    }
 1233
 1234    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1235        -cx.text_system().descent(font_id, font_size)
 1236    }
 1237    /// The full width of the space taken up by the gutter.
 1238    pub fn full_width(&self) -> Pixels {
 1239        self.margin + self.width
 1240    }
 1241
 1242    /// The width of the space reserved for the fold indicators,
 1243    /// use alongside 'justify_end' and `gutter_width` to
 1244    /// right align content with the line numbers
 1245    pub fn fold_area_width(&self) -> Pixels {
 1246        self.margin + self.right_padding
 1247    }
 1248}
 1249
 1250struct CharacterDimensions {
 1251    em_width: Pixels,
 1252    em_advance: Pixels,
 1253    line_height: Pixels,
 1254}
 1255
 1256#[derive(Debug)]
 1257pub struct RemoteSelection {
 1258    pub replica_id: ReplicaId,
 1259    pub selection: Selection<Anchor>,
 1260    pub cursor_shape: CursorShape,
 1261    pub collaborator_id: CollaboratorId,
 1262    pub line_mode: bool,
 1263    pub user_name: Option<SharedString>,
 1264    pub color: PlayerColor,
 1265}
 1266
 1267#[derive(Clone, Debug)]
 1268struct SelectionHistoryEntry {
 1269    selections: Arc<[Selection<Anchor>]>,
 1270    select_next_state: Option<SelectNextState>,
 1271    select_prev_state: Option<SelectNextState>,
 1272    add_selections_state: Option<AddSelectionsState>,
 1273}
 1274
 1275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1276enum SelectionHistoryMode {
 1277    Normal,
 1278    Undoing,
 1279    Redoing,
 1280    Skipping,
 1281}
 1282
 1283#[derive(Clone, PartialEq, Eq, Hash)]
 1284struct HoveredCursor {
 1285    replica_id: u16,
 1286    selection_id: usize,
 1287}
 1288
 1289impl Default for SelectionHistoryMode {
 1290    fn default() -> Self {
 1291        Self::Normal
 1292    }
 1293}
 1294
 1295#[derive(Debug)]
 1296/// SelectionEffects controls the side-effects of updating the selection.
 1297///
 1298/// The default behaviour does "what you mostly want":
 1299/// - it pushes to the nav history if the cursor moved by >10 lines
 1300/// - it re-triggers completion requests
 1301/// - it scrolls to fit
 1302///
 1303/// You might want to modify these behaviours. For example when doing a "jump"
 1304/// like go to definition, we always want to add to nav history; but when scrolling
 1305/// in vim mode we never do.
 1306///
 1307/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1308/// move.
 1309#[derive(Clone)]
 1310pub struct SelectionEffects {
 1311    nav_history: Option<bool>,
 1312    completions: bool,
 1313    scroll: Option<Autoscroll>,
 1314}
 1315
 1316impl Default for SelectionEffects {
 1317    fn default() -> Self {
 1318        Self {
 1319            nav_history: None,
 1320            completions: true,
 1321            scroll: Some(Autoscroll::fit()),
 1322        }
 1323    }
 1324}
 1325impl SelectionEffects {
 1326    pub fn scroll(scroll: Autoscroll) -> Self {
 1327        Self {
 1328            scroll: Some(scroll),
 1329            ..Default::default()
 1330        }
 1331    }
 1332
 1333    pub fn no_scroll() -> Self {
 1334        Self {
 1335            scroll: None,
 1336            ..Default::default()
 1337        }
 1338    }
 1339
 1340    pub fn completions(self, completions: bool) -> Self {
 1341        Self {
 1342            completions,
 1343            ..self
 1344        }
 1345    }
 1346
 1347    pub fn nav_history(self, nav_history: bool) -> Self {
 1348        Self {
 1349            nav_history: Some(nav_history),
 1350            ..self
 1351        }
 1352    }
 1353}
 1354
 1355struct DeferredSelectionEffectsState {
 1356    changed: bool,
 1357    effects: SelectionEffects,
 1358    old_cursor_position: Anchor,
 1359    history_entry: SelectionHistoryEntry,
 1360}
 1361
 1362#[derive(Default)]
 1363struct SelectionHistory {
 1364    #[allow(clippy::type_complexity)]
 1365    selections_by_transaction:
 1366        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1367    mode: SelectionHistoryMode,
 1368    undo_stack: VecDeque<SelectionHistoryEntry>,
 1369    redo_stack: VecDeque<SelectionHistoryEntry>,
 1370}
 1371
 1372impl SelectionHistory {
 1373    #[track_caller]
 1374    fn insert_transaction(
 1375        &mut self,
 1376        transaction_id: TransactionId,
 1377        selections: Arc<[Selection<Anchor>]>,
 1378    ) {
 1379        if selections.is_empty() {
 1380            log::error!(
 1381                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1382                std::panic::Location::caller()
 1383            );
 1384            return;
 1385        }
 1386        self.selections_by_transaction
 1387            .insert(transaction_id, (selections, None));
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction(
 1392        &self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get(&transaction_id)
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction_mut(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get_mut(&transaction_id)
 1404    }
 1405
 1406    fn push(&mut self, entry: SelectionHistoryEntry) {
 1407        if !entry.selections.is_empty() {
 1408            match self.mode {
 1409                SelectionHistoryMode::Normal => {
 1410                    self.push_undo(entry);
 1411                    self.redo_stack.clear();
 1412                }
 1413                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1414                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1415                SelectionHistoryMode::Skipping => {}
 1416            }
 1417        }
 1418    }
 1419
 1420    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1421        if self
 1422            .undo_stack
 1423            .back()
 1424            .is_none_or(|e| e.selections != entry.selections)
 1425        {
 1426            self.undo_stack.push_back(entry);
 1427            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1428                self.undo_stack.pop_front();
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .redo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.redo_stack.push_back(entry);
 1440            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.redo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445}
 1446
 1447#[derive(Clone, Copy)]
 1448pub struct RowHighlightOptions {
 1449    pub autoscroll: bool,
 1450    pub include_gutter: bool,
 1451}
 1452
 1453impl Default for RowHighlightOptions {
 1454    fn default() -> Self {
 1455        Self {
 1456            autoscroll: Default::default(),
 1457            include_gutter: true,
 1458        }
 1459    }
 1460}
 1461
 1462struct RowHighlight {
 1463    index: usize,
 1464    range: Range<Anchor>,
 1465    color: Hsla,
 1466    options: RowHighlightOptions,
 1467    type_id: TypeId,
 1468}
 1469
 1470#[derive(Clone, Debug)]
 1471struct AddSelectionsState {
 1472    groups: Vec<AddSelectionsGroup>,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsGroup {
 1477    above: bool,
 1478    stack: Vec<usize>,
 1479}
 1480
 1481#[derive(Clone)]
 1482struct SelectNextState {
 1483    query: AhoCorasick,
 1484    wordwise: bool,
 1485    done: bool,
 1486}
 1487
 1488impl std::fmt::Debug for SelectNextState {
 1489    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1490        f.debug_struct(std::any::type_name::<Self>())
 1491            .field("wordwise", &self.wordwise)
 1492            .field("done", &self.done)
 1493            .finish()
 1494    }
 1495}
 1496
 1497#[derive(Debug)]
 1498struct AutocloseRegion {
 1499    selection_id: usize,
 1500    range: Range<Anchor>,
 1501    pair: BracketPair,
 1502}
 1503
 1504#[derive(Debug)]
 1505struct SnippetState {
 1506    ranges: Vec<Vec<Range<Anchor>>>,
 1507    active_index: usize,
 1508    choices: Vec<Option<Vec<String>>>,
 1509}
 1510
 1511#[doc(hidden)]
 1512pub struct RenameState {
 1513    pub range: Range<Anchor>,
 1514    pub old_name: Arc<str>,
 1515    pub editor: Entity<Editor>,
 1516    block_id: CustomBlockId,
 1517}
 1518
 1519struct InvalidationStack<T>(Vec<T>);
 1520
 1521struct RegisteredEditPredictionProvider {
 1522    provider: Arc<dyn EditPredictionProviderHandle>,
 1523    _subscription: Subscription,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527pub struct ActiveDiagnosticGroup {
 1528    pub active_range: Range<Anchor>,
 1529    pub active_message: String,
 1530    pub group_id: usize,
 1531    pub blocks: HashSet<CustomBlockId>,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535
 1536pub(crate) enum ActiveDiagnostic {
 1537    None,
 1538    All,
 1539    Group(ActiveDiagnosticGroup),
 1540}
 1541
 1542#[derive(Serialize, Deserialize, Clone, Debug)]
 1543pub struct ClipboardSelection {
 1544    /// The number of bytes in this selection.
 1545    pub len: usize,
 1546    /// Whether this was a full-line selection.
 1547    pub is_entire_line: bool,
 1548    /// The indentation of the first line when this content was originally copied.
 1549    pub first_line_indent: u32,
 1550}
 1551
 1552// selections, scroll behavior, was newest selection reversed
 1553type SelectSyntaxNodeHistoryState = (
 1554    Box<[Selection<usize>]>,
 1555    SelectSyntaxNodeScrollBehavior,
 1556    bool,
 1557);
 1558
 1559#[derive(Default)]
 1560struct SelectSyntaxNodeHistory {
 1561    stack: Vec<SelectSyntaxNodeHistoryState>,
 1562    // disable temporarily to allow changing selections without losing the stack
 1563    pub disable_clearing: bool,
 1564}
 1565
 1566impl SelectSyntaxNodeHistory {
 1567    pub fn try_clear(&mut self) {
 1568        if !self.disable_clearing {
 1569            self.stack.clear();
 1570        }
 1571    }
 1572
 1573    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1574        self.stack.push(selection);
 1575    }
 1576
 1577    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1578        self.stack.pop()
 1579    }
 1580}
 1581
 1582enum SelectSyntaxNodeScrollBehavior {
 1583    CursorTop,
 1584    FitSelection,
 1585    CursorBottom,
 1586}
 1587
 1588#[derive(Debug)]
 1589pub(crate) struct NavigationData {
 1590    cursor_anchor: Anchor,
 1591    cursor_position: Point,
 1592    scroll_anchor: ScrollAnchor,
 1593    scroll_top_row: u32,
 1594}
 1595
 1596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1597pub enum GotoDefinitionKind {
 1598    Symbol,
 1599    Declaration,
 1600    Type,
 1601    Implementation,
 1602}
 1603
 1604#[derive(Debug, Clone)]
 1605enum InlayHintRefreshReason {
 1606    ModifiersChanged(bool),
 1607    Toggle(bool),
 1608    SettingsChange(InlayHintSettings),
 1609    NewLinesShown,
 1610    BufferEdited(HashSet<Arc<Language>>),
 1611    RefreshRequested,
 1612    ExcerptsRemoved(Vec<ExcerptId>),
 1613}
 1614
 1615impl InlayHintRefreshReason {
 1616    fn description(&self) -> &'static str {
 1617        match self {
 1618            Self::ModifiersChanged(_) => "modifiers changed",
 1619            Self::Toggle(_) => "toggle",
 1620            Self::SettingsChange(_) => "settings change",
 1621            Self::NewLinesShown => "new lines shown",
 1622            Self::BufferEdited(_) => "buffer edited",
 1623            Self::RefreshRequested => "refresh requested",
 1624            Self::ExcerptsRemoved(_) => "excerpts removed",
 1625        }
 1626    }
 1627}
 1628
 1629pub enum FormatTarget {
 1630    Buffers(HashSet<Entity<Buffer>>),
 1631    Ranges(Vec<Range<MultiBufferPoint>>),
 1632}
 1633
 1634pub(crate) struct FocusedBlock {
 1635    id: BlockId,
 1636    focus_handle: WeakFocusHandle,
 1637}
 1638
 1639#[derive(Clone)]
 1640enum JumpData {
 1641    MultiBufferRow {
 1642        row: MultiBufferRow,
 1643        line_offset_from_top: u32,
 1644    },
 1645    MultiBufferPoint {
 1646        excerpt_id: ExcerptId,
 1647        position: Point,
 1648        anchor: text::Anchor,
 1649        line_offset_from_top: u32,
 1650    },
 1651}
 1652
 1653pub enum MultibufferSelectionMode {
 1654    First,
 1655    All,
 1656}
 1657
 1658#[derive(Clone, Copy, Debug, Default)]
 1659pub struct RewrapOptions {
 1660    pub override_language_settings: bool,
 1661    pub preserve_existing_whitespace: bool,
 1662}
 1663
 1664impl Editor {
 1665    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1666        let buffer = cx.new(|cx| Buffer::local("", cx));
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1669    }
 1670
 1671    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1672        let buffer = cx.new(|cx| Buffer::local("", cx));
 1673        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::full(), buffer, None, window, cx)
 1675    }
 1676
 1677    pub fn auto_height(
 1678        min_lines: usize,
 1679        max_lines: usize,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(
 1686            EditorMode::AutoHeight {
 1687                min_lines,
 1688                max_lines: Some(max_lines),
 1689            },
 1690            buffer,
 1691            None,
 1692            window,
 1693            cx,
 1694        )
 1695    }
 1696
 1697    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1698    /// The editor grows as tall as needed to fit its content.
 1699    pub fn auto_height_unbounded(
 1700        min_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: None,
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    pub fn for_buffer(
 1719        buffer: Entity<Buffer>,
 1720        project: Option<Entity<Project>>,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(EditorMode::full(), buffer, project, window, cx)
 1726    }
 1727
 1728    pub fn for_multibuffer(
 1729        buffer: Entity<MultiBuffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        Self::new(EditorMode::full(), buffer, project, window, cx)
 1735    }
 1736
 1737    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let mut clone = Self::new(
 1739            self.mode.clone(),
 1740            self.buffer.clone(),
 1741            self.project.clone(),
 1742            window,
 1743            cx,
 1744        );
 1745        self.display_map.update(cx, |display_map, cx| {
 1746            let snapshot = display_map.snapshot(cx);
 1747            clone.display_map.update(cx, |display_map, cx| {
 1748                display_map.set_state(&snapshot, cx);
 1749            });
 1750        });
 1751        clone.folds_did_change(cx);
 1752        clone.selections.clone_state(&self.selections);
 1753        clone.scroll_manager.clone_state(&self.scroll_manager);
 1754        clone.searchable = self.searchable;
 1755        clone.read_only = self.read_only;
 1756        clone
 1757    }
 1758
 1759    pub fn new(
 1760        mode: EditorMode,
 1761        buffer: Entity<MultiBuffer>,
 1762        project: Option<Entity<Project>>,
 1763        window: &mut Window,
 1764        cx: &mut Context<Self>,
 1765    ) -> Self {
 1766        Editor::new_internal(mode, buffer, project, None, window, cx)
 1767    }
 1768
 1769    fn new_internal(
 1770        mode: EditorMode,
 1771        buffer: Entity<MultiBuffer>,
 1772        project: Option<Entity<Project>>,
 1773        display_map: Option<Entity<DisplayMap>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        debug_assert!(
 1778            display_map.is_none() || mode.is_minimap(),
 1779            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1780        );
 1781
 1782        let full_mode = mode.is_full();
 1783        let is_minimap = mode.is_minimap();
 1784        let diagnostics_max_severity = if full_mode {
 1785            EditorSettings::get_global(cx)
 1786                .diagnostics_max_severity
 1787                .unwrap_or(DiagnosticSeverity::Hint)
 1788        } else {
 1789            DiagnosticSeverity::Off
 1790        };
 1791        let style = window.text_style();
 1792        let font_size = style.font_size.to_pixels(window.rem_size());
 1793        let editor = cx.entity().downgrade();
 1794        let fold_placeholder = FoldPlaceholder {
 1795            constrain_width: false,
 1796            render: Arc::new(move |fold_id, fold_range, cx| {
 1797                let editor = editor.clone();
 1798                div()
 1799                    .id(fold_id)
 1800                    .bg(cx.theme().colors().ghost_element_background)
 1801                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1802                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1803                    .rounded_xs()
 1804                    .size_full()
 1805                    .cursor_pointer()
 1806                    .child("")
 1807                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1808                    .on_click(move |_, _window, cx| {
 1809                        editor
 1810                            .update(cx, |editor, cx| {
 1811                                editor.unfold_ranges(
 1812                                    &[fold_range.start..fold_range.end],
 1813                                    true,
 1814                                    false,
 1815                                    cx,
 1816                                );
 1817                                cx.stop_propagation();
 1818                            })
 1819                            .ok();
 1820                    })
 1821                    .into_any()
 1822            }),
 1823            merge_adjacent: true,
 1824            ..FoldPlaceholder::default()
 1825        };
 1826        let display_map = display_map.unwrap_or_else(|| {
 1827            cx.new(|cx| {
 1828                DisplayMap::new(
 1829                    buffer.clone(),
 1830                    style.font(),
 1831                    font_size,
 1832                    None,
 1833                    FILE_HEADER_HEIGHT,
 1834                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1835                    fold_placeholder,
 1836                    diagnostics_max_severity,
 1837                    cx,
 1838                )
 1839            })
 1840        });
 1841
 1842        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1843
 1844        let blink_manager = cx.new(|cx| {
 1845            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1846            if is_minimap {
 1847                blink_manager.disable(cx);
 1848            }
 1849            blink_manager
 1850        });
 1851
 1852        let soft_wrap_mode_override =
 1853            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1854
 1855        let mut project_subscriptions = Vec::new();
 1856        if full_mode && let Some(project) = project.as_ref() {
 1857            project_subscriptions.push(cx.subscribe_in(
 1858                project,
 1859                window,
 1860                |editor, _, event, window, cx| match event {
 1861                    project::Event::RefreshCodeLens => {
 1862                        // we always query lens with actions, without storing them, always refreshing them
 1863                    }
 1864                    project::Event::RefreshInlayHints => {
 1865                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                    }
 1867                    project::Event::LanguageServerAdded(..)
 1868                    | project::Event::LanguageServerRemoved(..) => {
 1869                        if editor.tasks_update_task.is_none() {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        }
 1872                    }
 1873                    project::Event::SnippetEdit(id, snippet_edits) => {
 1874                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1875                            let focus_handle = editor.focus_handle(cx);
 1876                            if focus_handle.is_focused(window) {
 1877                                let snapshot = buffer.read(cx).snapshot();
 1878                                for (range, snippet) in snippet_edits {
 1879                                    let editor_range =
 1880                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1881                                    editor
 1882                                        .insert_snippet(
 1883                                            &[editor_range],
 1884                                            snippet.clone(),
 1885                                            window,
 1886                                            cx,
 1887                                        )
 1888                                        .ok();
 1889                                }
 1890                            }
 1891                        }
 1892                    }
 1893                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1894                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1895                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1896                        }
 1897                    }
 1898
 1899                    project::Event::EntryRenamed(transaction) => {
 1900                        let Some(workspace) = editor.workspace() else {
 1901                            return;
 1902                        };
 1903                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1904                        else {
 1905                            return;
 1906                        };
 1907                        if active_editor.entity_id() == cx.entity_id() {
 1908                            let edited_buffers_already_open = {
 1909                                let other_editors: Vec<Entity<Editor>> = workspace
 1910                                    .read(cx)
 1911                                    .panes()
 1912                                    .iter()
 1913                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1914                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1915                                    .collect();
 1916
 1917                                transaction.0.keys().all(|buffer| {
 1918                                    other_editors.iter().any(|editor| {
 1919                                        let multi_buffer = editor.read(cx).buffer();
 1920                                        multi_buffer.read(cx).is_singleton()
 1921                                            && multi_buffer.read(cx).as_singleton().map_or(
 1922                                                false,
 1923                                                |singleton| {
 1924                                                    singleton.entity_id() == buffer.entity_id()
 1925                                                },
 1926                                            )
 1927                                    })
 1928                                })
 1929                            };
 1930
 1931                            if !edited_buffers_already_open {
 1932                                let workspace = workspace.downgrade();
 1933                                let transaction = transaction.clone();
 1934                                cx.defer_in(window, move |_, window, cx| {
 1935                                    cx.spawn_in(window, async move |editor, cx| {
 1936                                        Self::open_project_transaction(
 1937                                            &editor,
 1938                                            workspace,
 1939                                            transaction,
 1940                                            "Rename".to_string(),
 1941                                            cx,
 1942                                        )
 1943                                        .await
 1944                                        .ok()
 1945                                    })
 1946                                    .detach();
 1947                                });
 1948                            }
 1949                        }
 1950                    }
 1951
 1952                    _ => {}
 1953                },
 1954            ));
 1955            if let Some(task_inventory) = project
 1956                .read(cx)
 1957                .task_store()
 1958                .read(cx)
 1959                .task_inventory()
 1960                .cloned()
 1961            {
 1962                project_subscriptions.push(cx.observe_in(
 1963                    &task_inventory,
 1964                    window,
 1965                    |editor, _, window, cx| {
 1966                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1967                    },
 1968                ));
 1969            };
 1970
 1971            project_subscriptions.push(cx.subscribe_in(
 1972                &project.read(cx).breakpoint_store(),
 1973                window,
 1974                |editor, _, event, window, cx| match event {
 1975                    BreakpointStoreEvent::ClearDebugLines => {
 1976                        editor.clear_row_highlights::<ActiveDebugLine>();
 1977                        editor.refresh_inline_values(cx);
 1978                    }
 1979                    BreakpointStoreEvent::SetDebugLine => {
 1980                        if editor.go_to_active_debug_line(window, cx) {
 1981                            cx.stop_propagation();
 1982                        }
 1983
 1984                        editor.refresh_inline_values(cx);
 1985                    }
 1986                    _ => {}
 1987                },
 1988            ));
 1989            let git_store = project.read(cx).git_store().clone();
 1990            let project = project.clone();
 1991            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1992                if let GitStoreEvent::RepositoryUpdated(
 1993                    _,
 1994                    RepositoryEvent::Updated {
 1995                        new_instance: true, ..
 1996                    },
 1997                    _,
 1998                ) = event
 1999                {
 2000                    this.load_diff_task = Some(
 2001                        update_uncommitted_diff_for_buffer(
 2002                            cx.entity(),
 2003                            &project,
 2004                            this.buffer.read(cx).all_buffers(),
 2005                            this.buffer.clone(),
 2006                            cx,
 2007                        )
 2008                        .shared(),
 2009                    );
 2010                }
 2011            }));
 2012        }
 2013
 2014        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2015
 2016        let inlay_hint_settings =
 2017            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2018        let focus_handle = cx.focus_handle();
 2019        if !is_minimap {
 2020            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2021                .detach();
 2022            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2023                .detach();
 2024            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2025                .detach();
 2026            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2027                .detach();
 2028            cx.observe_pending_input(window, Self::observe_pending_input)
 2029                .detach();
 2030        }
 2031
 2032        let show_indent_guides =
 2033            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2034                Some(false)
 2035            } else {
 2036                None
 2037            };
 2038
 2039        let breakpoint_store = match (&mode, project.as_ref()) {
 2040            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2041            _ => None,
 2042        };
 2043
 2044        let mut code_action_providers = Vec::new();
 2045        let mut load_uncommitted_diff = None;
 2046        if let Some(project) = project.clone() {
 2047            load_uncommitted_diff = Some(
 2048                update_uncommitted_diff_for_buffer(
 2049                    cx.entity(),
 2050                    &project,
 2051                    buffer.read(cx).all_buffers(),
 2052                    buffer.clone(),
 2053                    cx,
 2054                )
 2055                .shared(),
 2056            );
 2057            code_action_providers.push(Rc::new(project) as Rc<_>);
 2058        }
 2059
 2060        let mut editor = Self {
 2061            focus_handle,
 2062            show_cursor_when_unfocused: false,
 2063            last_focused_descendant: None,
 2064            buffer: buffer.clone(),
 2065            display_map: display_map.clone(),
 2066            placeholder_display_map: None,
 2067            selections,
 2068            scroll_manager: ScrollManager::new(cx),
 2069            columnar_selection_state: None,
 2070            add_selections_state: None,
 2071            select_next_state: None,
 2072            select_prev_state: None,
 2073            selection_history: SelectionHistory::default(),
 2074            defer_selection_effects: false,
 2075            deferred_selection_effects_state: None,
 2076            autoclose_regions: Vec::new(),
 2077            snippet_stack: InvalidationStack::default(),
 2078            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2079            ime_transaction: None,
 2080            active_diagnostics: ActiveDiagnostic::None,
 2081            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2082            inline_diagnostics_update: Task::ready(()),
 2083            inline_diagnostics: Vec::new(),
 2084            soft_wrap_mode_override,
 2085            diagnostics_max_severity,
 2086            hard_wrap: None,
 2087            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2088            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2089            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2090            project,
 2091            blink_manager: blink_manager.clone(),
 2092            show_local_selections: true,
 2093            show_scrollbars: ScrollbarAxes {
 2094                horizontal: full_mode,
 2095                vertical: full_mode,
 2096            },
 2097            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2098            offset_content: !matches!(mode, EditorMode::SingleLine),
 2099            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2100            show_gutter: full_mode,
 2101            show_line_numbers: (!full_mode).then_some(false),
 2102            use_relative_line_numbers: None,
 2103            disable_expand_excerpt_buttons: !full_mode,
 2104            show_git_diff_gutter: None,
 2105            show_code_actions: None,
 2106            show_runnables: None,
 2107            show_breakpoints: None,
 2108            show_wrap_guides: None,
 2109            show_indent_guides,
 2110            highlight_order: 0,
 2111            highlighted_rows: HashMap::default(),
 2112            background_highlights: HashMap::default(),
 2113            gutter_highlights: HashMap::default(),
 2114            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2115            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2116            nav_history: None,
 2117            context_menu: RefCell::new(None),
 2118            context_menu_options: None,
 2119            mouse_context_menu: None,
 2120            completion_tasks: Vec::new(),
 2121            inline_blame_popover: None,
 2122            inline_blame_popover_show_task: None,
 2123            signature_help_state: SignatureHelpState::default(),
 2124            auto_signature_help: None,
 2125            find_all_references_task_sources: Vec::new(),
 2126            next_completion_id: 0,
 2127            next_inlay_id: 0,
 2128            code_action_providers,
 2129            available_code_actions: None,
 2130            code_actions_task: None,
 2131            quick_selection_highlight_task: None,
 2132            debounced_selection_highlight_task: None,
 2133            document_highlights_task: None,
 2134            linked_editing_range_task: None,
 2135            pending_rename: None,
 2136            searchable: !is_minimap,
 2137            cursor_shape: EditorSettings::get_global(cx)
 2138                .cursor_shape
 2139                .unwrap_or_default(),
 2140            current_line_highlight: None,
 2141            autoindent_mode: Some(AutoindentMode::EachLine),
 2142            collapse_matches: false,
 2143            workspace: None,
 2144            input_enabled: !is_minimap,
 2145            use_modal_editing: full_mode,
 2146            read_only: is_minimap,
 2147            use_autoclose: true,
 2148            use_auto_surround: true,
 2149            auto_replace_emoji_shortcode: false,
 2150            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2151            leader_id: None,
 2152            remote_id: None,
 2153            hover_state: HoverState::default(),
 2154            pending_mouse_down: None,
 2155            hovered_link_state: None,
 2156            edit_prediction_provider: None,
 2157            active_edit_prediction: None,
 2158            stale_edit_prediction_in_menu: None,
 2159            edit_prediction_preview: EditPredictionPreview::Inactive {
 2160                released_too_fast: false,
 2161            },
 2162            inline_diagnostics_enabled: full_mode,
 2163            diagnostics_enabled: full_mode,
 2164            word_completions_enabled: full_mode,
 2165            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2166            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2167            gutter_hovered: false,
 2168            pixel_position_of_newest_cursor: None,
 2169            last_bounds: None,
 2170            last_position_map: None,
 2171            expect_bounds_change: None,
 2172            gutter_dimensions: GutterDimensions::default(),
 2173            style: None,
 2174            show_cursor_names: false,
 2175            hovered_cursors: HashMap::default(),
 2176            next_editor_action_id: EditorActionId::default(),
 2177            editor_actions: Rc::default(),
 2178            edit_predictions_hidden_for_vim_mode: false,
 2179            show_edit_predictions_override: None,
 2180            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2181            edit_prediction_settings: EditPredictionSettings::Disabled,
 2182            edit_prediction_indent_conflict: false,
 2183            edit_prediction_requires_modifier_in_indent_conflict: true,
 2184            custom_context_menu: None,
 2185            show_git_blame_gutter: false,
 2186            show_git_blame_inline: false,
 2187            show_selection_menu: None,
 2188            show_git_blame_inline_delay_task: None,
 2189            git_blame_inline_enabled: full_mode
 2190                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2191            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2192            serialize_dirty_buffers: !is_minimap
 2193                && ProjectSettings::get_global(cx)
 2194                    .session
 2195                    .restore_unsaved_buffers,
 2196            blame: None,
 2197            blame_subscription: None,
 2198            tasks: BTreeMap::default(),
 2199
 2200            breakpoint_store,
 2201            gutter_breakpoint_indicator: (None, None),
 2202            hovered_diff_hunk_row: None,
 2203            _subscriptions: (!is_minimap)
 2204                .then(|| {
 2205                    vec![
 2206                        cx.observe(&buffer, Self::on_buffer_changed),
 2207                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2208                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2209                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2210                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2211                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2212                        cx.observe_window_activation(window, |editor, window, cx| {
 2213                            let active = window.is_window_active();
 2214                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2215                                if active {
 2216                                    blink_manager.enable(cx);
 2217                                } else {
 2218                                    blink_manager.disable(cx);
 2219                                }
 2220                            });
 2221                            if active {
 2222                                editor.show_mouse_cursor(cx);
 2223                            }
 2224                        }),
 2225                    ]
 2226                })
 2227                .unwrap_or_default(),
 2228            tasks_update_task: None,
 2229            pull_diagnostics_task: Task::ready(()),
 2230            colors: None,
 2231            next_color_inlay_id: 0,
 2232            linked_edit_ranges: Default::default(),
 2233            in_project_search: false,
 2234            previous_search_ranges: None,
 2235            breadcrumb_header: None,
 2236            focused_block: None,
 2237            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2238            addons: HashMap::default(),
 2239            registered_buffers: HashMap::default(),
 2240            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2241            selection_mark_mode: false,
 2242            toggle_fold_multiple_buffers: Task::ready(()),
 2243            serialize_selections: Task::ready(()),
 2244            serialize_folds: Task::ready(()),
 2245            text_style_refinement: None,
 2246            load_diff_task: load_uncommitted_diff,
 2247            temporary_diff_override: false,
 2248            mouse_cursor_hidden: false,
 2249            minimap: None,
 2250            hide_mouse_mode: EditorSettings::get_global(cx)
 2251                .hide_mouse
 2252                .unwrap_or_default(),
 2253            change_list: ChangeList::new(),
 2254            mode,
 2255            selection_drag_state: SelectionDragState::None,
 2256            folding_newlines: Task::ready(()),
 2257            lookup_key: None,
 2258        };
 2259
 2260        if is_minimap {
 2261            return editor;
 2262        }
 2263
 2264        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2265            editor
 2266                ._subscriptions
 2267                .push(cx.observe(breakpoints, |_, _, cx| {
 2268                    cx.notify();
 2269                }));
 2270        }
 2271        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2272        editor._subscriptions.extend(project_subscriptions);
 2273
 2274        editor._subscriptions.push(cx.subscribe_in(
 2275            &cx.entity(),
 2276            window,
 2277            |editor, _, e: &EditorEvent, window, cx| match e {
 2278                EditorEvent::ScrollPositionChanged { local, .. } => {
 2279                    if *local {
 2280                        let new_anchor = editor.scroll_manager.anchor();
 2281                        let snapshot = editor.snapshot(window, cx);
 2282                        editor.update_restoration_data(cx, move |data| {
 2283                            data.scroll_position = (
 2284                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2285                                new_anchor.offset,
 2286                            );
 2287                        });
 2288                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2289                        editor.inline_blame_popover.take();
 2290                    }
 2291                }
 2292                EditorEvent::Edited { .. } => {
 2293                    if !vim_enabled(cx) {
 2294                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2295                        let pop_state = editor
 2296                            .change_list
 2297                            .last()
 2298                            .map(|previous| {
 2299                                previous.len() == selections.len()
 2300                                    && previous.iter().enumerate().all(|(ix, p)| {
 2301                                        p.to_display_point(&map).row()
 2302                                            == selections[ix].head().row()
 2303                                    })
 2304                            })
 2305                            .unwrap_or(false);
 2306                        let new_positions = selections
 2307                            .into_iter()
 2308                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2309                            .collect();
 2310                        editor
 2311                            .change_list
 2312                            .push_to_change_list(pop_state, new_positions);
 2313                    }
 2314                }
 2315                _ => (),
 2316            },
 2317        ));
 2318
 2319        if let Some(dap_store) = editor
 2320            .project
 2321            .as_ref()
 2322            .map(|project| project.read(cx).dap_store())
 2323        {
 2324            let weak_editor = cx.weak_entity();
 2325
 2326            editor
 2327                ._subscriptions
 2328                .push(
 2329                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2330                        let session_entity = cx.entity();
 2331                        weak_editor
 2332                            .update(cx, |editor, cx| {
 2333                                editor._subscriptions.push(
 2334                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2335                                );
 2336                            })
 2337                            .ok();
 2338                    }),
 2339                );
 2340
 2341            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2342                editor
 2343                    ._subscriptions
 2344                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2345            }
 2346        }
 2347
 2348        // skip adding the initial selection to selection history
 2349        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2350        editor.end_selection(window, cx);
 2351        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2352
 2353        editor.scroll_manager.show_scrollbars(window, cx);
 2354        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2355
 2356        if full_mode {
 2357            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2358            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2359
 2360            if editor.git_blame_inline_enabled {
 2361                editor.start_git_blame_inline(false, window, cx);
 2362            }
 2363
 2364            editor.go_to_active_debug_line(window, cx);
 2365
 2366            if let Some(buffer) = buffer.read(cx).as_singleton()
 2367                && let Some(project) = editor.project()
 2368            {
 2369                let handle = project.update(cx, |project, cx| {
 2370                    project.register_buffer_with_language_servers(&buffer, cx)
 2371                });
 2372                editor
 2373                    .registered_buffers
 2374                    .insert(buffer.read(cx).remote_id(), handle);
 2375            }
 2376
 2377            editor.minimap =
 2378                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2379            editor.colors = Some(LspColorData::new(cx));
 2380            editor.update_lsp_data(false, None, window, cx);
 2381        }
 2382
 2383        if editor.mode.is_full() {
 2384            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2385        }
 2386
 2387        editor
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending_anchor()
 2416            .is_some_and(|pending_selection| {
 2417                let snapshot = self.buffer().read(cx).snapshot(cx);
 2418                pending_selection.range().includes(range, &snapshot)
 2419            })
 2420        {
 2421            return true;
 2422        }
 2423
 2424        self.selections
 2425            .disjoint_in_range::<usize>(range.clone(), cx)
 2426            .into_iter()
 2427            .any(|selection| {
 2428                // This is needed to cover a corner case, if we just check for an existing
 2429                // selection in the fold range, having a cursor at the start of the fold
 2430                // marks it as selected. Non-empty selections don't cause this.
 2431                let length = selection.end - selection.start;
 2432                length > 0
 2433            })
 2434    }
 2435
 2436    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2437        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2438    }
 2439
 2440    fn key_context_internal(
 2441        &self,
 2442        has_active_edit_prediction: bool,
 2443        window: &Window,
 2444        cx: &App,
 2445    ) -> KeyContext {
 2446        let mut key_context = KeyContext::new_with_defaults();
 2447        key_context.add("Editor");
 2448        let mode = match self.mode {
 2449            EditorMode::SingleLine => "single_line",
 2450            EditorMode::AutoHeight { .. } => "auto_height",
 2451            EditorMode::Minimap { .. } => "minimap",
 2452            EditorMode::Full { .. } => "full",
 2453        };
 2454
 2455        if EditorSettings::jupyter_enabled(cx) {
 2456            key_context.add("jupyter");
 2457        }
 2458
 2459        key_context.set("mode", mode);
 2460        if self.pending_rename.is_some() {
 2461            key_context.add("renaming");
 2462        }
 2463
 2464        match self.context_menu.borrow().as_ref() {
 2465            Some(CodeContextMenu::Completions(menu)) => {
 2466                if menu.visible() {
 2467                    key_context.add("menu");
 2468                    key_context.add("showing_completions");
 2469                }
 2470            }
 2471            Some(CodeContextMenu::CodeActions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_code_actions")
 2475                }
 2476            }
 2477            None => {}
 2478        }
 2479
 2480        if self.signature_help_state.has_multiple_signatures() {
 2481            key_context.add("showing_signature_help");
 2482        }
 2483
 2484        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2485        if !self.focus_handle(cx).contains_focused(window, cx)
 2486            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2487        {
 2488            for addon in self.addons.values() {
 2489                addon.extend_key_context(&mut key_context, cx)
 2490            }
 2491        }
 2492
 2493        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2494            if let Some(extension) = singleton_buffer
 2495                .read(cx)
 2496                .file()
 2497                .and_then(|file| file.path().extension()?.to_str())
 2498            {
 2499                key_context.set("extension", extension.to_string());
 2500            }
 2501        } else {
 2502            key_context.add("multibuffer");
 2503        }
 2504
 2505        if has_active_edit_prediction {
 2506            if self.edit_prediction_in_conflict() {
 2507                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2508            } else {
 2509                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2510                key_context.add("copilot_suggestion");
 2511            }
 2512        }
 2513
 2514        if self.selection_mark_mode {
 2515            key_context.add("selection_mode");
 2516        }
 2517
 2518        key_context
 2519    }
 2520
 2521    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2522        self.last_bounds.as_ref()
 2523    }
 2524
 2525    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2526        if self.mouse_cursor_hidden {
 2527            self.mouse_cursor_hidden = false;
 2528            cx.notify();
 2529        }
 2530    }
 2531
 2532    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2533        let hide_mouse_cursor = match origin {
 2534            HideMouseCursorOrigin::TypingAction => {
 2535                matches!(
 2536                    self.hide_mouse_mode,
 2537                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2538                )
 2539            }
 2540            HideMouseCursorOrigin::MovementAction => {
 2541                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2542            }
 2543        };
 2544        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2545            self.mouse_cursor_hidden = hide_mouse_cursor;
 2546            cx.notify();
 2547        }
 2548    }
 2549
 2550    pub fn edit_prediction_in_conflict(&self) -> bool {
 2551        if !self.show_edit_predictions_in_menu() {
 2552            return false;
 2553        }
 2554
 2555        let showing_completions = self
 2556            .context_menu
 2557            .borrow()
 2558            .as_ref()
 2559            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2560
 2561        showing_completions
 2562            || self.edit_prediction_requires_modifier()
 2563            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2564            // bindings to insert tab characters.
 2565            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2566    }
 2567
 2568    pub fn accept_edit_prediction_keybind(
 2569        &self,
 2570        accept_partial: bool,
 2571        window: &Window,
 2572        cx: &App,
 2573    ) -> AcceptEditPredictionBinding {
 2574        let key_context = self.key_context_internal(true, window, cx);
 2575        let in_conflict = self.edit_prediction_in_conflict();
 2576
 2577        let bindings = if accept_partial {
 2578            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2579        } else {
 2580            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2581        };
 2582
 2583        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2584        // just the first one.
 2585        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2586            !in_conflict
 2587                || binding
 2588                    .keystrokes()
 2589                    .first()
 2590                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2591        }))
 2592    }
 2593
 2594    pub fn new_file(
 2595        workspace: &mut Workspace,
 2596        _: &workspace::NewFile,
 2597        window: &mut Window,
 2598        cx: &mut Context<Workspace>,
 2599    ) {
 2600        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2601            "Failed to create buffer",
 2602            window,
 2603            cx,
 2604            |e, _, _| match e.error_code() {
 2605                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2606                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2607                e.error_tag("required").unwrap_or("the latest version")
 2608            )),
 2609                _ => None,
 2610            },
 2611        );
 2612    }
 2613
 2614    pub fn new_in_workspace(
 2615        workspace: &mut Workspace,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) -> Task<Result<Entity<Editor>>> {
 2619        let project = workspace.project().clone();
 2620        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2621
 2622        cx.spawn_in(window, async move |workspace, cx| {
 2623            let buffer = create.await?;
 2624            workspace.update_in(cx, |workspace, window, cx| {
 2625                let editor =
 2626                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2627                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2628                editor
 2629            })
 2630        })
 2631    }
 2632
 2633    fn new_file_vertical(
 2634        workspace: &mut Workspace,
 2635        _: &workspace::NewFileSplitVertical,
 2636        window: &mut Window,
 2637        cx: &mut Context<Workspace>,
 2638    ) {
 2639        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2640    }
 2641
 2642    fn new_file_horizontal(
 2643        workspace: &mut Workspace,
 2644        _: &workspace::NewFileSplitHorizontal,
 2645        window: &mut Window,
 2646        cx: &mut Context<Workspace>,
 2647    ) {
 2648        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2649    }
 2650
 2651    fn new_file_in_direction(
 2652        workspace: &mut Workspace,
 2653        direction: SplitDirection,
 2654        window: &mut Window,
 2655        cx: &mut Context<Workspace>,
 2656    ) {
 2657        let project = workspace.project().clone();
 2658        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2659
 2660        cx.spawn_in(window, async move |workspace, cx| {
 2661            let buffer = create.await?;
 2662            workspace.update_in(cx, move |workspace, window, cx| {
 2663                workspace.split_item(
 2664                    direction,
 2665                    Box::new(
 2666                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2667                    ),
 2668                    window,
 2669                    cx,
 2670                )
 2671            })?;
 2672            anyhow::Ok(())
 2673        })
 2674        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2675            match e.error_code() {
 2676                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2677                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2678                e.error_tag("required").unwrap_or("the latest version")
 2679            )),
 2680                _ => None,
 2681            }
 2682        });
 2683    }
 2684
 2685    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2686        self.leader_id
 2687    }
 2688
 2689    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2690        &self.buffer
 2691    }
 2692
 2693    pub fn project(&self) -> Option<&Entity<Project>> {
 2694        self.project.as_ref()
 2695    }
 2696
 2697    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2698        self.workspace.as_ref()?.0.upgrade()
 2699    }
 2700
 2701    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2702        self.buffer().read(cx).title(cx)
 2703    }
 2704
 2705    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2706        let git_blame_gutter_max_author_length = self
 2707            .render_git_blame_gutter(cx)
 2708            .then(|| {
 2709                if let Some(blame) = self.blame.as_ref() {
 2710                    let max_author_length =
 2711                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2712                    Some(max_author_length)
 2713                } else {
 2714                    None
 2715                }
 2716            })
 2717            .flatten();
 2718
 2719        EditorSnapshot {
 2720            mode: self.mode.clone(),
 2721            show_gutter: self.show_gutter,
 2722            show_line_numbers: self.show_line_numbers,
 2723            show_git_diff_gutter: self.show_git_diff_gutter,
 2724            show_code_actions: self.show_code_actions,
 2725            show_runnables: self.show_runnables,
 2726            show_breakpoints: self.show_breakpoints,
 2727            git_blame_gutter_max_author_length,
 2728            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2729            placeholder_display_snapshot: self
 2730                .placeholder_display_map
 2731                .as_ref()
 2732                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2733            scroll_anchor: self.scroll_manager.anchor(),
 2734            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2735            is_focused: self.focus_handle.is_focused(window),
 2736            current_line_highlight: self
 2737                .current_line_highlight
 2738                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2739            gutter_hovered: self.gutter_hovered,
 2740        }
 2741    }
 2742
 2743    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2744        self.buffer.read(cx).language_at(point, cx)
 2745    }
 2746
 2747    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2748        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2749    }
 2750
 2751    pub fn active_excerpt(
 2752        &self,
 2753        cx: &App,
 2754    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2755        self.buffer
 2756            .read(cx)
 2757            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2758    }
 2759
 2760    pub fn mode(&self) -> &EditorMode {
 2761        &self.mode
 2762    }
 2763
 2764    pub fn set_mode(&mut self, mode: EditorMode) {
 2765        self.mode = mode;
 2766    }
 2767
 2768    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2769        self.collaboration_hub.as_deref()
 2770    }
 2771
 2772    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2773        self.collaboration_hub = Some(hub);
 2774    }
 2775
 2776    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2777        self.in_project_search = in_project_search;
 2778    }
 2779
 2780    pub fn set_custom_context_menu(
 2781        &mut self,
 2782        f: impl 'static
 2783        + Fn(
 2784            &mut Self,
 2785            DisplayPoint,
 2786            &mut Window,
 2787            &mut Context<Self>,
 2788        ) -> Option<Entity<ui::ContextMenu>>,
 2789    ) {
 2790        self.custom_context_menu = Some(Box::new(f))
 2791    }
 2792
 2793    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2794        self.completion_provider = provider;
 2795    }
 2796
 2797    #[cfg(any(test, feature = "test-support"))]
 2798    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2799        self.completion_provider.clone()
 2800    }
 2801
 2802    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2803        self.semantics_provider.clone()
 2804    }
 2805
 2806    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2807        self.semantics_provider = provider;
 2808    }
 2809
 2810    pub fn set_edit_prediction_provider<T>(
 2811        &mut self,
 2812        provider: Option<Entity<T>>,
 2813        window: &mut Window,
 2814        cx: &mut Context<Self>,
 2815    ) where
 2816        T: EditPredictionProvider,
 2817    {
 2818        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2819            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2820                if this.focus_handle.is_focused(window) {
 2821                    this.update_visible_edit_prediction(window, cx);
 2822                }
 2823            }),
 2824            provider: Arc::new(provider),
 2825        });
 2826        self.update_edit_prediction_settings(cx);
 2827        self.refresh_edit_prediction(false, false, window, cx);
 2828    }
 2829
 2830    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2831        self.placeholder_display_map
 2832            .as_ref()
 2833            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2834    }
 2835
 2836    pub fn set_placeholder_text(
 2837        &mut self,
 2838        placeholder_text: &str,
 2839        window: &mut Window,
 2840        cx: &mut Context<Self>,
 2841    ) {
 2842        let multibuffer = cx
 2843            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2844
 2845        let style = window.text_style();
 2846
 2847        self.placeholder_display_map = Some(cx.new(|cx| {
 2848            DisplayMap::new(
 2849                multibuffer,
 2850                style.font(),
 2851                style.font_size.to_pixels(window.rem_size()),
 2852                None,
 2853                FILE_HEADER_HEIGHT,
 2854                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2855                Default::default(),
 2856                DiagnosticSeverity::Off,
 2857                cx,
 2858            )
 2859        }));
 2860        cx.notify();
 2861    }
 2862
 2863    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2864        self.cursor_shape = cursor_shape;
 2865
 2866        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2867        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2868
 2869        cx.notify();
 2870    }
 2871
 2872    pub fn set_current_line_highlight(
 2873        &mut self,
 2874        current_line_highlight: Option<CurrentLineHighlight>,
 2875    ) {
 2876        self.current_line_highlight = current_line_highlight;
 2877    }
 2878
 2879    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2880        self.collapse_matches = collapse_matches;
 2881    }
 2882
 2883    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2884        let buffers = self.buffer.read(cx).all_buffers();
 2885        let Some(project) = self.project.as_ref() else {
 2886            return;
 2887        };
 2888        project.update(cx, |project, cx| {
 2889            for buffer in buffers {
 2890                self.registered_buffers
 2891                    .entry(buffer.read(cx).remote_id())
 2892                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2893            }
 2894        })
 2895    }
 2896
 2897    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2898        if self.collapse_matches {
 2899            return range.start..range.start;
 2900        }
 2901        range.clone()
 2902    }
 2903
 2904    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2905        if self.display_map.read(cx).clip_at_line_ends != clip {
 2906            self.display_map
 2907                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2908        }
 2909    }
 2910
 2911    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2912        self.input_enabled = input_enabled;
 2913    }
 2914
 2915    pub fn set_edit_predictions_hidden_for_vim_mode(
 2916        &mut self,
 2917        hidden: bool,
 2918        window: &mut Window,
 2919        cx: &mut Context<Self>,
 2920    ) {
 2921        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2922            self.edit_predictions_hidden_for_vim_mode = hidden;
 2923            if hidden {
 2924                self.update_visible_edit_prediction(window, cx);
 2925            } else {
 2926                self.refresh_edit_prediction(true, false, window, cx);
 2927            }
 2928        }
 2929    }
 2930
 2931    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2932        self.menu_edit_predictions_policy = value;
 2933    }
 2934
 2935    pub fn set_autoindent(&mut self, autoindent: bool) {
 2936        if autoindent {
 2937            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2938        } else {
 2939            self.autoindent_mode = None;
 2940        }
 2941    }
 2942
 2943    pub fn read_only(&self, cx: &App) -> bool {
 2944        self.read_only || self.buffer.read(cx).read_only()
 2945    }
 2946
 2947    pub fn set_read_only(&mut self, read_only: bool) {
 2948        self.read_only = read_only;
 2949    }
 2950
 2951    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2952        self.use_autoclose = autoclose;
 2953    }
 2954
 2955    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2956        self.use_auto_surround = auto_surround;
 2957    }
 2958
 2959    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2960        self.auto_replace_emoji_shortcode = auto_replace;
 2961    }
 2962
 2963    pub fn toggle_edit_predictions(
 2964        &mut self,
 2965        _: &ToggleEditPrediction,
 2966        window: &mut Window,
 2967        cx: &mut Context<Self>,
 2968    ) {
 2969        if self.show_edit_predictions_override.is_some() {
 2970            self.set_show_edit_predictions(None, window, cx);
 2971        } else {
 2972            let show_edit_predictions = !self.edit_predictions_enabled();
 2973            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2974        }
 2975    }
 2976
 2977    pub fn set_show_edit_predictions(
 2978        &mut self,
 2979        show_edit_predictions: Option<bool>,
 2980        window: &mut Window,
 2981        cx: &mut Context<Self>,
 2982    ) {
 2983        self.show_edit_predictions_override = show_edit_predictions;
 2984        self.update_edit_prediction_settings(cx);
 2985
 2986        if let Some(false) = show_edit_predictions {
 2987            self.discard_edit_prediction(false, cx);
 2988        } else {
 2989            self.refresh_edit_prediction(false, true, window, cx);
 2990        }
 2991    }
 2992
 2993    fn edit_predictions_disabled_in_scope(
 2994        &self,
 2995        buffer: &Entity<Buffer>,
 2996        buffer_position: language::Anchor,
 2997        cx: &App,
 2998    ) -> bool {
 2999        let snapshot = buffer.read(cx).snapshot();
 3000        let settings = snapshot.settings_at(buffer_position, cx);
 3001
 3002        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3003            return false;
 3004        };
 3005
 3006        scope.override_name().is_some_and(|scope_name| {
 3007            settings
 3008                .edit_predictions_disabled_in
 3009                .iter()
 3010                .any(|s| s == scope_name)
 3011        })
 3012    }
 3013
 3014    pub fn set_use_modal_editing(&mut self, to: bool) {
 3015        self.use_modal_editing = to;
 3016    }
 3017
 3018    pub fn use_modal_editing(&self) -> bool {
 3019        self.use_modal_editing
 3020    }
 3021
 3022    fn selections_did_change(
 3023        &mut self,
 3024        local: bool,
 3025        old_cursor_position: &Anchor,
 3026        effects: SelectionEffects,
 3027        window: &mut Window,
 3028        cx: &mut Context<Self>,
 3029    ) {
 3030        window.invalidate_character_coordinates();
 3031
 3032        // Copy selections to primary selection buffer
 3033        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3034        if local {
 3035            let selections = self.selections.all::<usize>(cx);
 3036            let buffer_handle = self.buffer.read(cx).read(cx);
 3037
 3038            let mut text = String::new();
 3039            for (index, selection) in selections.iter().enumerate() {
 3040                let text_for_selection = buffer_handle
 3041                    .text_for_range(selection.start..selection.end)
 3042                    .collect::<String>();
 3043
 3044                text.push_str(&text_for_selection);
 3045                if index != selections.len() - 1 {
 3046                    text.push('\n');
 3047                }
 3048            }
 3049
 3050            if !text.is_empty() {
 3051                cx.write_to_primary(ClipboardItem::new_string(text));
 3052            }
 3053        }
 3054
 3055        let selection_anchors = self.selections.disjoint_anchors_arc();
 3056
 3057        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3058            self.buffer.update(cx, |buffer, cx| {
 3059                buffer.set_active_selections(
 3060                    &selection_anchors,
 3061                    self.selections.line_mode,
 3062                    self.cursor_shape,
 3063                    cx,
 3064                )
 3065            });
 3066        }
 3067        let display_map = self
 3068            .display_map
 3069            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3070        let buffer = &display_map.buffer_snapshot;
 3071        if self.selections.count() == 1 {
 3072            self.add_selections_state = None;
 3073        }
 3074        self.select_next_state = None;
 3075        self.select_prev_state = None;
 3076        self.select_syntax_node_history.try_clear();
 3077        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3078        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3079        self.take_rename(false, window, cx);
 3080
 3081        let newest_selection = self.selections.newest_anchor();
 3082        let new_cursor_position = newest_selection.head();
 3083        let selection_start = newest_selection.start;
 3084
 3085        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3086            self.push_to_nav_history(
 3087                *old_cursor_position,
 3088                Some(new_cursor_position.to_point(buffer)),
 3089                false,
 3090                effects.nav_history == Some(true),
 3091                cx,
 3092            );
 3093        }
 3094
 3095        if local {
 3096            if let Some(buffer_id) = new_cursor_position.buffer_id
 3097                && !self.registered_buffers.contains_key(&buffer_id)
 3098                && let Some(project) = self.project.as_ref()
 3099            {
 3100                project.update(cx, |project, cx| {
 3101                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3102                        return;
 3103                    };
 3104                    self.registered_buffers.insert(
 3105                        buffer_id,
 3106                        project.register_buffer_with_language_servers(&buffer, cx),
 3107                    );
 3108                })
 3109            }
 3110
 3111            let mut context_menu = self.context_menu.borrow_mut();
 3112            let completion_menu = match context_menu.as_ref() {
 3113                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3114                Some(CodeContextMenu::CodeActions(_)) => {
 3115                    *context_menu = None;
 3116                    None
 3117                }
 3118                None => None,
 3119            };
 3120            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3121            drop(context_menu);
 3122
 3123            if effects.completions
 3124                && let Some(completion_position) = completion_position
 3125            {
 3126                let start_offset = selection_start.to_offset(buffer);
 3127                let position_matches = start_offset == completion_position.to_offset(buffer);
 3128                let continue_showing = if position_matches {
 3129                    if self.snippet_stack.is_empty() {
 3130                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3131                            == Some(CharKind::Word)
 3132                    } else {
 3133                        // Snippet choices can be shown even when the cursor is in whitespace.
 3134                        // Dismissing the menu with actions like backspace is handled by
 3135                        // invalidation regions.
 3136                        true
 3137                    }
 3138                } else {
 3139                    false
 3140                };
 3141
 3142                if continue_showing {
 3143                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3144                } else {
 3145                    self.hide_context_menu(window, cx);
 3146                }
 3147            }
 3148
 3149            hide_hover(self, cx);
 3150
 3151            if old_cursor_position.to_display_point(&display_map).row()
 3152                != new_cursor_position.to_display_point(&display_map).row()
 3153            {
 3154                self.available_code_actions.take();
 3155            }
 3156            self.refresh_code_actions(window, cx);
 3157            self.refresh_document_highlights(cx);
 3158            self.refresh_selected_text_highlights(false, window, cx);
 3159            refresh_matching_bracket_highlights(self, window, cx);
 3160            self.update_visible_edit_prediction(window, cx);
 3161            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3162            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3163            self.inline_blame_popover.take();
 3164            if self.git_blame_inline_enabled {
 3165                self.start_inline_blame_timer(window, cx);
 3166            }
 3167        }
 3168
 3169        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3170        cx.emit(EditorEvent::SelectionsChanged { local });
 3171
 3172        let selections = &self.selections.disjoint_anchors_arc();
 3173        if selections.len() == 1 {
 3174            cx.emit(SearchEvent::ActiveMatchChanged)
 3175        }
 3176        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3177            let inmemory_selections = selections
 3178                .iter()
 3179                .map(|s| {
 3180                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3181                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3182                })
 3183                .collect();
 3184            self.update_restoration_data(cx, |data| {
 3185                data.selections = inmemory_selections;
 3186            });
 3187
 3188            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3189                && let Some(workspace_id) =
 3190                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3191            {
 3192                let snapshot = self.buffer().read(cx).snapshot(cx);
 3193                let selections = selections.clone();
 3194                let background_executor = cx.background_executor().clone();
 3195                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3196                self.serialize_selections = cx.background_spawn(async move {
 3197                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3198                            let db_selections = selections
 3199                                .iter()
 3200                                .map(|selection| {
 3201                                    (
 3202                                        selection.start.to_offset(&snapshot),
 3203                                        selection.end.to_offset(&snapshot),
 3204                                    )
 3205                                })
 3206                                .collect();
 3207
 3208                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3209                                .await
 3210                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3211                                .log_err();
 3212                        });
 3213            }
 3214        }
 3215
 3216        cx.notify();
 3217    }
 3218
 3219    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3220        use text::ToOffset as _;
 3221        use text::ToPoint as _;
 3222
 3223        if self.mode.is_minimap()
 3224            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3225        {
 3226            return;
 3227        }
 3228
 3229        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3230            return;
 3231        };
 3232
 3233        let snapshot = singleton.read(cx).snapshot();
 3234        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3235            let display_snapshot = display_map.snapshot(cx);
 3236
 3237            display_snapshot
 3238                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3239                .map(|fold| {
 3240                    fold.range.start.text_anchor.to_point(&snapshot)
 3241                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3242                })
 3243                .collect()
 3244        });
 3245        self.update_restoration_data(cx, |data| {
 3246            data.folds = inmemory_folds;
 3247        });
 3248
 3249        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3250            return;
 3251        };
 3252        let background_executor = cx.background_executor().clone();
 3253        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3254        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3255            display_map
 3256                .snapshot(cx)
 3257                .folds_in_range(0..snapshot.len())
 3258                .map(|fold| {
 3259                    (
 3260                        fold.range.start.text_anchor.to_offset(&snapshot),
 3261                        fold.range.end.text_anchor.to_offset(&snapshot),
 3262                    )
 3263                })
 3264                .collect()
 3265        });
 3266        self.serialize_folds = cx.background_spawn(async move {
 3267            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3268            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3269                .await
 3270                .with_context(|| {
 3271                    format!(
 3272                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3273                    )
 3274                })
 3275                .log_err();
 3276        });
 3277    }
 3278
 3279    pub fn sync_selections(
 3280        &mut self,
 3281        other: Entity<Editor>,
 3282        cx: &mut Context<Self>,
 3283    ) -> gpui::Subscription {
 3284        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3285        self.selections.change_with(cx, |selections| {
 3286            selections.select_anchors(other_selections);
 3287        });
 3288
 3289        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3290            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3291                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3292                if other_selections.is_empty() {
 3293                    return;
 3294                }
 3295                this.selections.change_with(cx, |selections| {
 3296                    selections.select_anchors(other_selections);
 3297                });
 3298            }
 3299        });
 3300
 3301        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3302            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3303                let these_selections = this.selections.disjoint_anchors().to_vec();
 3304                if these_selections.is_empty() {
 3305                    return;
 3306                }
 3307                other.update(cx, |other_editor, cx| {
 3308                    other_editor.selections.change_with(cx, |selections| {
 3309                        selections.select_anchors(these_selections);
 3310                    })
 3311                });
 3312            }
 3313        });
 3314
 3315        Subscription::join(other_subscription, this_subscription)
 3316    }
 3317
 3318    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3319    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3320    /// effects of selection change occur at the end of the transaction.
 3321    pub fn change_selections<R>(
 3322        &mut self,
 3323        effects: SelectionEffects,
 3324        window: &mut Window,
 3325        cx: &mut Context<Self>,
 3326        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3327    ) -> R {
 3328        if let Some(state) = &mut self.deferred_selection_effects_state {
 3329            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3330            state.effects.completions = effects.completions;
 3331            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3332            let (changed, result) = self.selections.change_with(cx, change);
 3333            state.changed |= changed;
 3334            return result;
 3335        }
 3336        let mut state = DeferredSelectionEffectsState {
 3337            changed: false,
 3338            effects,
 3339            old_cursor_position: self.selections.newest_anchor().head(),
 3340            history_entry: SelectionHistoryEntry {
 3341                selections: self.selections.disjoint_anchors_arc(),
 3342                select_next_state: self.select_next_state.clone(),
 3343                select_prev_state: self.select_prev_state.clone(),
 3344                add_selections_state: self.add_selections_state.clone(),
 3345            },
 3346        };
 3347        let (changed, result) = self.selections.change_with(cx, change);
 3348        state.changed = state.changed || changed;
 3349        if self.defer_selection_effects {
 3350            self.deferred_selection_effects_state = Some(state);
 3351        } else {
 3352            self.apply_selection_effects(state, window, cx);
 3353        }
 3354        result
 3355    }
 3356
 3357    /// Defers the effects of selection change, so that the effects of multiple calls to
 3358    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3359    /// to selection history and the state of popovers based on selection position aren't
 3360    /// erroneously updated.
 3361    pub fn with_selection_effects_deferred<R>(
 3362        &mut self,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3366    ) -> R {
 3367        let already_deferred = self.defer_selection_effects;
 3368        self.defer_selection_effects = true;
 3369        let result = update(self, window, cx);
 3370        if !already_deferred {
 3371            self.defer_selection_effects = false;
 3372            if let Some(state) = self.deferred_selection_effects_state.take() {
 3373                self.apply_selection_effects(state, window, cx);
 3374            }
 3375        }
 3376        result
 3377    }
 3378
 3379    fn apply_selection_effects(
 3380        &mut self,
 3381        state: DeferredSelectionEffectsState,
 3382        window: &mut Window,
 3383        cx: &mut Context<Self>,
 3384    ) {
 3385        if state.changed {
 3386            self.selection_history.push(state.history_entry);
 3387
 3388            if let Some(autoscroll) = state.effects.scroll {
 3389                self.request_autoscroll(autoscroll, cx);
 3390            }
 3391
 3392            let old_cursor_position = &state.old_cursor_position;
 3393
 3394            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3395
 3396            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3397                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3398            }
 3399        }
 3400    }
 3401
 3402    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3403    where
 3404        I: IntoIterator<Item = (Range<S>, T)>,
 3405        S: ToOffset,
 3406        T: Into<Arc<str>>,
 3407    {
 3408        if self.read_only(cx) {
 3409            return;
 3410        }
 3411
 3412        self.buffer
 3413            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3414    }
 3415
 3416    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3417    where
 3418        I: IntoIterator<Item = (Range<S>, T)>,
 3419        S: ToOffset,
 3420        T: Into<Arc<str>>,
 3421    {
 3422        if self.read_only(cx) {
 3423            return;
 3424        }
 3425
 3426        self.buffer.update(cx, |buffer, cx| {
 3427            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3428        });
 3429    }
 3430
 3431    pub fn edit_with_block_indent<I, S, T>(
 3432        &mut self,
 3433        edits: I,
 3434        original_indent_columns: Vec<Option<u32>>,
 3435        cx: &mut Context<Self>,
 3436    ) where
 3437        I: IntoIterator<Item = (Range<S>, T)>,
 3438        S: ToOffset,
 3439        T: Into<Arc<str>>,
 3440    {
 3441        if self.read_only(cx) {
 3442            return;
 3443        }
 3444
 3445        self.buffer.update(cx, |buffer, cx| {
 3446            buffer.edit(
 3447                edits,
 3448                Some(AutoindentMode::Block {
 3449                    original_indent_columns,
 3450                }),
 3451                cx,
 3452            )
 3453        });
 3454    }
 3455
 3456    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3457        self.hide_context_menu(window, cx);
 3458
 3459        match phase {
 3460            SelectPhase::Begin {
 3461                position,
 3462                add,
 3463                click_count,
 3464            } => self.begin_selection(position, add, click_count, window, cx),
 3465            SelectPhase::BeginColumnar {
 3466                position,
 3467                goal_column,
 3468                reset,
 3469                mode,
 3470            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3471            SelectPhase::Extend {
 3472                position,
 3473                click_count,
 3474            } => self.extend_selection(position, click_count, window, cx),
 3475            SelectPhase::Update {
 3476                position,
 3477                goal_column,
 3478                scroll_delta,
 3479            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3480            SelectPhase::End => self.end_selection(window, cx),
 3481        }
 3482    }
 3483
 3484    fn extend_selection(
 3485        &mut self,
 3486        position: DisplayPoint,
 3487        click_count: usize,
 3488        window: &mut Window,
 3489        cx: &mut Context<Self>,
 3490    ) {
 3491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3492        let tail = self.selections.newest::<usize>(cx).tail();
 3493        self.begin_selection(position, false, click_count, window, cx);
 3494
 3495        let position = position.to_offset(&display_map, Bias::Left);
 3496        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3497
 3498        let mut pending_selection = self
 3499            .selections
 3500            .pending_anchor()
 3501            .cloned()
 3502            .expect("extend_selection not called with pending selection");
 3503        if position >= tail {
 3504            pending_selection.start = tail_anchor;
 3505        } else {
 3506            pending_selection.end = tail_anchor;
 3507            pending_selection.reversed = true;
 3508        }
 3509
 3510        let mut pending_mode = self.selections.pending_mode().unwrap();
 3511        match &mut pending_mode {
 3512            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3513            _ => {}
 3514        }
 3515
 3516        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3517            SelectionEffects::scroll(Autoscroll::fit())
 3518        } else {
 3519            SelectionEffects::no_scroll()
 3520        };
 3521
 3522        self.change_selections(effects, window, cx, |s| {
 3523            s.set_pending(pending_selection.clone(), pending_mode)
 3524        });
 3525    }
 3526
 3527    fn begin_selection(
 3528        &mut self,
 3529        position: DisplayPoint,
 3530        add: bool,
 3531        click_count: usize,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if !self.focus_handle.is_focused(window) {
 3536            self.last_focused_descendant = None;
 3537            window.focus(&self.focus_handle);
 3538        }
 3539
 3540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3541        let buffer = &display_map.buffer_snapshot;
 3542        let position = display_map.clip_point(position, Bias::Left);
 3543
 3544        let start;
 3545        let end;
 3546        let mode;
 3547        let mut auto_scroll;
 3548        match click_count {
 3549            1 => {
 3550                start = buffer.anchor_before(position.to_point(&display_map));
 3551                end = start;
 3552                mode = SelectMode::Character;
 3553                auto_scroll = true;
 3554            }
 3555            2 => {
 3556                let position = display_map
 3557                    .clip_point(position, Bias::Left)
 3558                    .to_offset(&display_map, Bias::Left);
 3559                let (range, _) = buffer.surrounding_word(position, None);
 3560                start = buffer.anchor_before(range.start);
 3561                end = buffer.anchor_before(range.end);
 3562                mode = SelectMode::Word(start..end);
 3563                auto_scroll = true;
 3564            }
 3565            3 => {
 3566                let position = display_map
 3567                    .clip_point(position, Bias::Left)
 3568                    .to_point(&display_map);
 3569                let line_start = display_map.prev_line_boundary(position).0;
 3570                let next_line_start = buffer.clip_point(
 3571                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3572                    Bias::Left,
 3573                );
 3574                start = buffer.anchor_before(line_start);
 3575                end = buffer.anchor_before(next_line_start);
 3576                mode = SelectMode::Line(start..end);
 3577                auto_scroll = true;
 3578            }
 3579            _ => {
 3580                start = buffer.anchor_before(0);
 3581                end = buffer.anchor_before(buffer.len());
 3582                mode = SelectMode::All;
 3583                auto_scroll = false;
 3584            }
 3585        }
 3586        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3587
 3588        let point_to_delete: Option<usize> = {
 3589            let selected_points: Vec<Selection<Point>> =
 3590                self.selections.disjoint_in_range(start..end, cx);
 3591
 3592            if !add || click_count > 1 {
 3593                None
 3594            } else if !selected_points.is_empty() {
 3595                Some(selected_points[0].id)
 3596            } else {
 3597                let clicked_point_already_selected =
 3598                    self.selections.disjoint_anchors().iter().find(|selection| {
 3599                        selection.start.to_point(buffer) == start.to_point(buffer)
 3600                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3601                    });
 3602
 3603                clicked_point_already_selected.map(|selection| selection.id)
 3604            }
 3605        };
 3606
 3607        let selections_count = self.selections.count();
 3608        let effects = if auto_scroll {
 3609            SelectionEffects::default()
 3610        } else {
 3611            SelectionEffects::no_scroll()
 3612        };
 3613
 3614        self.change_selections(effects, window, cx, |s| {
 3615            if let Some(point_to_delete) = point_to_delete {
 3616                s.delete(point_to_delete);
 3617
 3618                if selections_count == 1 {
 3619                    s.set_pending_anchor_range(start..end, mode);
 3620                }
 3621            } else {
 3622                if !add {
 3623                    s.clear_disjoint();
 3624                }
 3625
 3626                s.set_pending_anchor_range(start..end, mode);
 3627            }
 3628        });
 3629    }
 3630
 3631    fn begin_columnar_selection(
 3632        &mut self,
 3633        position: DisplayPoint,
 3634        goal_column: u32,
 3635        reset: bool,
 3636        mode: ColumnarMode,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639    ) {
 3640        if !self.focus_handle.is_focused(window) {
 3641            self.last_focused_descendant = None;
 3642            window.focus(&self.focus_handle);
 3643        }
 3644
 3645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3646
 3647        if reset {
 3648            let pointer_position = display_map
 3649                .buffer_snapshot
 3650                .anchor_before(position.to_point(&display_map));
 3651
 3652            self.change_selections(
 3653                SelectionEffects::scroll(Autoscroll::newest()),
 3654                window,
 3655                cx,
 3656                |s| {
 3657                    s.clear_disjoint();
 3658                    s.set_pending_anchor_range(
 3659                        pointer_position..pointer_position,
 3660                        SelectMode::Character,
 3661                    );
 3662                },
 3663            );
 3664        };
 3665
 3666        let tail = self.selections.newest::<Point>(cx).tail();
 3667        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3668        self.columnar_selection_state = match mode {
 3669            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3670                selection_tail: selection_anchor,
 3671                display_point: if reset {
 3672                    if position.column() != goal_column {
 3673                        Some(DisplayPoint::new(position.row(), goal_column))
 3674                    } else {
 3675                        None
 3676                    }
 3677                } else {
 3678                    None
 3679                },
 3680            }),
 3681            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3682                selection_tail: selection_anchor,
 3683            }),
 3684        };
 3685
 3686        if !reset {
 3687            self.select_columns(position, goal_column, &display_map, window, cx);
 3688        }
 3689    }
 3690
 3691    fn update_selection(
 3692        &mut self,
 3693        position: DisplayPoint,
 3694        goal_column: u32,
 3695        scroll_delta: gpui::Point<f32>,
 3696        window: &mut Window,
 3697        cx: &mut Context<Self>,
 3698    ) {
 3699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3700
 3701        if self.columnar_selection_state.is_some() {
 3702            self.select_columns(position, goal_column, &display_map, window, cx);
 3703        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3704            let buffer = &display_map.buffer_snapshot;
 3705            let head;
 3706            let tail;
 3707            let mode = self.selections.pending_mode().unwrap();
 3708            match &mode {
 3709                SelectMode::Character => {
 3710                    head = position.to_point(&display_map);
 3711                    tail = pending.tail().to_point(buffer);
 3712                }
 3713                SelectMode::Word(original_range) => {
 3714                    let offset = display_map
 3715                        .clip_point(position, Bias::Left)
 3716                        .to_offset(&display_map, Bias::Left);
 3717                    let original_range = original_range.to_offset(buffer);
 3718
 3719                    let head_offset = if buffer.is_inside_word(offset, None)
 3720                        || original_range.contains(&offset)
 3721                    {
 3722                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3723                        if word_range.start < original_range.start {
 3724                            word_range.start
 3725                        } else {
 3726                            word_range.end
 3727                        }
 3728                    } else {
 3729                        offset
 3730                    };
 3731
 3732                    head = head_offset.to_point(buffer);
 3733                    if head_offset <= original_range.start {
 3734                        tail = original_range.end.to_point(buffer);
 3735                    } else {
 3736                        tail = original_range.start.to_point(buffer);
 3737                    }
 3738                }
 3739                SelectMode::Line(original_range) => {
 3740                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3741
 3742                    let position = display_map
 3743                        .clip_point(position, Bias::Left)
 3744                        .to_point(&display_map);
 3745                    let line_start = display_map.prev_line_boundary(position).0;
 3746                    let next_line_start = buffer.clip_point(
 3747                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3748                        Bias::Left,
 3749                    );
 3750
 3751                    if line_start < original_range.start {
 3752                        head = line_start
 3753                    } else {
 3754                        head = next_line_start
 3755                    }
 3756
 3757                    if head <= original_range.start {
 3758                        tail = original_range.end;
 3759                    } else {
 3760                        tail = original_range.start;
 3761                    }
 3762                }
 3763                SelectMode::All => {
 3764                    return;
 3765                }
 3766            };
 3767
 3768            if head < tail {
 3769                pending.start = buffer.anchor_before(head);
 3770                pending.end = buffer.anchor_before(tail);
 3771                pending.reversed = true;
 3772            } else {
 3773                pending.start = buffer.anchor_before(tail);
 3774                pending.end = buffer.anchor_before(head);
 3775                pending.reversed = false;
 3776            }
 3777
 3778            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3779                s.set_pending(pending.clone(), mode);
 3780            });
 3781        } else {
 3782            log::error!("update_selection dispatched with no pending selection");
 3783            return;
 3784        }
 3785
 3786        self.apply_scroll_delta(scroll_delta, window, cx);
 3787        cx.notify();
 3788    }
 3789
 3790    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3791        self.columnar_selection_state.take();
 3792        if self.selections.pending_anchor().is_some() {
 3793            let selections = self.selections.all::<usize>(cx);
 3794            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3795                s.select(selections);
 3796                s.clear_pending();
 3797            });
 3798        }
 3799    }
 3800
 3801    fn select_columns(
 3802        &mut self,
 3803        head: DisplayPoint,
 3804        goal_column: u32,
 3805        display_map: &DisplaySnapshot,
 3806        window: &mut Window,
 3807        cx: &mut Context<Self>,
 3808    ) {
 3809        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3810            return;
 3811        };
 3812
 3813        let tail = match columnar_state {
 3814            ColumnarSelectionState::FromMouse {
 3815                selection_tail,
 3816                display_point,
 3817            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3818            ColumnarSelectionState::FromSelection { selection_tail } => {
 3819                selection_tail.to_display_point(display_map)
 3820            }
 3821        };
 3822
 3823        let start_row = cmp::min(tail.row(), head.row());
 3824        let end_row = cmp::max(tail.row(), head.row());
 3825        let start_column = cmp::min(tail.column(), goal_column);
 3826        let end_column = cmp::max(tail.column(), goal_column);
 3827        let reversed = start_column < tail.column();
 3828
 3829        let selection_ranges = (start_row.0..=end_row.0)
 3830            .map(DisplayRow)
 3831            .filter_map(|row| {
 3832                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3833                    || start_column <= display_map.line_len(row))
 3834                    && !display_map.is_block_line(row)
 3835                {
 3836                    let start = display_map
 3837                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3838                        .to_point(display_map);
 3839                    let end = display_map
 3840                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3841                        .to_point(display_map);
 3842                    if reversed {
 3843                        Some(end..start)
 3844                    } else {
 3845                        Some(start..end)
 3846                    }
 3847                } else {
 3848                    None
 3849                }
 3850            })
 3851            .collect::<Vec<_>>();
 3852
 3853        let ranges = match columnar_state {
 3854            ColumnarSelectionState::FromMouse { .. } => {
 3855                let mut non_empty_ranges = selection_ranges
 3856                    .iter()
 3857                    .filter(|selection_range| selection_range.start != selection_range.end)
 3858                    .peekable();
 3859                if non_empty_ranges.peek().is_some() {
 3860                    non_empty_ranges.cloned().collect()
 3861                } else {
 3862                    selection_ranges
 3863                }
 3864            }
 3865            _ => selection_ranges,
 3866        };
 3867
 3868        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3869            s.select_ranges(ranges);
 3870        });
 3871        cx.notify();
 3872    }
 3873
 3874    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3875        self.selections
 3876            .all_adjusted(cx)
 3877            .iter()
 3878            .any(|selection| !selection.is_empty())
 3879    }
 3880
 3881    pub fn has_pending_nonempty_selection(&self) -> bool {
 3882        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3883            Some(Selection { start, end, .. }) => start != end,
 3884            None => false,
 3885        };
 3886
 3887        pending_nonempty_selection
 3888            || (self.columnar_selection_state.is_some()
 3889                && self.selections.disjoint_anchors().len() > 1)
 3890    }
 3891
 3892    pub fn has_pending_selection(&self) -> bool {
 3893        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3894    }
 3895
 3896    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3897        self.selection_mark_mode = false;
 3898        self.selection_drag_state = SelectionDragState::None;
 3899
 3900        if self.clear_expanded_diff_hunks(cx) {
 3901            cx.notify();
 3902            return;
 3903        }
 3904        if self.dismiss_menus_and_popups(true, window, cx) {
 3905            return;
 3906        }
 3907
 3908        if self.mode.is_full()
 3909            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3910        {
 3911            return;
 3912        }
 3913
 3914        cx.propagate();
 3915    }
 3916
 3917    pub fn dismiss_menus_and_popups(
 3918        &mut self,
 3919        is_user_requested: bool,
 3920        window: &mut Window,
 3921        cx: &mut Context<Self>,
 3922    ) -> bool {
 3923        if self.take_rename(false, window, cx).is_some() {
 3924            return true;
 3925        }
 3926
 3927        if hide_hover(self, cx) {
 3928            return true;
 3929        }
 3930
 3931        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3932            return true;
 3933        }
 3934
 3935        if self.hide_context_menu(window, cx).is_some() {
 3936            return true;
 3937        }
 3938
 3939        if self.mouse_context_menu.take().is_some() {
 3940            return true;
 3941        }
 3942
 3943        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3944            return true;
 3945        }
 3946
 3947        if self.snippet_stack.pop().is_some() {
 3948            return true;
 3949        }
 3950
 3951        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3952            self.dismiss_diagnostics(cx);
 3953            return true;
 3954        }
 3955
 3956        false
 3957    }
 3958
 3959    fn linked_editing_ranges_for(
 3960        &self,
 3961        selection: Range<text::Anchor>,
 3962        cx: &App,
 3963    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3964        if self.linked_edit_ranges.is_empty() {
 3965            return None;
 3966        }
 3967        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3968            selection.end.buffer_id.and_then(|end_buffer_id| {
 3969                if selection.start.buffer_id != Some(end_buffer_id) {
 3970                    return None;
 3971                }
 3972                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3973                let snapshot = buffer.read(cx).snapshot();
 3974                self.linked_edit_ranges
 3975                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3976                    .map(|ranges| (ranges, snapshot, buffer))
 3977            })?;
 3978        use text::ToOffset as TO;
 3979        // find offset from the start of current range to current cursor position
 3980        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3981
 3982        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3983        let start_difference = start_offset - start_byte_offset;
 3984        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3985        let end_difference = end_offset - start_byte_offset;
 3986        // Current range has associated linked ranges.
 3987        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3988        for range in linked_ranges.iter() {
 3989            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3990            let end_offset = start_offset + end_difference;
 3991            let start_offset = start_offset + start_difference;
 3992            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3993                continue;
 3994            }
 3995            if self.selections.disjoint_anchor_ranges().any(|s| {
 3996                if s.start.buffer_id != selection.start.buffer_id
 3997                    || s.end.buffer_id != selection.end.buffer_id
 3998                {
 3999                    return false;
 4000                }
 4001                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4002                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4003            }) {
 4004                continue;
 4005            }
 4006            let start = buffer_snapshot.anchor_after(start_offset);
 4007            let end = buffer_snapshot.anchor_after(end_offset);
 4008            linked_edits
 4009                .entry(buffer.clone())
 4010                .or_default()
 4011                .push(start..end);
 4012        }
 4013        Some(linked_edits)
 4014    }
 4015
 4016    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4017        let text: Arc<str> = text.into();
 4018
 4019        if self.read_only(cx) {
 4020            return;
 4021        }
 4022
 4023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4024
 4025        let selections = self.selections.all_adjusted(cx);
 4026        let mut bracket_inserted = false;
 4027        let mut edits = Vec::new();
 4028        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4029        let mut new_selections = Vec::with_capacity(selections.len());
 4030        let mut new_autoclose_regions = Vec::new();
 4031        let snapshot = self.buffer.read(cx).read(cx);
 4032        let mut clear_linked_edit_ranges = false;
 4033
 4034        for (selection, autoclose_region) in
 4035            self.selections_with_autoclose_regions(selections, &snapshot)
 4036        {
 4037            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4038                // Determine if the inserted text matches the opening or closing
 4039                // bracket of any of this language's bracket pairs.
 4040                let mut bracket_pair = None;
 4041                let mut is_bracket_pair_start = false;
 4042                let mut is_bracket_pair_end = false;
 4043                if !text.is_empty() {
 4044                    let mut bracket_pair_matching_end = None;
 4045                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4046                    //  and they are removing the character that triggered IME popup.
 4047                    for (pair, enabled) in scope.brackets() {
 4048                        if !pair.close && !pair.surround {
 4049                            continue;
 4050                        }
 4051
 4052                        if enabled && pair.start.ends_with(text.as_ref()) {
 4053                            let prefix_len = pair.start.len() - text.len();
 4054                            let preceding_text_matches_prefix = prefix_len == 0
 4055                                || (selection.start.column >= (prefix_len as u32)
 4056                                    && snapshot.contains_str_at(
 4057                                        Point::new(
 4058                                            selection.start.row,
 4059                                            selection.start.column - (prefix_len as u32),
 4060                                        ),
 4061                                        &pair.start[..prefix_len],
 4062                                    ));
 4063                            if preceding_text_matches_prefix {
 4064                                bracket_pair = Some(pair.clone());
 4065                                is_bracket_pair_start = true;
 4066                                break;
 4067                            }
 4068                        }
 4069                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4070                        {
 4071                            // take first bracket pair matching end, but don't break in case a later bracket
 4072                            // pair matches start
 4073                            bracket_pair_matching_end = Some(pair.clone());
 4074                        }
 4075                    }
 4076                    if let Some(end) = bracket_pair_matching_end
 4077                        && bracket_pair.is_none()
 4078                    {
 4079                        bracket_pair = Some(end);
 4080                        is_bracket_pair_end = true;
 4081                    }
 4082                }
 4083
 4084                if let Some(bracket_pair) = bracket_pair {
 4085                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4086                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4087                    let auto_surround =
 4088                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4089                    if selection.is_empty() {
 4090                        if is_bracket_pair_start {
 4091                            // If the inserted text is a suffix of an opening bracket and the
 4092                            // selection is preceded by the rest of the opening bracket, then
 4093                            // insert the closing bracket.
 4094                            let following_text_allows_autoclose = snapshot
 4095                                .chars_at(selection.start)
 4096                                .next()
 4097                                .is_none_or(|c| scope.should_autoclose_before(c));
 4098
 4099                            let preceding_text_allows_autoclose = selection.start.column == 0
 4100                                || snapshot
 4101                                    .reversed_chars_at(selection.start)
 4102                                    .next()
 4103                                    .is_none_or(|c| {
 4104                                        bracket_pair.start != bracket_pair.end
 4105                                            || !snapshot
 4106                                                .char_classifier_at(selection.start)
 4107                                                .is_word(c)
 4108                                    });
 4109
 4110                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4111                                && bracket_pair.start.len() == 1
 4112                            {
 4113                                let target = bracket_pair.start.chars().next().unwrap();
 4114                                let current_line_count = snapshot
 4115                                    .reversed_chars_at(selection.start)
 4116                                    .take_while(|&c| c != '\n')
 4117                                    .filter(|&c| c == target)
 4118                                    .count();
 4119                                current_line_count % 2 == 1
 4120                            } else {
 4121                                false
 4122                            };
 4123
 4124                            if autoclose
 4125                                && bracket_pair.close
 4126                                && following_text_allows_autoclose
 4127                                && preceding_text_allows_autoclose
 4128                                && !is_closing_quote
 4129                            {
 4130                                let anchor = snapshot.anchor_before(selection.end);
 4131                                new_selections.push((selection.map(|_| anchor), text.len()));
 4132                                new_autoclose_regions.push((
 4133                                    anchor,
 4134                                    text.len(),
 4135                                    selection.id,
 4136                                    bracket_pair.clone(),
 4137                                ));
 4138                                edits.push((
 4139                                    selection.range(),
 4140                                    format!("{}{}", text, bracket_pair.end).into(),
 4141                                ));
 4142                                bracket_inserted = true;
 4143                                continue;
 4144                            }
 4145                        }
 4146
 4147                        if let Some(region) = autoclose_region {
 4148                            // If the selection is followed by an auto-inserted closing bracket,
 4149                            // then don't insert that closing bracket again; just move the selection
 4150                            // past the closing bracket.
 4151                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4152                                && text.as_ref() == region.pair.end.as_str()
 4153                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4154                            if should_skip {
 4155                                let anchor = snapshot.anchor_after(selection.end);
 4156                                new_selections
 4157                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4158                                continue;
 4159                            }
 4160                        }
 4161
 4162                        let always_treat_brackets_as_autoclosed = snapshot
 4163                            .language_settings_at(selection.start, cx)
 4164                            .always_treat_brackets_as_autoclosed;
 4165                        if always_treat_brackets_as_autoclosed
 4166                            && is_bracket_pair_end
 4167                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4168                        {
 4169                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4170                            // and the inserted text is a closing bracket and the selection is followed
 4171                            // by the closing bracket then move the selection past the closing bracket.
 4172                            let anchor = snapshot.anchor_after(selection.end);
 4173                            new_selections.push((selection.map(|_| anchor), text.len()));
 4174                            continue;
 4175                        }
 4176                    }
 4177                    // If an opening bracket is 1 character long and is typed while
 4178                    // text is selected, then surround that text with the bracket pair.
 4179                    else if auto_surround
 4180                        && bracket_pair.surround
 4181                        && is_bracket_pair_start
 4182                        && bracket_pair.start.chars().count() == 1
 4183                    {
 4184                        edits.push((selection.start..selection.start, text.clone()));
 4185                        edits.push((
 4186                            selection.end..selection.end,
 4187                            bracket_pair.end.as_str().into(),
 4188                        ));
 4189                        bracket_inserted = true;
 4190                        new_selections.push((
 4191                            Selection {
 4192                                id: selection.id,
 4193                                start: snapshot.anchor_after(selection.start),
 4194                                end: snapshot.anchor_before(selection.end),
 4195                                reversed: selection.reversed,
 4196                                goal: selection.goal,
 4197                            },
 4198                            0,
 4199                        ));
 4200                        continue;
 4201                    }
 4202                }
 4203            }
 4204
 4205            if self.auto_replace_emoji_shortcode
 4206                && selection.is_empty()
 4207                && text.as_ref().ends_with(':')
 4208                && let Some(possible_emoji_short_code) =
 4209                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4210                && !possible_emoji_short_code.is_empty()
 4211                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4212            {
 4213                let emoji_shortcode_start = Point::new(
 4214                    selection.start.row,
 4215                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4216                );
 4217
 4218                // Remove shortcode from buffer
 4219                edits.push((
 4220                    emoji_shortcode_start..selection.start,
 4221                    "".to_string().into(),
 4222                ));
 4223                new_selections.push((
 4224                    Selection {
 4225                        id: selection.id,
 4226                        start: snapshot.anchor_after(emoji_shortcode_start),
 4227                        end: snapshot.anchor_before(selection.start),
 4228                        reversed: selection.reversed,
 4229                        goal: selection.goal,
 4230                    },
 4231                    0,
 4232                ));
 4233
 4234                // Insert emoji
 4235                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4236                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4237                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4238
 4239                continue;
 4240            }
 4241
 4242            // If not handling any auto-close operation, then just replace the selected
 4243            // text with the given input and move the selection to the end of the
 4244            // newly inserted text.
 4245            let anchor = snapshot.anchor_after(selection.end);
 4246            if !self.linked_edit_ranges.is_empty() {
 4247                let start_anchor = snapshot.anchor_before(selection.start);
 4248
 4249                let is_word_char = text.chars().next().is_none_or(|char| {
 4250                    let classifier = snapshot
 4251                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4252                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4253                    classifier.is_word(char)
 4254                });
 4255
 4256                if is_word_char {
 4257                    if let Some(ranges) = self
 4258                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4259                    {
 4260                        for (buffer, edits) in ranges {
 4261                            linked_edits
 4262                                .entry(buffer.clone())
 4263                                .or_default()
 4264                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4265                        }
 4266                    }
 4267                } else {
 4268                    clear_linked_edit_ranges = true;
 4269                }
 4270            }
 4271
 4272            new_selections.push((selection.map(|_| anchor), 0));
 4273            edits.push((selection.start..selection.end, text.clone()));
 4274        }
 4275
 4276        drop(snapshot);
 4277
 4278        self.transact(window, cx, |this, window, cx| {
 4279            if clear_linked_edit_ranges {
 4280                this.linked_edit_ranges.clear();
 4281            }
 4282            let initial_buffer_versions =
 4283                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4284
 4285            this.buffer.update(cx, |buffer, cx| {
 4286                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4287            });
 4288            for (buffer, edits) in linked_edits {
 4289                buffer.update(cx, |buffer, cx| {
 4290                    let snapshot = buffer.snapshot();
 4291                    let edits = edits
 4292                        .into_iter()
 4293                        .map(|(range, text)| {
 4294                            use text::ToPoint as TP;
 4295                            let end_point = TP::to_point(&range.end, &snapshot);
 4296                            let start_point = TP::to_point(&range.start, &snapshot);
 4297                            (start_point..end_point, text)
 4298                        })
 4299                        .sorted_by_key(|(range, _)| range.start);
 4300                    buffer.edit(edits, None, cx);
 4301                })
 4302            }
 4303            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4304            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4305            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4306            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4307                .zip(new_selection_deltas)
 4308                .map(|(selection, delta)| Selection {
 4309                    id: selection.id,
 4310                    start: selection.start + delta,
 4311                    end: selection.end + delta,
 4312                    reversed: selection.reversed,
 4313                    goal: SelectionGoal::None,
 4314                })
 4315                .collect::<Vec<_>>();
 4316
 4317            let mut i = 0;
 4318            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4319                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4320                let start = map.buffer_snapshot.anchor_before(position);
 4321                let end = map.buffer_snapshot.anchor_after(position);
 4322                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4323                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4324                        Ordering::Less => i += 1,
 4325                        Ordering::Greater => break,
 4326                        Ordering::Equal => {
 4327                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4328                                Ordering::Less => i += 1,
 4329                                Ordering::Equal => break,
 4330                                Ordering::Greater => break,
 4331                            }
 4332                        }
 4333                    }
 4334                }
 4335                this.autoclose_regions.insert(
 4336                    i,
 4337                    AutocloseRegion {
 4338                        selection_id,
 4339                        range: start..end,
 4340                        pair,
 4341                    },
 4342                );
 4343            }
 4344
 4345            let had_active_edit_prediction = this.has_active_edit_prediction();
 4346            this.change_selections(
 4347                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4348                window,
 4349                cx,
 4350                |s| s.select(new_selections),
 4351            );
 4352
 4353            if !bracket_inserted
 4354                && let Some(on_type_format_task) =
 4355                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4356            {
 4357                on_type_format_task.detach_and_log_err(cx);
 4358            }
 4359
 4360            let editor_settings = EditorSettings::get_global(cx);
 4361            if bracket_inserted
 4362                && (editor_settings.auto_signature_help
 4363                    || editor_settings.show_signature_help_after_edits)
 4364            {
 4365                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4366            }
 4367
 4368            let trigger_in_words =
 4369                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4370            if this.hard_wrap.is_some() {
 4371                let latest: Range<Point> = this.selections.newest(cx).range();
 4372                if latest.is_empty()
 4373                    && this
 4374                        .buffer()
 4375                        .read(cx)
 4376                        .snapshot(cx)
 4377                        .line_len(MultiBufferRow(latest.start.row))
 4378                        == latest.start.column
 4379                {
 4380                    this.rewrap_impl(
 4381                        RewrapOptions {
 4382                            override_language_settings: true,
 4383                            preserve_existing_whitespace: true,
 4384                        },
 4385                        cx,
 4386                    )
 4387                }
 4388            }
 4389            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4390            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4391            this.refresh_edit_prediction(true, false, window, cx);
 4392            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4393        });
 4394    }
 4395
 4396    fn find_possible_emoji_shortcode_at_position(
 4397        snapshot: &MultiBufferSnapshot,
 4398        position: Point,
 4399    ) -> Option<String> {
 4400        let mut chars = Vec::new();
 4401        let mut found_colon = false;
 4402        for char in snapshot.reversed_chars_at(position).take(100) {
 4403            // Found a possible emoji shortcode in the middle of the buffer
 4404            if found_colon {
 4405                if char.is_whitespace() {
 4406                    chars.reverse();
 4407                    return Some(chars.iter().collect());
 4408                }
 4409                // If the previous character is not a whitespace, we are in the middle of a word
 4410                // and we only want to complete the shortcode if the word is made up of other emojis
 4411                let mut containing_word = String::new();
 4412                for ch in snapshot
 4413                    .reversed_chars_at(position)
 4414                    .skip(chars.len() + 1)
 4415                    .take(100)
 4416                {
 4417                    if ch.is_whitespace() {
 4418                        break;
 4419                    }
 4420                    containing_word.push(ch);
 4421                }
 4422                let containing_word = containing_word.chars().rev().collect::<String>();
 4423                if util::word_consists_of_emojis(containing_word.as_str()) {
 4424                    chars.reverse();
 4425                    return Some(chars.iter().collect());
 4426                }
 4427            }
 4428
 4429            if char.is_whitespace() || !char.is_ascii() {
 4430                return None;
 4431            }
 4432            if char == ':' {
 4433                found_colon = true;
 4434            } else {
 4435                chars.push(char);
 4436            }
 4437        }
 4438        // Found a possible emoji shortcode at the beginning of the buffer
 4439        chars.reverse();
 4440        Some(chars.iter().collect())
 4441    }
 4442
 4443    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4444        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4445        self.transact(window, cx, |this, window, cx| {
 4446            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4447                let selections = this.selections.all::<usize>(cx);
 4448                let multi_buffer = this.buffer.read(cx);
 4449                let buffer = multi_buffer.snapshot(cx);
 4450                selections
 4451                    .iter()
 4452                    .map(|selection| {
 4453                        let start_point = selection.start.to_point(&buffer);
 4454                        let mut existing_indent =
 4455                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4456                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4457                        let start = selection.start;
 4458                        let end = selection.end;
 4459                        let selection_is_empty = start == end;
 4460                        let language_scope = buffer.language_scope_at(start);
 4461                        let (
 4462                            comment_delimiter,
 4463                            doc_delimiter,
 4464                            insert_extra_newline,
 4465                            indent_on_newline,
 4466                            indent_on_extra_newline,
 4467                        ) = if let Some(language) = &language_scope {
 4468                            let mut insert_extra_newline =
 4469                                insert_extra_newline_brackets(&buffer, start..end, language)
 4470                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4471
 4472                            // Comment extension on newline is allowed only for cursor selections
 4473                            let comment_delimiter = maybe!({
 4474                                if !selection_is_empty {
 4475                                    return None;
 4476                                }
 4477
 4478                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4479                                    return None;
 4480                                }
 4481
 4482                                let delimiters = language.line_comment_prefixes();
 4483                                let max_len_of_delimiter =
 4484                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4485                                let (snapshot, range) =
 4486                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4487
 4488                                let num_of_whitespaces = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .take_while(|c| c.is_whitespace())
 4491                                    .count();
 4492                                let comment_candidate = snapshot
 4493                                    .chars_for_range(range.clone())
 4494                                    .skip(num_of_whitespaces)
 4495                                    .take(max_len_of_delimiter)
 4496                                    .collect::<String>();
 4497                                let (delimiter, trimmed_len) = delimiters
 4498                                    .iter()
 4499                                    .filter_map(|delimiter| {
 4500                                        let prefix = delimiter.trim_end();
 4501                                        if comment_candidate.starts_with(prefix) {
 4502                                            Some((delimiter, prefix.len()))
 4503                                        } else {
 4504                                            None
 4505                                        }
 4506                                    })
 4507                                    .max_by_key(|(_, len)| *len)?;
 4508
 4509                                if let Some(BlockCommentConfig {
 4510                                    start: block_start, ..
 4511                                }) = language.block_comment()
 4512                                {
 4513                                    let block_start_trimmed = block_start.trim_end();
 4514                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4515                                        let line_content = snapshot
 4516                                            .chars_for_range(range)
 4517                                            .skip(num_of_whitespaces)
 4518                                            .take(block_start_trimmed.len())
 4519                                            .collect::<String>();
 4520
 4521                                        if line_content.starts_with(block_start_trimmed) {
 4522                                            return None;
 4523                                        }
 4524                                    }
 4525                                }
 4526
 4527                                let cursor_is_placed_after_comment_marker =
 4528                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4529                                if cursor_is_placed_after_comment_marker {
 4530                                    Some(delimiter.clone())
 4531                                } else {
 4532                                    None
 4533                                }
 4534                            });
 4535
 4536                            let mut indent_on_newline = IndentSize::spaces(0);
 4537                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4538
 4539                            let doc_delimiter = maybe!({
 4540                                if !selection_is_empty {
 4541                                    return None;
 4542                                }
 4543
 4544                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4545                                    return None;
 4546                                }
 4547
 4548                                let BlockCommentConfig {
 4549                                    start: start_tag,
 4550                                    end: end_tag,
 4551                                    prefix: delimiter,
 4552                                    tab_size: len,
 4553                                } = language.documentation_comment()?;
 4554                                let is_within_block_comment = buffer
 4555                                    .language_scope_at(start_point)
 4556                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4557                                if !is_within_block_comment {
 4558                                    return None;
 4559                                }
 4560
 4561                                let (snapshot, range) =
 4562                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4563
 4564                                let num_of_whitespaces = snapshot
 4565                                    .chars_for_range(range.clone())
 4566                                    .take_while(|c| c.is_whitespace())
 4567                                    .count();
 4568
 4569                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4570                                let column = start_point.column;
 4571                                let cursor_is_after_start_tag = {
 4572                                    let start_tag_len = start_tag.len();
 4573                                    let start_tag_line = snapshot
 4574                                        .chars_for_range(range.clone())
 4575                                        .skip(num_of_whitespaces)
 4576                                        .take(start_tag_len)
 4577                                        .collect::<String>();
 4578                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4579                                        num_of_whitespaces + start_tag_len <= column as usize
 4580                                    } else {
 4581                                        false
 4582                                    }
 4583                                };
 4584
 4585                                let cursor_is_after_delimiter = {
 4586                                    let delimiter_trim = delimiter.trim_end();
 4587                                    let delimiter_line = snapshot
 4588                                        .chars_for_range(range.clone())
 4589                                        .skip(num_of_whitespaces)
 4590                                        .take(delimiter_trim.len())
 4591                                        .collect::<String>();
 4592                                    if delimiter_line.starts_with(delimiter_trim) {
 4593                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4594                                    } else {
 4595                                        false
 4596                                    }
 4597                                };
 4598
 4599                                let cursor_is_before_end_tag_if_exists = {
 4600                                    let mut char_position = 0u32;
 4601                                    let mut end_tag_offset = None;
 4602
 4603                                    'outer: for chunk in snapshot.text_for_range(range) {
 4604                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4605                                            let chars_before_match =
 4606                                                chunk[..byte_pos].chars().count() as u32;
 4607                                            end_tag_offset =
 4608                                                Some(char_position + chars_before_match);
 4609                                            break 'outer;
 4610                                        }
 4611                                        char_position += chunk.chars().count() as u32;
 4612                                    }
 4613
 4614                                    if let Some(end_tag_offset) = end_tag_offset {
 4615                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4616                                        if cursor_is_after_start_tag {
 4617                                            if cursor_is_before_end_tag {
 4618                                                insert_extra_newline = true;
 4619                                            }
 4620                                            let cursor_is_at_start_of_end_tag =
 4621                                                column == end_tag_offset;
 4622                                            if cursor_is_at_start_of_end_tag {
 4623                                                indent_on_extra_newline.len = *len;
 4624                                            }
 4625                                        }
 4626                                        cursor_is_before_end_tag
 4627                                    } else {
 4628                                        true
 4629                                    }
 4630                                };
 4631
 4632                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4633                                    && cursor_is_before_end_tag_if_exists
 4634                                {
 4635                                    if cursor_is_after_start_tag {
 4636                                        indent_on_newline.len = *len;
 4637                                    }
 4638                                    Some(delimiter.clone())
 4639                                } else {
 4640                                    None
 4641                                }
 4642                            });
 4643
 4644                            (
 4645                                comment_delimiter,
 4646                                doc_delimiter,
 4647                                insert_extra_newline,
 4648                                indent_on_newline,
 4649                                indent_on_extra_newline,
 4650                            )
 4651                        } else {
 4652                            (
 4653                                None,
 4654                                None,
 4655                                false,
 4656                                IndentSize::default(),
 4657                                IndentSize::default(),
 4658                            )
 4659                        };
 4660
 4661                        let prevent_auto_indent = doc_delimiter.is_some();
 4662                        let delimiter = comment_delimiter.or(doc_delimiter);
 4663
 4664                        let capacity_for_delimiter =
 4665                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4666                        let mut new_text = String::with_capacity(
 4667                            1 + capacity_for_delimiter
 4668                                + existing_indent.len as usize
 4669                                + indent_on_newline.len as usize
 4670                                + indent_on_extra_newline.len as usize,
 4671                        );
 4672                        new_text.push('\n');
 4673                        new_text.extend(existing_indent.chars());
 4674                        new_text.extend(indent_on_newline.chars());
 4675
 4676                        if let Some(delimiter) = &delimiter {
 4677                            new_text.push_str(delimiter);
 4678                        }
 4679
 4680                        if insert_extra_newline {
 4681                            new_text.push('\n');
 4682                            new_text.extend(existing_indent.chars());
 4683                            new_text.extend(indent_on_extra_newline.chars());
 4684                        }
 4685
 4686                        let anchor = buffer.anchor_after(end);
 4687                        let new_selection = selection.map(|_| anchor);
 4688                        (
 4689                            ((start..end, new_text), prevent_auto_indent),
 4690                            (insert_extra_newline, new_selection),
 4691                        )
 4692                    })
 4693                    .unzip()
 4694            };
 4695
 4696            let mut auto_indent_edits = Vec::new();
 4697            let mut edits = Vec::new();
 4698            for (edit, prevent_auto_indent) in edits_with_flags {
 4699                if prevent_auto_indent {
 4700                    edits.push(edit);
 4701                } else {
 4702                    auto_indent_edits.push(edit);
 4703                }
 4704            }
 4705            if !edits.is_empty() {
 4706                this.edit(edits, cx);
 4707            }
 4708            if !auto_indent_edits.is_empty() {
 4709                this.edit_with_autoindent(auto_indent_edits, cx);
 4710            }
 4711
 4712            let buffer = this.buffer.read(cx).snapshot(cx);
 4713            let new_selections = selection_info
 4714                .into_iter()
 4715                .map(|(extra_newline_inserted, new_selection)| {
 4716                    let mut cursor = new_selection.end.to_point(&buffer);
 4717                    if extra_newline_inserted {
 4718                        cursor.row -= 1;
 4719                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4720                    }
 4721                    new_selection.map(|_| cursor)
 4722                })
 4723                .collect();
 4724
 4725            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4726            this.refresh_edit_prediction(true, false, window, cx);
 4727        });
 4728    }
 4729
 4730    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4732
 4733        let buffer = self.buffer.read(cx);
 4734        let snapshot = buffer.snapshot(cx);
 4735
 4736        let mut edits = Vec::new();
 4737        let mut rows = Vec::new();
 4738
 4739        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4740            let cursor = selection.head();
 4741            let row = cursor.row;
 4742
 4743            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4744
 4745            let newline = "\n".to_string();
 4746            edits.push((start_of_line..start_of_line, newline));
 4747
 4748            rows.push(row + rows_inserted as u32);
 4749        }
 4750
 4751        self.transact(window, cx, |editor, window, cx| {
 4752            editor.edit(edits, cx);
 4753
 4754            editor.change_selections(Default::default(), window, cx, |s| {
 4755                let mut index = 0;
 4756                s.move_cursors_with(|map, _, _| {
 4757                    let row = rows[index];
 4758                    index += 1;
 4759
 4760                    let point = Point::new(row, 0);
 4761                    let boundary = map.next_line_boundary(point).1;
 4762                    let clipped = map.clip_point(boundary, Bias::Left);
 4763
 4764                    (clipped, SelectionGoal::None)
 4765                });
 4766            });
 4767
 4768            let mut indent_edits = Vec::new();
 4769            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4770            for row in rows {
 4771                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4772                for (row, indent) in indents {
 4773                    if indent.len == 0 {
 4774                        continue;
 4775                    }
 4776
 4777                    let text = match indent.kind {
 4778                        IndentKind::Space => " ".repeat(indent.len as usize),
 4779                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4780                    };
 4781                    let point = Point::new(row.0, 0);
 4782                    indent_edits.push((point..point, text));
 4783                }
 4784            }
 4785            editor.edit(indent_edits, cx);
 4786        });
 4787    }
 4788
 4789    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4791
 4792        let buffer = self.buffer.read(cx);
 4793        let snapshot = buffer.snapshot(cx);
 4794
 4795        let mut edits = Vec::new();
 4796        let mut rows = Vec::new();
 4797        let mut rows_inserted = 0;
 4798
 4799        for selection in self.selections.all_adjusted(cx) {
 4800            let cursor = selection.head();
 4801            let row = cursor.row;
 4802
 4803            let point = Point::new(row + 1, 0);
 4804            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4805
 4806            let newline = "\n".to_string();
 4807            edits.push((start_of_line..start_of_line, newline));
 4808
 4809            rows_inserted += 1;
 4810            rows.push(row + rows_inserted);
 4811        }
 4812
 4813        self.transact(window, cx, |editor, window, cx| {
 4814            editor.edit(edits, cx);
 4815
 4816            editor.change_selections(Default::default(), window, cx, |s| {
 4817                let mut index = 0;
 4818                s.move_cursors_with(|map, _, _| {
 4819                    let row = rows[index];
 4820                    index += 1;
 4821
 4822                    let point = Point::new(row, 0);
 4823                    let boundary = map.next_line_boundary(point).1;
 4824                    let clipped = map.clip_point(boundary, Bias::Left);
 4825
 4826                    (clipped, SelectionGoal::None)
 4827                });
 4828            });
 4829
 4830            let mut indent_edits = Vec::new();
 4831            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4832            for row in rows {
 4833                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4834                for (row, indent) in indents {
 4835                    if indent.len == 0 {
 4836                        continue;
 4837                    }
 4838
 4839                    let text = match indent.kind {
 4840                        IndentKind::Space => " ".repeat(indent.len as usize),
 4841                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4842                    };
 4843                    let point = Point::new(row.0, 0);
 4844                    indent_edits.push((point..point, text));
 4845                }
 4846            }
 4847            editor.edit(indent_edits, cx);
 4848        });
 4849    }
 4850
 4851    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4852        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4853            original_indent_columns: Vec::new(),
 4854        });
 4855        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4856    }
 4857
 4858    fn insert_with_autoindent_mode(
 4859        &mut self,
 4860        text: &str,
 4861        autoindent_mode: Option<AutoindentMode>,
 4862        window: &mut Window,
 4863        cx: &mut Context<Self>,
 4864    ) {
 4865        if self.read_only(cx) {
 4866            return;
 4867        }
 4868
 4869        let text: Arc<str> = text.into();
 4870        self.transact(window, cx, |this, window, cx| {
 4871            let old_selections = this.selections.all_adjusted(cx);
 4872            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4873                let anchors = {
 4874                    let snapshot = buffer.read(cx);
 4875                    old_selections
 4876                        .iter()
 4877                        .map(|s| {
 4878                            let anchor = snapshot.anchor_after(s.head());
 4879                            s.map(|_| anchor)
 4880                        })
 4881                        .collect::<Vec<_>>()
 4882                };
 4883                buffer.edit(
 4884                    old_selections
 4885                        .iter()
 4886                        .map(|s| (s.start..s.end, text.clone())),
 4887                    autoindent_mode,
 4888                    cx,
 4889                );
 4890                anchors
 4891            });
 4892
 4893            this.change_selections(Default::default(), window, cx, |s| {
 4894                s.select_anchors(selection_anchors);
 4895            });
 4896
 4897            cx.notify();
 4898        });
 4899    }
 4900
 4901    fn trigger_completion_on_input(
 4902        &mut self,
 4903        text: &str,
 4904        trigger_in_words: bool,
 4905        window: &mut Window,
 4906        cx: &mut Context<Self>,
 4907    ) {
 4908        let completions_source = self
 4909            .context_menu
 4910            .borrow()
 4911            .as_ref()
 4912            .and_then(|menu| match menu {
 4913                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4914                CodeContextMenu::CodeActions(_) => None,
 4915            });
 4916
 4917        match completions_source {
 4918            Some(CompletionsMenuSource::Words { .. }) => {
 4919                self.open_or_update_completions_menu(
 4920                    Some(CompletionsMenuSource::Words {
 4921                        ignore_threshold: false,
 4922                    }),
 4923                    None,
 4924                    window,
 4925                    cx,
 4926                );
 4927            }
 4928            Some(CompletionsMenuSource::Normal)
 4929            | Some(CompletionsMenuSource::SnippetChoices)
 4930            | None
 4931                if self.is_completion_trigger(
 4932                    text,
 4933                    trigger_in_words,
 4934                    completions_source.is_some(),
 4935                    cx,
 4936                ) =>
 4937            {
 4938                self.show_completions(
 4939                    &ShowCompletions {
 4940                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4941                    },
 4942                    window,
 4943                    cx,
 4944                )
 4945            }
 4946            _ => {
 4947                self.hide_context_menu(window, cx);
 4948            }
 4949        }
 4950    }
 4951
 4952    fn is_completion_trigger(
 4953        &self,
 4954        text: &str,
 4955        trigger_in_words: bool,
 4956        menu_is_open: bool,
 4957        cx: &mut Context<Self>,
 4958    ) -> bool {
 4959        let position = self.selections.newest_anchor().head();
 4960        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4961            return false;
 4962        };
 4963
 4964        if let Some(completion_provider) = &self.completion_provider {
 4965            completion_provider.is_completion_trigger(
 4966                &buffer,
 4967                position.text_anchor,
 4968                text,
 4969                trigger_in_words,
 4970                menu_is_open,
 4971                cx,
 4972            )
 4973        } else {
 4974            false
 4975        }
 4976    }
 4977
 4978    /// If any empty selections is touching the start of its innermost containing autoclose
 4979    /// region, expand it to select the brackets.
 4980    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4981        let selections = self.selections.all::<usize>(cx);
 4982        let buffer = self.buffer.read(cx).read(cx);
 4983        let new_selections = self
 4984            .selections_with_autoclose_regions(selections, &buffer)
 4985            .map(|(mut selection, region)| {
 4986                if !selection.is_empty() {
 4987                    return selection;
 4988                }
 4989
 4990                if let Some(region) = region {
 4991                    let mut range = region.range.to_offset(&buffer);
 4992                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4993                        range.start -= region.pair.start.len();
 4994                        if buffer.contains_str_at(range.start, &region.pair.start)
 4995                            && buffer.contains_str_at(range.end, &region.pair.end)
 4996                        {
 4997                            range.end += region.pair.end.len();
 4998                            selection.start = range.start;
 4999                            selection.end = range.end;
 5000
 5001                            return selection;
 5002                        }
 5003                    }
 5004                }
 5005
 5006                let always_treat_brackets_as_autoclosed = buffer
 5007                    .language_settings_at(selection.start, cx)
 5008                    .always_treat_brackets_as_autoclosed;
 5009
 5010                if !always_treat_brackets_as_autoclosed {
 5011                    return selection;
 5012                }
 5013
 5014                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5015                    for (pair, enabled) in scope.brackets() {
 5016                        if !enabled || !pair.close {
 5017                            continue;
 5018                        }
 5019
 5020                        if buffer.contains_str_at(selection.start, &pair.end) {
 5021                            let pair_start_len = pair.start.len();
 5022                            if buffer.contains_str_at(
 5023                                selection.start.saturating_sub(pair_start_len),
 5024                                &pair.start,
 5025                            ) {
 5026                                selection.start -= pair_start_len;
 5027                                selection.end += pair.end.len();
 5028
 5029                                return selection;
 5030                            }
 5031                        }
 5032                    }
 5033                }
 5034
 5035                selection
 5036            })
 5037            .collect();
 5038
 5039        drop(buffer);
 5040        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5041            selections.select(new_selections)
 5042        });
 5043    }
 5044
 5045    /// Iterate the given selections, and for each one, find the smallest surrounding
 5046    /// autoclose region. This uses the ordering of the selections and the autoclose
 5047    /// regions to avoid repeated comparisons.
 5048    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5049        &'a self,
 5050        selections: impl IntoIterator<Item = Selection<D>>,
 5051        buffer: &'a MultiBufferSnapshot,
 5052    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5053        let mut i = 0;
 5054        let mut regions = self.autoclose_regions.as_slice();
 5055        selections.into_iter().map(move |selection| {
 5056            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5057
 5058            let mut enclosing = None;
 5059            while let Some(pair_state) = regions.get(i) {
 5060                if pair_state.range.end.to_offset(buffer) < range.start {
 5061                    regions = &regions[i + 1..];
 5062                    i = 0;
 5063                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5064                    break;
 5065                } else {
 5066                    if pair_state.selection_id == selection.id {
 5067                        enclosing = Some(pair_state);
 5068                    }
 5069                    i += 1;
 5070                }
 5071            }
 5072
 5073            (selection, enclosing)
 5074        })
 5075    }
 5076
 5077    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5078    fn invalidate_autoclose_regions(
 5079        &mut self,
 5080        mut selections: &[Selection<Anchor>],
 5081        buffer: &MultiBufferSnapshot,
 5082    ) {
 5083        self.autoclose_regions.retain(|state| {
 5084            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5085                return false;
 5086            }
 5087
 5088            let mut i = 0;
 5089            while let Some(selection) = selections.get(i) {
 5090                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5091                    selections = &selections[1..];
 5092                    continue;
 5093                }
 5094                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5095                    break;
 5096                }
 5097                if selection.id == state.selection_id {
 5098                    return true;
 5099                } else {
 5100                    i += 1;
 5101                }
 5102            }
 5103            false
 5104        });
 5105    }
 5106
 5107    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5108        let offset = position.to_offset(buffer);
 5109        let (word_range, kind) =
 5110            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5111        if offset > word_range.start && kind == Some(CharKind::Word) {
 5112            Some(
 5113                buffer
 5114                    .text_for_range(word_range.start..offset)
 5115                    .collect::<String>(),
 5116            )
 5117        } else {
 5118            None
 5119        }
 5120    }
 5121
 5122    pub fn toggle_inline_values(
 5123        &mut self,
 5124        _: &ToggleInlineValues,
 5125        _: &mut Window,
 5126        cx: &mut Context<Self>,
 5127    ) {
 5128        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5129
 5130        self.refresh_inline_values(cx);
 5131    }
 5132
 5133    pub fn toggle_inlay_hints(
 5134        &mut self,
 5135        _: &ToggleInlayHints,
 5136        _: &mut Window,
 5137        cx: &mut Context<Self>,
 5138    ) {
 5139        self.refresh_inlay_hints(
 5140            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5141            cx,
 5142        );
 5143    }
 5144
 5145    pub fn inlay_hints_enabled(&self) -> bool {
 5146        self.inlay_hint_cache.enabled
 5147    }
 5148
 5149    pub fn inline_values_enabled(&self) -> bool {
 5150        self.inline_value_cache.enabled
 5151    }
 5152
 5153    #[cfg(any(test, feature = "test-support"))]
 5154    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5155        self.display_map
 5156            .read(cx)
 5157            .current_inlays()
 5158            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5159            .cloned()
 5160            .collect()
 5161    }
 5162
 5163    #[cfg(any(test, feature = "test-support"))]
 5164    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5165        self.display_map
 5166            .read(cx)
 5167            .current_inlays()
 5168            .cloned()
 5169            .collect()
 5170    }
 5171
 5172    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5173        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5174            return;
 5175        }
 5176
 5177        let reason_description = reason.description();
 5178        let ignore_debounce = matches!(
 5179            reason,
 5180            InlayHintRefreshReason::SettingsChange(_)
 5181                | InlayHintRefreshReason::Toggle(_)
 5182                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5183                | InlayHintRefreshReason::ModifiersChanged(_)
 5184        );
 5185        let (invalidate_cache, required_languages) = match reason {
 5186            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5187                match self.inlay_hint_cache.modifiers_override(enabled) {
 5188                    Some(enabled) => {
 5189                        if enabled {
 5190                            (InvalidationStrategy::RefreshRequested, None)
 5191                        } else {
 5192                            self.splice_inlays(
 5193                                &self
 5194                                    .visible_inlay_hints(cx)
 5195                                    .iter()
 5196                                    .map(|inlay| inlay.id)
 5197                                    .collect::<Vec<InlayId>>(),
 5198                                Vec::new(),
 5199                                cx,
 5200                            );
 5201                            return;
 5202                        }
 5203                    }
 5204                    None => return,
 5205                }
 5206            }
 5207            InlayHintRefreshReason::Toggle(enabled) => {
 5208                if self.inlay_hint_cache.toggle(enabled) {
 5209                    if enabled {
 5210                        (InvalidationStrategy::RefreshRequested, None)
 5211                    } else {
 5212                        self.splice_inlays(
 5213                            &self
 5214                                .visible_inlay_hints(cx)
 5215                                .iter()
 5216                                .map(|inlay| inlay.id)
 5217                                .collect::<Vec<InlayId>>(),
 5218                            Vec::new(),
 5219                            cx,
 5220                        );
 5221                        return;
 5222                    }
 5223                } else {
 5224                    return;
 5225                }
 5226            }
 5227            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5228                match self.inlay_hint_cache.update_settings(
 5229                    &self.buffer,
 5230                    new_settings,
 5231                    self.visible_inlay_hints(cx),
 5232                    cx,
 5233                ) {
 5234                    ControlFlow::Break(Some(InlaySplice {
 5235                        to_remove,
 5236                        to_insert,
 5237                    })) => {
 5238                        self.splice_inlays(&to_remove, to_insert, cx);
 5239                        return;
 5240                    }
 5241                    ControlFlow::Break(None) => return,
 5242                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5243                }
 5244            }
 5245            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5246                if let Some(InlaySplice {
 5247                    to_remove,
 5248                    to_insert,
 5249                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5250                {
 5251                    self.splice_inlays(&to_remove, to_insert, cx);
 5252                }
 5253                self.display_map.update(cx, |display_map, _| {
 5254                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5255                });
 5256                return;
 5257            }
 5258            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5259            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5260                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5261            }
 5262            InlayHintRefreshReason::RefreshRequested => {
 5263                (InvalidationStrategy::RefreshRequested, None)
 5264            }
 5265        };
 5266
 5267        if let Some(InlaySplice {
 5268            to_remove,
 5269            to_insert,
 5270        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5271            reason_description,
 5272            self.visible_excerpts(required_languages.as_ref(), cx),
 5273            invalidate_cache,
 5274            ignore_debounce,
 5275            cx,
 5276        ) {
 5277            self.splice_inlays(&to_remove, to_insert, cx);
 5278        }
 5279    }
 5280
 5281    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5282        self.display_map
 5283            .read(cx)
 5284            .current_inlays()
 5285            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5286            .cloned()
 5287            .collect()
 5288    }
 5289
 5290    pub fn visible_excerpts(
 5291        &self,
 5292        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5293        cx: &mut Context<Editor>,
 5294    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5295        let Some(project) = self.project() else {
 5296            return HashMap::default();
 5297        };
 5298        let project = project.read(cx);
 5299        let multi_buffer = self.buffer().read(cx);
 5300        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5301        let multi_buffer_visible_start = self
 5302            .scroll_manager
 5303            .anchor()
 5304            .anchor
 5305            .to_point(&multi_buffer_snapshot);
 5306        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5307            multi_buffer_visible_start
 5308                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5309            Bias::Left,
 5310        );
 5311        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5312        multi_buffer_snapshot
 5313            .range_to_buffer_ranges(multi_buffer_visible_range)
 5314            .into_iter()
 5315            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5316            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5317                let buffer_file = project::File::from_dyn(buffer.file())?;
 5318                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5319                let worktree_entry = buffer_worktree
 5320                    .read(cx)
 5321                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5322                if worktree_entry.is_ignored {
 5323                    return None;
 5324                }
 5325
 5326                let language = buffer.language()?;
 5327                if let Some(restrict_to_languages) = restrict_to_languages
 5328                    && !restrict_to_languages.contains(language)
 5329                {
 5330                    return None;
 5331                }
 5332                Some((
 5333                    excerpt_id,
 5334                    (
 5335                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5336                        buffer.version().clone(),
 5337                        excerpt_visible_range,
 5338                    ),
 5339                ))
 5340            })
 5341            .collect()
 5342    }
 5343
 5344    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5345        TextLayoutDetails {
 5346            text_system: window.text_system().clone(),
 5347            editor_style: self.style.clone().unwrap(),
 5348            rem_size: window.rem_size(),
 5349            scroll_anchor: self.scroll_manager.anchor(),
 5350            visible_rows: self.visible_line_count(),
 5351            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5352        }
 5353    }
 5354
 5355    pub fn splice_inlays(
 5356        &self,
 5357        to_remove: &[InlayId],
 5358        to_insert: Vec<Inlay>,
 5359        cx: &mut Context<Self>,
 5360    ) {
 5361        self.display_map.update(cx, |display_map, cx| {
 5362            display_map.splice_inlays(to_remove, to_insert, cx)
 5363        });
 5364        cx.notify();
 5365    }
 5366
 5367    fn trigger_on_type_formatting(
 5368        &self,
 5369        input: String,
 5370        window: &mut Window,
 5371        cx: &mut Context<Self>,
 5372    ) -> Option<Task<Result<()>>> {
 5373        if input.len() != 1 {
 5374            return None;
 5375        }
 5376
 5377        let project = self.project()?;
 5378        let position = self.selections.newest_anchor().head();
 5379        let (buffer, buffer_position) = self
 5380            .buffer
 5381            .read(cx)
 5382            .text_anchor_for_position(position, cx)?;
 5383
 5384        let settings = language_settings::language_settings(
 5385            buffer
 5386                .read(cx)
 5387                .language_at(buffer_position)
 5388                .map(|l| l.name()),
 5389            buffer.read(cx).file(),
 5390            cx,
 5391        );
 5392        if !settings.use_on_type_format {
 5393            return None;
 5394        }
 5395
 5396        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5397        // hence we do LSP request & edit on host side only — add formats to host's history.
 5398        let push_to_lsp_host_history = true;
 5399        // If this is not the host, append its history with new edits.
 5400        let push_to_client_history = project.read(cx).is_via_collab();
 5401
 5402        let on_type_formatting = project.update(cx, |project, cx| {
 5403            project.on_type_format(
 5404                buffer.clone(),
 5405                buffer_position,
 5406                input,
 5407                push_to_lsp_host_history,
 5408                cx,
 5409            )
 5410        });
 5411        Some(cx.spawn_in(window, async move |editor, cx| {
 5412            if let Some(transaction) = on_type_formatting.await? {
 5413                if push_to_client_history {
 5414                    buffer
 5415                        .update(cx, |buffer, _| {
 5416                            buffer.push_transaction(transaction, Instant::now());
 5417                            buffer.finalize_last_transaction();
 5418                        })
 5419                        .ok();
 5420                }
 5421                editor.update(cx, |editor, cx| {
 5422                    editor.refresh_document_highlights(cx);
 5423                })?;
 5424            }
 5425            Ok(())
 5426        }))
 5427    }
 5428
 5429    pub fn show_word_completions(
 5430        &mut self,
 5431        _: &ShowWordCompletions,
 5432        window: &mut Window,
 5433        cx: &mut Context<Self>,
 5434    ) {
 5435        self.open_or_update_completions_menu(
 5436            Some(CompletionsMenuSource::Words {
 5437                ignore_threshold: true,
 5438            }),
 5439            None,
 5440            window,
 5441            cx,
 5442        );
 5443    }
 5444
 5445    pub fn show_completions(
 5446        &mut self,
 5447        options: &ShowCompletions,
 5448        window: &mut Window,
 5449        cx: &mut Context<Self>,
 5450    ) {
 5451        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5452    }
 5453
 5454    fn open_or_update_completions_menu(
 5455        &mut self,
 5456        requested_source: Option<CompletionsMenuSource>,
 5457        trigger: Option<&str>,
 5458        window: &mut Window,
 5459        cx: &mut Context<Self>,
 5460    ) {
 5461        if self.pending_rename.is_some() {
 5462            return;
 5463        }
 5464
 5465        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5466
 5467        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5468        // inserted and selected. To handle that case, the start of the selection is used so that
 5469        // the menu starts with all choices.
 5470        let position = self
 5471            .selections
 5472            .newest_anchor()
 5473            .start
 5474            .bias_right(&multibuffer_snapshot);
 5475        if position.diff_base_anchor.is_some() {
 5476            return;
 5477        }
 5478        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5479        let Some(buffer) = buffer_position
 5480            .buffer_id
 5481            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5482        else {
 5483            return;
 5484        };
 5485        let buffer_snapshot = buffer.read(cx).snapshot();
 5486
 5487        let query: Option<Arc<String>> =
 5488            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5489                .map(|query| query.into());
 5490
 5491        drop(multibuffer_snapshot);
 5492
 5493        // Hide the current completions menu when query is empty. Without this, cached
 5494        // completions from before the trigger char may be reused (#32774).
 5495        if query.is_none() {
 5496            let menu_is_open = matches!(
 5497                self.context_menu.borrow().as_ref(),
 5498                Some(CodeContextMenu::Completions(_))
 5499            );
 5500            if menu_is_open {
 5501                self.hide_context_menu(window, cx);
 5502            }
 5503        }
 5504
 5505        let mut ignore_word_threshold = false;
 5506        let provider = match requested_source {
 5507            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5508            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5509                ignore_word_threshold = ignore_threshold;
 5510                None
 5511            }
 5512            Some(CompletionsMenuSource::SnippetChoices) => {
 5513                log::error!("bug: SnippetChoices requested_source is not handled");
 5514                None
 5515            }
 5516        };
 5517
 5518        let sort_completions = provider
 5519            .as_ref()
 5520            .is_some_and(|provider| provider.sort_completions());
 5521
 5522        let filter_completions = provider
 5523            .as_ref()
 5524            .is_none_or(|provider| provider.filter_completions());
 5525
 5526        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5527            if filter_completions {
 5528                menu.filter(query.clone(), provider.clone(), window, cx);
 5529            }
 5530            // When `is_incomplete` is false, no need to re-query completions when the current query
 5531            // is a suffix of the initial query.
 5532            if !menu.is_incomplete {
 5533                // If the new query is a suffix of the old query (typing more characters) and
 5534                // the previous result was complete, the existing completions can be filtered.
 5535                //
 5536                // Note that this is always true for snippet completions.
 5537                let query_matches = match (&menu.initial_query, &query) {
 5538                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5539                    (None, _) => true,
 5540                    _ => false,
 5541                };
 5542                if query_matches {
 5543                    let position_matches = if menu.initial_position == position {
 5544                        true
 5545                    } else {
 5546                        let snapshot = self.buffer.read(cx).read(cx);
 5547                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5548                    };
 5549                    if position_matches {
 5550                        return;
 5551                    }
 5552                }
 5553            }
 5554        };
 5555
 5556        let trigger_kind = match trigger {
 5557            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5558                CompletionTriggerKind::TRIGGER_CHARACTER
 5559            }
 5560            _ => CompletionTriggerKind::INVOKED,
 5561        };
 5562        let completion_context = CompletionContext {
 5563            trigger_character: trigger.and_then(|trigger| {
 5564                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5565                    Some(String::from(trigger))
 5566                } else {
 5567                    None
 5568                }
 5569            }),
 5570            trigger_kind,
 5571        };
 5572
 5573        let Anchor {
 5574            excerpt_id: buffer_excerpt_id,
 5575            text_anchor: buffer_position,
 5576            ..
 5577        } = buffer_position;
 5578
 5579        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5580            buffer_snapshot.surrounding_word(buffer_position, None)
 5581        {
 5582            let word_to_exclude = buffer_snapshot
 5583                .text_for_range(word_range.clone())
 5584                .collect::<String>();
 5585            (
 5586                buffer_snapshot.anchor_before(word_range.start)
 5587                    ..buffer_snapshot.anchor_after(buffer_position),
 5588                Some(word_to_exclude),
 5589            )
 5590        } else {
 5591            (buffer_position..buffer_position, None)
 5592        };
 5593
 5594        let language = buffer_snapshot
 5595            .language_at(buffer_position)
 5596            .map(|language| language.name());
 5597
 5598        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5599            .completions
 5600            .clone();
 5601
 5602        let show_completion_documentation = buffer_snapshot
 5603            .settings_at(buffer_position, cx)
 5604            .show_completion_documentation;
 5605
 5606        // The document can be large, so stay in reasonable bounds when searching for words,
 5607        // otherwise completion pop-up might be slow to appear.
 5608        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5609        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5610        let min_word_search = buffer_snapshot.clip_point(
 5611            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5612            Bias::Left,
 5613        );
 5614        let max_word_search = buffer_snapshot.clip_point(
 5615            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5616            Bias::Right,
 5617        );
 5618        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5619            ..buffer_snapshot.point_to_offset(max_word_search);
 5620
 5621        let skip_digits = query
 5622            .as_ref()
 5623            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5624
 5625        let omit_word_completions = !self.word_completions_enabled
 5626            || (!ignore_word_threshold
 5627                && match &query {
 5628                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5629                    None => completion_settings.words_min_length != 0,
 5630                });
 5631
 5632        let (mut words, provider_responses) = match &provider {
 5633            Some(provider) => {
 5634                let provider_responses = provider.completions(
 5635                    buffer_excerpt_id,
 5636                    &buffer,
 5637                    buffer_position,
 5638                    completion_context,
 5639                    window,
 5640                    cx,
 5641                );
 5642
 5643                let words = match (omit_word_completions, completion_settings.words) {
 5644                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5645                        Task::ready(BTreeMap::default())
 5646                    }
 5647                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5648                        .background_spawn(async move {
 5649                            buffer_snapshot.words_in_range(WordsQuery {
 5650                                fuzzy_contents: None,
 5651                                range: word_search_range,
 5652                                skip_digits,
 5653                            })
 5654                        }),
 5655                };
 5656
 5657                (words, provider_responses)
 5658            }
 5659            None => {
 5660                let words = if omit_word_completions {
 5661                    Task::ready(BTreeMap::default())
 5662                } else {
 5663                    cx.background_spawn(async move {
 5664                        buffer_snapshot.words_in_range(WordsQuery {
 5665                            fuzzy_contents: None,
 5666                            range: word_search_range,
 5667                            skip_digits,
 5668                        })
 5669                    })
 5670                };
 5671                (words, Task::ready(Ok(Vec::new())))
 5672            }
 5673        };
 5674
 5675        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5676
 5677        let id = post_inc(&mut self.next_completion_id);
 5678        let task = cx.spawn_in(window, async move |editor, cx| {
 5679            let Ok(()) = editor.update(cx, |this, _| {
 5680                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5681            }) else {
 5682                return;
 5683            };
 5684
 5685            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5686            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5687            let mut completions = Vec::new();
 5688            let mut is_incomplete = false;
 5689            let mut display_options: Option<CompletionDisplayOptions> = None;
 5690            if let Some(provider_responses) = provider_responses.await.log_err()
 5691                && !provider_responses.is_empty()
 5692            {
 5693                for response in provider_responses {
 5694                    completions.extend(response.completions);
 5695                    is_incomplete = is_incomplete || response.is_incomplete;
 5696                    match display_options.as_mut() {
 5697                        None => {
 5698                            display_options = Some(response.display_options);
 5699                        }
 5700                        Some(options) => options.merge(&response.display_options),
 5701                    }
 5702                }
 5703                if completion_settings.words == WordsCompletionMode::Fallback {
 5704                    words = Task::ready(BTreeMap::default());
 5705                }
 5706            }
 5707            let display_options = display_options.unwrap_or_default();
 5708
 5709            let mut words = words.await;
 5710            if let Some(word_to_exclude) = &word_to_exclude {
 5711                words.remove(word_to_exclude);
 5712            }
 5713            for lsp_completion in &completions {
 5714                words.remove(&lsp_completion.new_text);
 5715            }
 5716            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5717                replace_range: word_replace_range.clone(),
 5718                new_text: word.clone(),
 5719                label: CodeLabel::plain(word, None),
 5720                icon_path: None,
 5721                documentation: None,
 5722                source: CompletionSource::BufferWord {
 5723                    word_range,
 5724                    resolved: false,
 5725                },
 5726                insert_text_mode: Some(InsertTextMode::AS_IS),
 5727                confirm: None,
 5728            }));
 5729
 5730            let menu = if completions.is_empty() {
 5731                None
 5732            } else {
 5733                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5734                    let languages = editor
 5735                        .workspace
 5736                        .as_ref()
 5737                        .and_then(|(workspace, _)| workspace.upgrade())
 5738                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5739                    let menu = CompletionsMenu::new(
 5740                        id,
 5741                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5742                        sort_completions,
 5743                        show_completion_documentation,
 5744                        position,
 5745                        query.clone(),
 5746                        is_incomplete,
 5747                        buffer.clone(),
 5748                        completions.into(),
 5749                        display_options,
 5750                        snippet_sort_order,
 5751                        languages,
 5752                        language,
 5753                        cx,
 5754                    );
 5755
 5756                    let query = if filter_completions { query } else { None };
 5757                    let matches_task = if let Some(query) = query {
 5758                        menu.do_async_filtering(query, cx)
 5759                    } else {
 5760                        Task::ready(menu.unfiltered_matches())
 5761                    };
 5762                    (menu, matches_task)
 5763                }) else {
 5764                    return;
 5765                };
 5766
 5767                let matches = matches_task.await;
 5768
 5769                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5770                    // Newer menu already set, so exit.
 5771                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5772                        editor.context_menu.borrow().as_ref()
 5773                        && prev_menu.id > id
 5774                    {
 5775                        return;
 5776                    };
 5777
 5778                    // Only valid to take prev_menu because it the new menu is immediately set
 5779                    // below, or the menu is hidden.
 5780                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5781                        editor.context_menu.borrow_mut().take()
 5782                    {
 5783                        let position_matches =
 5784                            if prev_menu.initial_position == menu.initial_position {
 5785                                true
 5786                            } else {
 5787                                let snapshot = editor.buffer.read(cx).read(cx);
 5788                                prev_menu.initial_position.to_offset(&snapshot)
 5789                                    == menu.initial_position.to_offset(&snapshot)
 5790                            };
 5791                        if position_matches {
 5792                            // Preserve markdown cache before `set_filter_results` because it will
 5793                            // try to populate the documentation cache.
 5794                            menu.preserve_markdown_cache(prev_menu);
 5795                        }
 5796                    };
 5797
 5798                    menu.set_filter_results(matches, provider, window, cx);
 5799                }) else {
 5800                    return;
 5801                };
 5802
 5803                menu.visible().then_some(menu)
 5804            };
 5805
 5806            editor
 5807                .update_in(cx, |editor, window, cx| {
 5808                    if editor.focus_handle.is_focused(window)
 5809                        && let Some(menu) = menu
 5810                    {
 5811                        *editor.context_menu.borrow_mut() =
 5812                            Some(CodeContextMenu::Completions(menu));
 5813
 5814                        crate::hover_popover::hide_hover(editor, cx);
 5815                        if editor.show_edit_predictions_in_menu() {
 5816                            editor.update_visible_edit_prediction(window, cx);
 5817                        } else {
 5818                            editor.discard_edit_prediction(false, cx);
 5819                        }
 5820
 5821                        cx.notify();
 5822                        return;
 5823                    }
 5824
 5825                    if editor.completion_tasks.len() <= 1 {
 5826                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5827                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5828                        // If it was already hidden and we don't show edit predictions in the menu,
 5829                        // we should also show the edit prediction when available.
 5830                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5831                            editor.update_visible_edit_prediction(window, cx);
 5832                        }
 5833                    }
 5834                })
 5835                .ok();
 5836        });
 5837
 5838        self.completion_tasks.push((id, task));
 5839    }
 5840
 5841    #[cfg(feature = "test-support")]
 5842    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5843        let menu = self.context_menu.borrow();
 5844        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5845            let completions = menu.completions.borrow();
 5846            Some(completions.to_vec())
 5847        } else {
 5848            None
 5849        }
 5850    }
 5851
 5852    pub fn with_completions_menu_matching_id<R>(
 5853        &self,
 5854        id: CompletionId,
 5855        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5856    ) -> R {
 5857        let mut context_menu = self.context_menu.borrow_mut();
 5858        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5859            return f(None);
 5860        };
 5861        if completions_menu.id != id {
 5862            return f(None);
 5863        }
 5864        f(Some(completions_menu))
 5865    }
 5866
 5867    pub fn confirm_completion(
 5868        &mut self,
 5869        action: &ConfirmCompletion,
 5870        window: &mut Window,
 5871        cx: &mut Context<Self>,
 5872    ) -> Option<Task<Result<()>>> {
 5873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5874        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5875    }
 5876
 5877    pub fn confirm_completion_insert(
 5878        &mut self,
 5879        _: &ConfirmCompletionInsert,
 5880        window: &mut Window,
 5881        cx: &mut Context<Self>,
 5882    ) -> Option<Task<Result<()>>> {
 5883        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5884        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5885    }
 5886
 5887    pub fn confirm_completion_replace(
 5888        &mut self,
 5889        _: &ConfirmCompletionReplace,
 5890        window: &mut Window,
 5891        cx: &mut Context<Self>,
 5892    ) -> Option<Task<Result<()>>> {
 5893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5894        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5895    }
 5896
 5897    pub fn compose_completion(
 5898        &mut self,
 5899        action: &ComposeCompletion,
 5900        window: &mut Window,
 5901        cx: &mut Context<Self>,
 5902    ) -> Option<Task<Result<()>>> {
 5903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5904        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5905    }
 5906
 5907    fn do_completion(
 5908        &mut self,
 5909        item_ix: Option<usize>,
 5910        intent: CompletionIntent,
 5911        window: &mut Window,
 5912        cx: &mut Context<Editor>,
 5913    ) -> Option<Task<Result<()>>> {
 5914        use language::ToOffset as _;
 5915
 5916        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5917        else {
 5918            return None;
 5919        };
 5920
 5921        let candidate_id = {
 5922            let entries = completions_menu.entries.borrow();
 5923            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5924            if self.show_edit_predictions_in_menu() {
 5925                self.discard_edit_prediction(true, cx);
 5926            }
 5927            mat.candidate_id
 5928        };
 5929
 5930        let completion = completions_menu
 5931            .completions
 5932            .borrow()
 5933            .get(candidate_id)?
 5934            .clone();
 5935        cx.stop_propagation();
 5936
 5937        let buffer_handle = completions_menu.buffer.clone();
 5938
 5939        let CompletionEdit {
 5940            new_text,
 5941            snippet,
 5942            replace_range,
 5943        } = process_completion_for_edit(
 5944            &completion,
 5945            intent,
 5946            &buffer_handle,
 5947            &completions_menu.initial_position.text_anchor,
 5948            cx,
 5949        );
 5950
 5951        let buffer = buffer_handle.read(cx);
 5952        let snapshot = self.buffer.read(cx).snapshot(cx);
 5953        let newest_anchor = self.selections.newest_anchor();
 5954        let replace_range_multibuffer = {
 5955            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5956            let multibuffer_anchor = snapshot
 5957                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5958                .unwrap()
 5959                ..snapshot
 5960                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5961                    .unwrap();
 5962            multibuffer_anchor.start.to_offset(&snapshot)
 5963                ..multibuffer_anchor.end.to_offset(&snapshot)
 5964        };
 5965        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5966            return None;
 5967        }
 5968
 5969        let old_text = buffer
 5970            .text_for_range(replace_range.clone())
 5971            .collect::<String>();
 5972        let lookbehind = newest_anchor
 5973            .start
 5974            .text_anchor
 5975            .to_offset(buffer)
 5976            .saturating_sub(replace_range.start);
 5977        let lookahead = replace_range
 5978            .end
 5979            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5980        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5981        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5982
 5983        let selections = self.selections.all::<usize>(cx);
 5984        let mut ranges = Vec::new();
 5985        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5986
 5987        for selection in &selections {
 5988            let range = if selection.id == newest_anchor.id {
 5989                replace_range_multibuffer.clone()
 5990            } else {
 5991                let mut range = selection.range();
 5992
 5993                // if prefix is present, don't duplicate it
 5994                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5995                    range.start = range.start.saturating_sub(lookbehind);
 5996
 5997                    // if suffix is also present, mimic the newest cursor and replace it
 5998                    if selection.id != newest_anchor.id
 5999                        && snapshot.contains_str_at(range.end, suffix)
 6000                    {
 6001                        range.end += lookahead;
 6002                    }
 6003                }
 6004                range
 6005            };
 6006
 6007            ranges.push(range.clone());
 6008
 6009            if !self.linked_edit_ranges.is_empty() {
 6010                let start_anchor = snapshot.anchor_before(range.start);
 6011                let end_anchor = snapshot.anchor_after(range.end);
 6012                if let Some(ranges) = self
 6013                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6014                {
 6015                    for (buffer, edits) in ranges {
 6016                        linked_edits
 6017                            .entry(buffer.clone())
 6018                            .or_default()
 6019                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6020                    }
 6021                }
 6022            }
 6023        }
 6024
 6025        let common_prefix_len = old_text
 6026            .chars()
 6027            .zip(new_text.chars())
 6028            .take_while(|(a, b)| a == b)
 6029            .map(|(a, _)| a.len_utf8())
 6030            .sum::<usize>();
 6031
 6032        cx.emit(EditorEvent::InputHandled {
 6033            utf16_range_to_replace: None,
 6034            text: new_text[common_prefix_len..].into(),
 6035        });
 6036
 6037        self.transact(window, cx, |editor, window, cx| {
 6038            if let Some(mut snippet) = snippet {
 6039                snippet.text = new_text.to_string();
 6040                editor
 6041                    .insert_snippet(&ranges, snippet, window, cx)
 6042                    .log_err();
 6043            } else {
 6044                editor.buffer.update(cx, |multi_buffer, cx| {
 6045                    let auto_indent = match completion.insert_text_mode {
 6046                        Some(InsertTextMode::AS_IS) => None,
 6047                        _ => editor.autoindent_mode.clone(),
 6048                    };
 6049                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6050                    multi_buffer.edit(edits, auto_indent, cx);
 6051                });
 6052            }
 6053            for (buffer, edits) in linked_edits {
 6054                buffer.update(cx, |buffer, cx| {
 6055                    let snapshot = buffer.snapshot();
 6056                    let edits = edits
 6057                        .into_iter()
 6058                        .map(|(range, text)| {
 6059                            use text::ToPoint as TP;
 6060                            let end_point = TP::to_point(&range.end, &snapshot);
 6061                            let start_point = TP::to_point(&range.start, &snapshot);
 6062                            (start_point..end_point, text)
 6063                        })
 6064                        .sorted_by_key(|(range, _)| range.start);
 6065                    buffer.edit(edits, None, cx);
 6066                })
 6067            }
 6068
 6069            editor.refresh_edit_prediction(true, false, window, cx);
 6070        });
 6071        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6072
 6073        let show_new_completions_on_confirm = completion
 6074            .confirm
 6075            .as_ref()
 6076            .is_some_and(|confirm| confirm(intent, window, cx));
 6077        if show_new_completions_on_confirm {
 6078            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6079        }
 6080
 6081        let provider = self.completion_provider.as_ref()?;
 6082        drop(completion);
 6083        let apply_edits = provider.apply_additional_edits_for_completion(
 6084            buffer_handle,
 6085            completions_menu.completions.clone(),
 6086            candidate_id,
 6087            true,
 6088            cx,
 6089        );
 6090
 6091        let editor_settings = EditorSettings::get_global(cx);
 6092        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6093            // After the code completion is finished, users often want to know what signatures are needed.
 6094            // so we should automatically call signature_help
 6095            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6096        }
 6097
 6098        Some(cx.foreground_executor().spawn(async move {
 6099            apply_edits.await?;
 6100            Ok(())
 6101        }))
 6102    }
 6103
 6104    pub fn toggle_code_actions(
 6105        &mut self,
 6106        action: &ToggleCodeActions,
 6107        window: &mut Window,
 6108        cx: &mut Context<Self>,
 6109    ) {
 6110        let quick_launch = action.quick_launch;
 6111        let mut context_menu = self.context_menu.borrow_mut();
 6112        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6113            if code_actions.deployed_from == action.deployed_from {
 6114                // Toggle if we're selecting the same one
 6115                *context_menu = None;
 6116                cx.notify();
 6117                return;
 6118            } else {
 6119                // Otherwise, clear it and start a new one
 6120                *context_menu = None;
 6121                cx.notify();
 6122            }
 6123        }
 6124        drop(context_menu);
 6125        let snapshot = self.snapshot(window, cx);
 6126        let deployed_from = action.deployed_from.clone();
 6127        let action = action.clone();
 6128        self.completion_tasks.clear();
 6129        self.discard_edit_prediction(false, cx);
 6130
 6131        let multibuffer_point = match &action.deployed_from {
 6132            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6133                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6134            }
 6135            _ => self.selections.newest::<Point>(cx).head(),
 6136        };
 6137        let Some((buffer, buffer_row)) = snapshot
 6138            .buffer_snapshot
 6139            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6140            .and_then(|(buffer_snapshot, range)| {
 6141                self.buffer()
 6142                    .read(cx)
 6143                    .buffer(buffer_snapshot.remote_id())
 6144                    .map(|buffer| (buffer, range.start.row))
 6145            })
 6146        else {
 6147            return;
 6148        };
 6149        let buffer_id = buffer.read(cx).remote_id();
 6150        let tasks = self
 6151            .tasks
 6152            .get(&(buffer_id, buffer_row))
 6153            .map(|t| Arc::new(t.to_owned()));
 6154
 6155        if !self.focus_handle.is_focused(window) {
 6156            return;
 6157        }
 6158        let project = self.project.clone();
 6159
 6160        let code_actions_task = match deployed_from {
 6161            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6162            _ => self.code_actions(buffer_row, window, cx),
 6163        };
 6164
 6165        let runnable_task = match deployed_from {
 6166            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6167            _ => {
 6168                let mut task_context_task = Task::ready(None);
 6169                if let Some(tasks) = &tasks
 6170                    && let Some(project) = project
 6171                {
 6172                    task_context_task =
 6173                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6174                }
 6175
 6176                cx.spawn_in(window, {
 6177                    let buffer = buffer.clone();
 6178                    async move |editor, cx| {
 6179                        let task_context = task_context_task.await;
 6180
 6181                        let resolved_tasks =
 6182                            tasks
 6183                                .zip(task_context.clone())
 6184                                .map(|(tasks, task_context)| ResolvedTasks {
 6185                                    templates: tasks.resolve(&task_context).collect(),
 6186                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6187                                        multibuffer_point.row,
 6188                                        tasks.column,
 6189                                    )),
 6190                                });
 6191                        let debug_scenarios = editor
 6192                            .update(cx, |editor, cx| {
 6193                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6194                            })?
 6195                            .await;
 6196                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6197                    }
 6198                })
 6199            }
 6200        };
 6201
 6202        cx.spawn_in(window, async move |editor, cx| {
 6203            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6204            let code_actions = code_actions_task.await;
 6205            let spawn_straight_away = quick_launch
 6206                && resolved_tasks
 6207                    .as_ref()
 6208                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6209                && code_actions
 6210                    .as_ref()
 6211                    .is_none_or(|actions| actions.is_empty())
 6212                && debug_scenarios.is_empty();
 6213
 6214            editor.update_in(cx, |editor, window, cx| {
 6215                crate::hover_popover::hide_hover(editor, cx);
 6216                let actions = CodeActionContents::new(
 6217                    resolved_tasks,
 6218                    code_actions,
 6219                    debug_scenarios,
 6220                    task_context.unwrap_or_default(),
 6221                );
 6222
 6223                // Don't show the menu if there are no actions available
 6224                if actions.is_empty() {
 6225                    cx.notify();
 6226                    return Task::ready(Ok(()));
 6227                }
 6228
 6229                *editor.context_menu.borrow_mut() =
 6230                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6231                        buffer,
 6232                        actions,
 6233                        selected_item: Default::default(),
 6234                        scroll_handle: UniformListScrollHandle::default(),
 6235                        deployed_from,
 6236                    }));
 6237                cx.notify();
 6238                if spawn_straight_away
 6239                    && let Some(task) = editor.confirm_code_action(
 6240                        &ConfirmCodeAction { item_ix: Some(0) },
 6241                        window,
 6242                        cx,
 6243                    )
 6244                {
 6245                    return task;
 6246                }
 6247
 6248                Task::ready(Ok(()))
 6249            })
 6250        })
 6251        .detach_and_log_err(cx);
 6252    }
 6253
 6254    fn debug_scenarios(
 6255        &mut self,
 6256        resolved_tasks: &Option<ResolvedTasks>,
 6257        buffer: &Entity<Buffer>,
 6258        cx: &mut App,
 6259    ) -> Task<Vec<task::DebugScenario>> {
 6260        maybe!({
 6261            let project = self.project()?;
 6262            let dap_store = project.read(cx).dap_store();
 6263            let mut scenarios = vec![];
 6264            let resolved_tasks = resolved_tasks.as_ref()?;
 6265            let buffer = buffer.read(cx);
 6266            let language = buffer.language()?;
 6267            let file = buffer.file();
 6268            let debug_adapter = language_settings(language.name().into(), file, cx)
 6269                .debuggers
 6270                .first()
 6271                .map(SharedString::from)
 6272                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6273
 6274            dap_store.update(cx, |dap_store, cx| {
 6275                for (_, task) in &resolved_tasks.templates {
 6276                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6277                        task.original_task().clone(),
 6278                        debug_adapter.clone().into(),
 6279                        task.display_label().to_owned().into(),
 6280                        cx,
 6281                    );
 6282                    scenarios.push(maybe_scenario);
 6283                }
 6284            });
 6285            Some(cx.background_spawn(async move {
 6286                futures::future::join_all(scenarios)
 6287                    .await
 6288                    .into_iter()
 6289                    .flatten()
 6290                    .collect::<Vec<_>>()
 6291            }))
 6292        })
 6293        .unwrap_or_else(|| Task::ready(vec![]))
 6294    }
 6295
 6296    fn code_actions(
 6297        &mut self,
 6298        buffer_row: u32,
 6299        window: &mut Window,
 6300        cx: &mut Context<Self>,
 6301    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6302        let mut task = self.code_actions_task.take();
 6303        cx.spawn_in(window, async move |editor, cx| {
 6304            while let Some(prev_task) = task {
 6305                prev_task.await.log_err();
 6306                task = editor
 6307                    .update(cx, |this, _| this.code_actions_task.take())
 6308                    .ok()?;
 6309            }
 6310
 6311            editor
 6312                .update(cx, |editor, cx| {
 6313                    editor
 6314                        .available_code_actions
 6315                        .clone()
 6316                        .and_then(|(location, code_actions)| {
 6317                            let snapshot = location.buffer.read(cx).snapshot();
 6318                            let point_range = location.range.to_point(&snapshot);
 6319                            let point_range = point_range.start.row..=point_range.end.row;
 6320                            if point_range.contains(&buffer_row) {
 6321                                Some(code_actions)
 6322                            } else {
 6323                                None
 6324                            }
 6325                        })
 6326                })
 6327                .ok()
 6328                .flatten()
 6329        })
 6330    }
 6331
 6332    pub fn confirm_code_action(
 6333        &mut self,
 6334        action: &ConfirmCodeAction,
 6335        window: &mut Window,
 6336        cx: &mut Context<Self>,
 6337    ) -> Option<Task<Result<()>>> {
 6338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6339
 6340        let actions_menu =
 6341            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6342                menu
 6343            } else {
 6344                return None;
 6345            };
 6346
 6347        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6348        let action = actions_menu.actions.get(action_ix)?;
 6349        let title = action.label();
 6350        let buffer = actions_menu.buffer;
 6351        let workspace = self.workspace()?;
 6352
 6353        match action {
 6354            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6355                workspace.update(cx, |workspace, cx| {
 6356                    workspace.schedule_resolved_task(
 6357                        task_source_kind,
 6358                        resolved_task,
 6359                        false,
 6360                        window,
 6361                        cx,
 6362                    );
 6363
 6364                    Some(Task::ready(Ok(())))
 6365                })
 6366            }
 6367            CodeActionsItem::CodeAction {
 6368                excerpt_id,
 6369                action,
 6370                provider,
 6371            } => {
 6372                let apply_code_action =
 6373                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6374                let workspace = workspace.downgrade();
 6375                Some(cx.spawn_in(window, async move |editor, cx| {
 6376                    let project_transaction = apply_code_action.await?;
 6377                    Self::open_project_transaction(
 6378                        &editor,
 6379                        workspace,
 6380                        project_transaction,
 6381                        title,
 6382                        cx,
 6383                    )
 6384                    .await
 6385                }))
 6386            }
 6387            CodeActionsItem::DebugScenario(scenario) => {
 6388                let context = actions_menu.actions.context;
 6389
 6390                workspace.update(cx, |workspace, cx| {
 6391                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6392                    workspace.start_debug_session(
 6393                        scenario,
 6394                        context,
 6395                        Some(buffer),
 6396                        None,
 6397                        window,
 6398                        cx,
 6399                    );
 6400                });
 6401                Some(Task::ready(Ok(())))
 6402            }
 6403        }
 6404    }
 6405
 6406    pub async fn open_project_transaction(
 6407        editor: &WeakEntity<Editor>,
 6408        workspace: WeakEntity<Workspace>,
 6409        transaction: ProjectTransaction,
 6410        title: String,
 6411        cx: &mut AsyncWindowContext,
 6412    ) -> Result<()> {
 6413        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6414        cx.update(|_, cx| {
 6415            entries.sort_unstable_by_key(|(buffer, _)| {
 6416                buffer.read(cx).file().map(|f| f.path().clone())
 6417            });
 6418        })?;
 6419
 6420        // If the project transaction's edits are all contained within this editor, then
 6421        // avoid opening a new editor to display them.
 6422
 6423        if let Some((buffer, transaction)) = entries.first() {
 6424            if entries.len() == 1 {
 6425                let excerpt = editor.update(cx, |editor, cx| {
 6426                    editor
 6427                        .buffer()
 6428                        .read(cx)
 6429                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6430                })?;
 6431                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6432                    && excerpted_buffer == *buffer
 6433                {
 6434                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6435                        let excerpt_range = excerpt_range.to_offset(buffer);
 6436                        buffer
 6437                            .edited_ranges_for_transaction::<usize>(transaction)
 6438                            .all(|range| {
 6439                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6440                            })
 6441                    })?;
 6442
 6443                    if all_edits_within_excerpt {
 6444                        return Ok(());
 6445                    }
 6446                }
 6447            }
 6448        } else {
 6449            return Ok(());
 6450        }
 6451
 6452        let mut ranges_to_highlight = Vec::new();
 6453        let excerpt_buffer = cx.new(|cx| {
 6454            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6455            for (buffer_handle, transaction) in &entries {
 6456                let edited_ranges = buffer_handle
 6457                    .read(cx)
 6458                    .edited_ranges_for_transaction::<Point>(transaction)
 6459                    .collect::<Vec<_>>();
 6460                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6461                    PathKey::for_buffer(buffer_handle, cx),
 6462                    buffer_handle.clone(),
 6463                    edited_ranges,
 6464                    multibuffer_context_lines(cx),
 6465                    cx,
 6466                );
 6467
 6468                ranges_to_highlight.extend(ranges);
 6469            }
 6470            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6471            multibuffer
 6472        })?;
 6473
 6474        workspace.update_in(cx, |workspace, window, cx| {
 6475            let project = workspace.project().clone();
 6476            let editor =
 6477                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6478            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6479            editor.update(cx, |editor, cx| {
 6480                editor.highlight_background::<Self>(
 6481                    &ranges_to_highlight,
 6482                    |theme| theme.colors().editor_highlighted_line_background,
 6483                    cx,
 6484                );
 6485            });
 6486        })?;
 6487
 6488        Ok(())
 6489    }
 6490
 6491    pub fn clear_code_action_providers(&mut self) {
 6492        self.code_action_providers.clear();
 6493        self.available_code_actions.take();
 6494    }
 6495
 6496    pub fn add_code_action_provider(
 6497        &mut self,
 6498        provider: Rc<dyn CodeActionProvider>,
 6499        window: &mut Window,
 6500        cx: &mut Context<Self>,
 6501    ) {
 6502        if self
 6503            .code_action_providers
 6504            .iter()
 6505            .any(|existing_provider| existing_provider.id() == provider.id())
 6506        {
 6507            return;
 6508        }
 6509
 6510        self.code_action_providers.push(provider);
 6511        self.refresh_code_actions(window, cx);
 6512    }
 6513
 6514    pub fn remove_code_action_provider(
 6515        &mut self,
 6516        id: Arc<str>,
 6517        window: &mut Window,
 6518        cx: &mut Context<Self>,
 6519    ) {
 6520        self.code_action_providers
 6521            .retain(|provider| provider.id() != id);
 6522        self.refresh_code_actions(window, cx);
 6523    }
 6524
 6525    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6526        !self.code_action_providers.is_empty()
 6527            && EditorSettings::get_global(cx).toolbar.code_actions
 6528    }
 6529
 6530    pub fn has_available_code_actions(&self) -> bool {
 6531        self.available_code_actions
 6532            .as_ref()
 6533            .is_some_and(|(_, actions)| !actions.is_empty())
 6534    }
 6535
 6536    fn render_inline_code_actions(
 6537        &self,
 6538        icon_size: ui::IconSize,
 6539        display_row: DisplayRow,
 6540        is_active: bool,
 6541        cx: &mut Context<Self>,
 6542    ) -> AnyElement {
 6543        let show_tooltip = !self.context_menu_visible();
 6544        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6545            .icon_size(icon_size)
 6546            .shape(ui::IconButtonShape::Square)
 6547            .icon_color(ui::Color::Hidden)
 6548            .toggle_state(is_active)
 6549            .when(show_tooltip, |this| {
 6550                this.tooltip({
 6551                    let focus_handle = self.focus_handle.clone();
 6552                    move |window, cx| {
 6553                        Tooltip::for_action_in(
 6554                            "Toggle Code Actions",
 6555                            &ToggleCodeActions {
 6556                                deployed_from: None,
 6557                                quick_launch: false,
 6558                            },
 6559                            &focus_handle,
 6560                            window,
 6561                            cx,
 6562                        )
 6563                    }
 6564                })
 6565            })
 6566            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6567                window.focus(&editor.focus_handle(cx));
 6568                editor.toggle_code_actions(
 6569                    &crate::actions::ToggleCodeActions {
 6570                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6571                            display_row,
 6572                        )),
 6573                        quick_launch: false,
 6574                    },
 6575                    window,
 6576                    cx,
 6577                );
 6578            }))
 6579            .into_any_element()
 6580    }
 6581
 6582    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6583        &self.context_menu
 6584    }
 6585
 6586    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6587        let newest_selection = self.selections.newest_anchor().clone();
 6588        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6589        let buffer = self.buffer.read(cx);
 6590        if newest_selection.head().diff_base_anchor.is_some() {
 6591            return None;
 6592        }
 6593        let (start_buffer, start) =
 6594            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6595        let (end_buffer, end) =
 6596            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6597        if start_buffer != end_buffer {
 6598            return None;
 6599        }
 6600
 6601        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6602            cx.background_executor()
 6603                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6604                .await;
 6605
 6606            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6607                let providers = this.code_action_providers.clone();
 6608                let tasks = this
 6609                    .code_action_providers
 6610                    .iter()
 6611                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6612                    .collect::<Vec<_>>();
 6613                (providers, tasks)
 6614            })?;
 6615
 6616            let mut actions = Vec::new();
 6617            for (provider, provider_actions) in
 6618                providers.into_iter().zip(future::join_all(tasks).await)
 6619            {
 6620                if let Some(provider_actions) = provider_actions.log_err() {
 6621                    actions.extend(provider_actions.into_iter().map(|action| {
 6622                        AvailableCodeAction {
 6623                            excerpt_id: newest_selection.start.excerpt_id,
 6624                            action,
 6625                            provider: provider.clone(),
 6626                        }
 6627                    }));
 6628                }
 6629            }
 6630
 6631            this.update(cx, |this, cx| {
 6632                this.available_code_actions = if actions.is_empty() {
 6633                    None
 6634                } else {
 6635                    Some((
 6636                        Location {
 6637                            buffer: start_buffer,
 6638                            range: start..end,
 6639                        },
 6640                        actions.into(),
 6641                    ))
 6642                };
 6643                cx.notify();
 6644            })
 6645        }));
 6646        None
 6647    }
 6648
 6649    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6650        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6651            self.show_git_blame_inline = false;
 6652
 6653            self.show_git_blame_inline_delay_task =
 6654                Some(cx.spawn_in(window, async move |this, cx| {
 6655                    cx.background_executor().timer(delay).await;
 6656
 6657                    this.update(cx, |this, cx| {
 6658                        this.show_git_blame_inline = true;
 6659                        cx.notify();
 6660                    })
 6661                    .log_err();
 6662                }));
 6663        }
 6664    }
 6665
 6666    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6667        let snapshot = self.snapshot(window, cx);
 6668        let cursor = self.selections.newest::<Point>(cx).head();
 6669        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6670        else {
 6671            return;
 6672        };
 6673
 6674        let Some(blame) = self.blame.as_ref() else {
 6675            return;
 6676        };
 6677
 6678        let row_info = RowInfo {
 6679            buffer_id: Some(buffer.remote_id()),
 6680            buffer_row: Some(point.row),
 6681            ..Default::default()
 6682        };
 6683        let Some((buffer, blame_entry)) = blame
 6684            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6685            .flatten()
 6686        else {
 6687            return;
 6688        };
 6689
 6690        let anchor = self.selections.newest_anchor().head();
 6691        let position = self.to_pixel_point(anchor, &snapshot, window);
 6692        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6693            self.show_blame_popover(
 6694                buffer,
 6695                &blame_entry,
 6696                position + last_bounds.origin,
 6697                true,
 6698                cx,
 6699            );
 6700        };
 6701    }
 6702
 6703    fn show_blame_popover(
 6704        &mut self,
 6705        buffer: BufferId,
 6706        blame_entry: &BlameEntry,
 6707        position: gpui::Point<Pixels>,
 6708        ignore_timeout: bool,
 6709        cx: &mut Context<Self>,
 6710    ) {
 6711        if let Some(state) = &mut self.inline_blame_popover {
 6712            state.hide_task.take();
 6713        } else {
 6714            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6715            let blame_entry = blame_entry.clone();
 6716            let show_task = cx.spawn(async move |editor, cx| {
 6717                if !ignore_timeout {
 6718                    cx.background_executor()
 6719                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6720                        .await;
 6721                }
 6722                editor
 6723                    .update(cx, |editor, cx| {
 6724                        editor.inline_blame_popover_show_task.take();
 6725                        let Some(blame) = editor.blame.as_ref() else {
 6726                            return;
 6727                        };
 6728                        let blame = blame.read(cx);
 6729                        let details = blame.details_for_entry(buffer, &blame_entry);
 6730                        let markdown = cx.new(|cx| {
 6731                            Markdown::new(
 6732                                details
 6733                                    .as_ref()
 6734                                    .map(|message| message.message.clone())
 6735                                    .unwrap_or_default(),
 6736                                None,
 6737                                None,
 6738                                cx,
 6739                            )
 6740                        });
 6741                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6742                            position,
 6743                            hide_task: None,
 6744                            popover_bounds: None,
 6745                            popover_state: InlineBlamePopoverState {
 6746                                scroll_handle: ScrollHandle::new(),
 6747                                commit_message: details,
 6748                                markdown,
 6749                            },
 6750                            keyboard_grace: ignore_timeout,
 6751                        });
 6752                        cx.notify();
 6753                    })
 6754                    .ok();
 6755            });
 6756            self.inline_blame_popover_show_task = Some(show_task);
 6757        }
 6758    }
 6759
 6760    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6761        self.inline_blame_popover_show_task.take();
 6762        if let Some(state) = &mut self.inline_blame_popover {
 6763            let hide_task = cx.spawn(async move |editor, cx| {
 6764                cx.background_executor()
 6765                    .timer(std::time::Duration::from_millis(100))
 6766                    .await;
 6767                editor
 6768                    .update(cx, |editor, cx| {
 6769                        editor.inline_blame_popover.take();
 6770                        cx.notify();
 6771                    })
 6772                    .ok();
 6773            });
 6774            state.hide_task = Some(hide_task);
 6775        }
 6776    }
 6777
 6778    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6779        if self.pending_rename.is_some() {
 6780            return None;
 6781        }
 6782
 6783        let provider = self.semantics_provider.clone()?;
 6784        let buffer = self.buffer.read(cx);
 6785        let newest_selection = self.selections.newest_anchor().clone();
 6786        let cursor_position = newest_selection.head();
 6787        let (cursor_buffer, cursor_buffer_position) =
 6788            buffer.text_anchor_for_position(cursor_position, cx)?;
 6789        let (tail_buffer, tail_buffer_position) =
 6790            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6791        if cursor_buffer != tail_buffer {
 6792            return None;
 6793        }
 6794
 6795        let snapshot = cursor_buffer.read(cx).snapshot();
 6796        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6797        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6798        if start_word_range != end_word_range {
 6799            self.document_highlights_task.take();
 6800            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6801            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6802            return None;
 6803        }
 6804
 6805        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6806        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6807            cx.background_executor()
 6808                .timer(Duration::from_millis(debounce))
 6809                .await;
 6810
 6811            let highlights = if let Some(highlights) = cx
 6812                .update(|cx| {
 6813                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6814                })
 6815                .ok()
 6816                .flatten()
 6817            {
 6818                highlights.await.log_err()
 6819            } else {
 6820                None
 6821            };
 6822
 6823            if let Some(highlights) = highlights {
 6824                this.update(cx, |this, cx| {
 6825                    if this.pending_rename.is_some() {
 6826                        return;
 6827                    }
 6828
 6829                    let buffer = this.buffer.read(cx);
 6830                    if buffer
 6831                        .text_anchor_for_position(cursor_position, cx)
 6832                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6833                    {
 6834                        return;
 6835                    }
 6836
 6837                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6838                    let mut write_ranges = Vec::new();
 6839                    let mut read_ranges = Vec::new();
 6840                    for highlight in highlights {
 6841                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6842                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6843                        {
 6844                            let start = highlight
 6845                                .range
 6846                                .start
 6847                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6848                            let end = highlight
 6849                                .range
 6850                                .end
 6851                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6852                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6853                                continue;
 6854                            }
 6855
 6856                            let range = Anchor {
 6857                                buffer_id: Some(buffer_id),
 6858                                excerpt_id,
 6859                                text_anchor: start,
 6860                                diff_base_anchor: None,
 6861                            }..Anchor {
 6862                                buffer_id: Some(buffer_id),
 6863                                excerpt_id,
 6864                                text_anchor: end,
 6865                                diff_base_anchor: None,
 6866                            };
 6867                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6868                                write_ranges.push(range);
 6869                            } else {
 6870                                read_ranges.push(range);
 6871                            }
 6872                        }
 6873                    }
 6874
 6875                    this.highlight_background::<DocumentHighlightRead>(
 6876                        &read_ranges,
 6877                        |theme| theme.colors().editor_document_highlight_read_background,
 6878                        cx,
 6879                    );
 6880                    this.highlight_background::<DocumentHighlightWrite>(
 6881                        &write_ranges,
 6882                        |theme| theme.colors().editor_document_highlight_write_background,
 6883                        cx,
 6884                    );
 6885                    cx.notify();
 6886                })
 6887                .log_err();
 6888            }
 6889        }));
 6890        None
 6891    }
 6892
 6893    fn prepare_highlight_query_from_selection(
 6894        &mut self,
 6895        cx: &mut Context<Editor>,
 6896    ) -> Option<(String, Range<Anchor>)> {
 6897        if matches!(self.mode, EditorMode::SingleLine) {
 6898            return None;
 6899        }
 6900        if !EditorSettings::get_global(cx).selection_highlight {
 6901            return None;
 6902        }
 6903        if self.selections.count() != 1 || self.selections.line_mode {
 6904            return None;
 6905        }
 6906        let selection = self.selections.newest::<Point>(cx);
 6907        if selection.is_empty() || selection.start.row != selection.end.row {
 6908            return None;
 6909        }
 6910        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6911        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6912        let query = multi_buffer_snapshot
 6913            .text_for_range(selection_anchor_range.clone())
 6914            .collect::<String>();
 6915        if query.trim().is_empty() {
 6916            return None;
 6917        }
 6918        Some((query, selection_anchor_range))
 6919    }
 6920
 6921    fn update_selection_occurrence_highlights(
 6922        &mut self,
 6923        query_text: String,
 6924        query_range: Range<Anchor>,
 6925        multi_buffer_range_to_query: Range<Point>,
 6926        use_debounce: bool,
 6927        window: &mut Window,
 6928        cx: &mut Context<Editor>,
 6929    ) -> Task<()> {
 6930        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6931        cx.spawn_in(window, async move |editor, cx| {
 6932            if use_debounce {
 6933                cx.background_executor()
 6934                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6935                    .await;
 6936            }
 6937            let match_task = cx.background_spawn(async move {
 6938                let buffer_ranges = multi_buffer_snapshot
 6939                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6940                    .into_iter()
 6941                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6942                let mut match_ranges = Vec::new();
 6943                let Ok(regex) = project::search::SearchQuery::text(
 6944                    query_text.clone(),
 6945                    false,
 6946                    false,
 6947                    false,
 6948                    Default::default(),
 6949                    Default::default(),
 6950                    false,
 6951                    None,
 6952                ) else {
 6953                    return Vec::default();
 6954                };
 6955                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6956                    match_ranges.extend(
 6957                        regex
 6958                            .search(buffer_snapshot, Some(search_range.clone()))
 6959                            .await
 6960                            .into_iter()
 6961                            .filter_map(|match_range| {
 6962                                let match_start = buffer_snapshot
 6963                                    .anchor_after(search_range.start + match_range.start);
 6964                                let match_end = buffer_snapshot
 6965                                    .anchor_before(search_range.start + match_range.end);
 6966                                let match_anchor_range = Anchor::range_in_buffer(
 6967                                    excerpt_id,
 6968                                    buffer_snapshot.remote_id(),
 6969                                    match_start..match_end,
 6970                                );
 6971                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6972                            }),
 6973                    );
 6974                }
 6975                match_ranges
 6976            });
 6977            let match_ranges = match_task.await;
 6978            editor
 6979                .update_in(cx, |editor, _, cx| {
 6980                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6981                    if !match_ranges.is_empty() {
 6982                        editor.highlight_background::<SelectedTextHighlight>(
 6983                            &match_ranges,
 6984                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6985                            cx,
 6986                        )
 6987                    }
 6988                })
 6989                .log_err();
 6990        })
 6991    }
 6992
 6993    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6994        struct NewlineFold;
 6995        let type_id = std::any::TypeId::of::<NewlineFold>();
 6996        if !self.mode.is_single_line() {
 6997            return;
 6998        }
 6999        let snapshot = self.snapshot(window, cx);
 7000        if snapshot.buffer_snapshot.max_point().row == 0 {
 7001            return;
 7002        }
 7003        let task = cx.background_spawn(async move {
 7004            let new_newlines = snapshot
 7005                .buffer_chars_at(0)
 7006                .filter_map(|(c, i)| {
 7007                    if c == '\n' {
 7008                        Some(
 7009                            snapshot.buffer_snapshot.anchor_after(i)
 7010                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7011                        )
 7012                    } else {
 7013                        None
 7014                    }
 7015                })
 7016                .collect::<Vec<_>>();
 7017            let existing_newlines = snapshot
 7018                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7019                .filter_map(|fold| {
 7020                    if fold.placeholder.type_tag == Some(type_id) {
 7021                        Some(fold.range.start..fold.range.end)
 7022                    } else {
 7023                        None
 7024                    }
 7025                })
 7026                .collect::<Vec<_>>();
 7027
 7028            (new_newlines, existing_newlines)
 7029        });
 7030        self.folding_newlines = cx.spawn(async move |this, cx| {
 7031            let (new_newlines, existing_newlines) = task.await;
 7032            if new_newlines == existing_newlines {
 7033                return;
 7034            }
 7035            let placeholder = FoldPlaceholder {
 7036                render: Arc::new(move |_, _, cx| {
 7037                    div()
 7038                        .bg(cx.theme().status().hint_background)
 7039                        .border_b_1()
 7040                        .size_full()
 7041                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7042                        .border_color(cx.theme().status().hint)
 7043                        .child("\\n")
 7044                        .into_any()
 7045                }),
 7046                constrain_width: false,
 7047                merge_adjacent: false,
 7048                type_tag: Some(type_id),
 7049            };
 7050            let creases = new_newlines
 7051                .into_iter()
 7052                .map(|range| Crease::simple(range, placeholder.clone()))
 7053                .collect();
 7054            this.update(cx, |this, cx| {
 7055                this.display_map.update(cx, |display_map, cx| {
 7056                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7057                    display_map.fold(creases, cx);
 7058                });
 7059            })
 7060            .ok();
 7061        });
 7062    }
 7063
 7064    fn refresh_selected_text_highlights(
 7065        &mut self,
 7066        on_buffer_edit: bool,
 7067        window: &mut Window,
 7068        cx: &mut Context<Editor>,
 7069    ) {
 7070        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7071        else {
 7072            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7073            self.quick_selection_highlight_task.take();
 7074            self.debounced_selection_highlight_task.take();
 7075            return;
 7076        };
 7077        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7078        if on_buffer_edit
 7079            || self
 7080                .quick_selection_highlight_task
 7081                .as_ref()
 7082                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7083        {
 7084            let multi_buffer_visible_start = self
 7085                .scroll_manager
 7086                .anchor()
 7087                .anchor
 7088                .to_point(&multi_buffer_snapshot);
 7089            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7090                multi_buffer_visible_start
 7091                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7092                Bias::Left,
 7093            );
 7094            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7095            self.quick_selection_highlight_task = Some((
 7096                query_range.clone(),
 7097                self.update_selection_occurrence_highlights(
 7098                    query_text.clone(),
 7099                    query_range.clone(),
 7100                    multi_buffer_visible_range,
 7101                    false,
 7102                    window,
 7103                    cx,
 7104                ),
 7105            ));
 7106        }
 7107        if on_buffer_edit
 7108            || self
 7109                .debounced_selection_highlight_task
 7110                .as_ref()
 7111                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7112        {
 7113            let multi_buffer_start = multi_buffer_snapshot
 7114                .anchor_before(0)
 7115                .to_point(&multi_buffer_snapshot);
 7116            let multi_buffer_end = multi_buffer_snapshot
 7117                .anchor_after(multi_buffer_snapshot.len())
 7118                .to_point(&multi_buffer_snapshot);
 7119            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7120            self.debounced_selection_highlight_task = Some((
 7121                query_range.clone(),
 7122                self.update_selection_occurrence_highlights(
 7123                    query_text,
 7124                    query_range,
 7125                    multi_buffer_full_range,
 7126                    true,
 7127                    window,
 7128                    cx,
 7129                ),
 7130            ));
 7131        }
 7132    }
 7133
 7134    pub fn refresh_edit_prediction(
 7135        &mut self,
 7136        debounce: bool,
 7137        user_requested: bool,
 7138        window: &mut Window,
 7139        cx: &mut Context<Self>,
 7140    ) -> Option<()> {
 7141        if DisableAiSettings::get_global(cx).disable_ai {
 7142            return None;
 7143        }
 7144
 7145        let provider = self.edit_prediction_provider()?;
 7146        let cursor = self.selections.newest_anchor().head();
 7147        let (buffer, cursor_buffer_position) =
 7148            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7149
 7150        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7151            self.discard_edit_prediction(false, cx);
 7152            return None;
 7153        }
 7154
 7155        self.update_visible_edit_prediction(window, cx);
 7156
 7157        if !user_requested
 7158            && (!self.should_show_edit_predictions()
 7159                || !self.is_focused(window)
 7160                || buffer.read(cx).is_empty())
 7161        {
 7162            self.discard_edit_prediction(false, cx);
 7163            return None;
 7164        }
 7165
 7166        provider.refresh(
 7167            self.project.clone(),
 7168            buffer,
 7169            cursor_buffer_position,
 7170            debounce,
 7171            cx,
 7172        );
 7173        Some(())
 7174    }
 7175
 7176    fn show_edit_predictions_in_menu(&self) -> bool {
 7177        match self.edit_prediction_settings {
 7178            EditPredictionSettings::Disabled => false,
 7179            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7180        }
 7181    }
 7182
 7183    pub fn edit_predictions_enabled(&self) -> bool {
 7184        match self.edit_prediction_settings {
 7185            EditPredictionSettings::Disabled => false,
 7186            EditPredictionSettings::Enabled { .. } => true,
 7187        }
 7188    }
 7189
 7190    fn edit_prediction_requires_modifier(&self) -> bool {
 7191        match self.edit_prediction_settings {
 7192            EditPredictionSettings::Disabled => false,
 7193            EditPredictionSettings::Enabled {
 7194                preview_requires_modifier,
 7195                ..
 7196            } => preview_requires_modifier,
 7197        }
 7198    }
 7199
 7200    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7201        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7202            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7203            self.discard_edit_prediction(false, cx);
 7204        } else {
 7205            let selection = self.selections.newest_anchor();
 7206            let cursor = selection.head();
 7207
 7208            if let Some((buffer, cursor_buffer_position)) =
 7209                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7210            {
 7211                self.edit_prediction_settings =
 7212                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7213            }
 7214        }
 7215    }
 7216
 7217    fn edit_prediction_settings_at_position(
 7218        &self,
 7219        buffer: &Entity<Buffer>,
 7220        buffer_position: language::Anchor,
 7221        cx: &App,
 7222    ) -> EditPredictionSettings {
 7223        if !self.mode.is_full()
 7224            || !self.show_edit_predictions_override.unwrap_or(true)
 7225            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7226        {
 7227            return EditPredictionSettings::Disabled;
 7228        }
 7229
 7230        let buffer = buffer.read(cx);
 7231
 7232        let file = buffer.file();
 7233
 7234        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7235            return EditPredictionSettings::Disabled;
 7236        };
 7237
 7238        let by_provider = matches!(
 7239            self.menu_edit_predictions_policy,
 7240            MenuEditPredictionsPolicy::ByProvider
 7241        );
 7242
 7243        let show_in_menu = by_provider
 7244            && self
 7245                .edit_prediction_provider
 7246                .as_ref()
 7247                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7248
 7249        let preview_requires_modifier =
 7250            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7251
 7252        EditPredictionSettings::Enabled {
 7253            show_in_menu,
 7254            preview_requires_modifier,
 7255        }
 7256    }
 7257
 7258    fn should_show_edit_predictions(&self) -> bool {
 7259        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7260    }
 7261
 7262    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7263        matches!(
 7264            self.edit_prediction_preview,
 7265            EditPredictionPreview::Active { .. }
 7266        )
 7267    }
 7268
 7269    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7270        let cursor = self.selections.newest_anchor().head();
 7271        if let Some((buffer, cursor_position)) =
 7272            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7273        {
 7274            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7275        } else {
 7276            false
 7277        }
 7278    }
 7279
 7280    pub fn supports_minimap(&self, cx: &App) -> bool {
 7281        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7282    }
 7283
 7284    fn edit_predictions_enabled_in_buffer(
 7285        &self,
 7286        buffer: &Entity<Buffer>,
 7287        buffer_position: language::Anchor,
 7288        cx: &App,
 7289    ) -> bool {
 7290        maybe!({
 7291            if self.read_only(cx) {
 7292                return Some(false);
 7293            }
 7294            let provider = self.edit_prediction_provider()?;
 7295            if !provider.is_enabled(buffer, buffer_position, cx) {
 7296                return Some(false);
 7297            }
 7298            let buffer = buffer.read(cx);
 7299            let Some(file) = buffer.file() else {
 7300                return Some(true);
 7301            };
 7302            let settings = all_language_settings(Some(file), cx);
 7303            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7304        })
 7305        .unwrap_or(false)
 7306    }
 7307
 7308    fn cycle_edit_prediction(
 7309        &mut self,
 7310        direction: Direction,
 7311        window: &mut Window,
 7312        cx: &mut Context<Self>,
 7313    ) -> Option<()> {
 7314        let provider = self.edit_prediction_provider()?;
 7315        let cursor = self.selections.newest_anchor().head();
 7316        let (buffer, cursor_buffer_position) =
 7317            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7318        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7319            return None;
 7320        }
 7321
 7322        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7323        self.update_visible_edit_prediction(window, cx);
 7324
 7325        Some(())
 7326    }
 7327
 7328    pub fn show_edit_prediction(
 7329        &mut self,
 7330        _: &ShowEditPrediction,
 7331        window: &mut Window,
 7332        cx: &mut Context<Self>,
 7333    ) {
 7334        if !self.has_active_edit_prediction() {
 7335            self.refresh_edit_prediction(false, true, window, cx);
 7336            return;
 7337        }
 7338
 7339        self.update_visible_edit_prediction(window, cx);
 7340    }
 7341
 7342    pub fn display_cursor_names(
 7343        &mut self,
 7344        _: &DisplayCursorNames,
 7345        window: &mut Window,
 7346        cx: &mut Context<Self>,
 7347    ) {
 7348        self.show_cursor_names(window, cx);
 7349    }
 7350
 7351    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7352        self.show_cursor_names = true;
 7353        cx.notify();
 7354        cx.spawn_in(window, async move |this, cx| {
 7355            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7356            this.update(cx, |this, cx| {
 7357                this.show_cursor_names = false;
 7358                cx.notify()
 7359            })
 7360            .ok()
 7361        })
 7362        .detach();
 7363    }
 7364
 7365    pub fn next_edit_prediction(
 7366        &mut self,
 7367        _: &NextEditPrediction,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) {
 7371        if self.has_active_edit_prediction() {
 7372            self.cycle_edit_prediction(Direction::Next, window, cx);
 7373        } else {
 7374            let is_copilot_disabled = self
 7375                .refresh_edit_prediction(false, true, window, cx)
 7376                .is_none();
 7377            if is_copilot_disabled {
 7378                cx.propagate();
 7379            }
 7380        }
 7381    }
 7382
 7383    pub fn previous_edit_prediction(
 7384        &mut self,
 7385        _: &PreviousEditPrediction,
 7386        window: &mut Window,
 7387        cx: &mut Context<Self>,
 7388    ) {
 7389        if self.has_active_edit_prediction() {
 7390            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7391        } else {
 7392            let is_copilot_disabled = self
 7393                .refresh_edit_prediction(false, true, window, cx)
 7394                .is_none();
 7395            if is_copilot_disabled {
 7396                cx.propagate();
 7397            }
 7398        }
 7399    }
 7400
 7401    pub fn accept_edit_prediction(
 7402        &mut self,
 7403        _: &AcceptEditPrediction,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) {
 7407        if self.show_edit_predictions_in_menu() {
 7408            self.hide_context_menu(window, cx);
 7409        }
 7410
 7411        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7412            return;
 7413        };
 7414
 7415        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7416
 7417        match &active_edit_prediction.completion {
 7418            EditPrediction::Move { target, .. } => {
 7419                let target = *target;
 7420
 7421                if let Some(position_map) = &self.last_position_map {
 7422                    if position_map
 7423                        .visible_row_range
 7424                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7425                        || !self.edit_prediction_requires_modifier()
 7426                    {
 7427                        self.unfold_ranges(&[target..target], true, false, cx);
 7428                        // Note that this is also done in vim's handler of the Tab action.
 7429                        self.change_selections(
 7430                            SelectionEffects::scroll(Autoscroll::newest()),
 7431                            window,
 7432                            cx,
 7433                            |selections| {
 7434                                selections.select_anchor_ranges([target..target]);
 7435                            },
 7436                        );
 7437                        self.clear_row_highlights::<EditPredictionPreview>();
 7438
 7439                        self.edit_prediction_preview
 7440                            .set_previous_scroll_position(None);
 7441                    } else {
 7442                        self.edit_prediction_preview
 7443                            .set_previous_scroll_position(Some(
 7444                                position_map.snapshot.scroll_anchor,
 7445                            ));
 7446
 7447                        self.highlight_rows::<EditPredictionPreview>(
 7448                            target..target,
 7449                            cx.theme().colors().editor_highlighted_line_background,
 7450                            RowHighlightOptions {
 7451                                autoscroll: true,
 7452                                ..Default::default()
 7453                            },
 7454                            cx,
 7455                        );
 7456                        self.request_autoscroll(Autoscroll::fit(), cx);
 7457                    }
 7458                }
 7459            }
 7460            EditPrediction::Edit { edits, .. } => {
 7461                if let Some(provider) = self.edit_prediction_provider() {
 7462                    provider.accept(cx);
 7463                }
 7464
 7465                // Store the transaction ID and selections before applying the edit
 7466                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7467
 7468                let snapshot = self.buffer.read(cx).snapshot(cx);
 7469                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7470
 7471                self.buffer.update(cx, |buffer, cx| {
 7472                    buffer.edit(edits.iter().cloned(), None, cx)
 7473                });
 7474
 7475                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7476                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7477                });
 7478
 7479                let selections = self.selections.disjoint_anchors_arc();
 7480                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7481                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7482                    if has_new_transaction {
 7483                        self.selection_history
 7484                            .insert_transaction(transaction_id_now, selections);
 7485                    }
 7486                }
 7487
 7488                self.update_visible_edit_prediction(window, cx);
 7489                if self.active_edit_prediction.is_none() {
 7490                    self.refresh_edit_prediction(true, true, window, cx);
 7491                }
 7492
 7493                cx.notify();
 7494            }
 7495        }
 7496
 7497        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7498    }
 7499
 7500    pub fn accept_partial_edit_prediction(
 7501        &mut self,
 7502        _: &AcceptPartialEditPrediction,
 7503        window: &mut Window,
 7504        cx: &mut Context<Self>,
 7505    ) {
 7506        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7507            return;
 7508        };
 7509        if self.selections.count() != 1 {
 7510            return;
 7511        }
 7512
 7513        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7514
 7515        match &active_edit_prediction.completion {
 7516            EditPrediction::Move { target, .. } => {
 7517                let target = *target;
 7518                self.change_selections(
 7519                    SelectionEffects::scroll(Autoscroll::newest()),
 7520                    window,
 7521                    cx,
 7522                    |selections| {
 7523                        selections.select_anchor_ranges([target..target]);
 7524                    },
 7525                );
 7526            }
 7527            EditPrediction::Edit { edits, .. } => {
 7528                // Find an insertion that starts at the cursor position.
 7529                let snapshot = self.buffer.read(cx).snapshot(cx);
 7530                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7531                let insertion = edits.iter().find_map(|(range, text)| {
 7532                    let range = range.to_offset(&snapshot);
 7533                    if range.is_empty() && range.start == cursor_offset {
 7534                        Some(text)
 7535                    } else {
 7536                        None
 7537                    }
 7538                });
 7539
 7540                if let Some(text) = insertion {
 7541                    let mut partial_completion = text
 7542                        .chars()
 7543                        .by_ref()
 7544                        .take_while(|c| c.is_alphabetic())
 7545                        .collect::<String>();
 7546                    if partial_completion.is_empty() {
 7547                        partial_completion = text
 7548                            .chars()
 7549                            .by_ref()
 7550                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7551                            .collect::<String>();
 7552                    }
 7553
 7554                    cx.emit(EditorEvent::InputHandled {
 7555                        utf16_range_to_replace: None,
 7556                        text: partial_completion.clone().into(),
 7557                    });
 7558
 7559                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7560
 7561                    self.refresh_edit_prediction(true, true, window, cx);
 7562                    cx.notify();
 7563                } else {
 7564                    self.accept_edit_prediction(&Default::default(), window, cx);
 7565                }
 7566            }
 7567        }
 7568    }
 7569
 7570    fn discard_edit_prediction(
 7571        &mut self,
 7572        should_report_edit_prediction_event: bool,
 7573        cx: &mut Context<Self>,
 7574    ) -> bool {
 7575        if should_report_edit_prediction_event {
 7576            let completion_id = self
 7577                .active_edit_prediction
 7578                .as_ref()
 7579                .and_then(|active_completion| active_completion.completion_id.clone());
 7580
 7581            self.report_edit_prediction_event(completion_id, false, cx);
 7582        }
 7583
 7584        if let Some(provider) = self.edit_prediction_provider() {
 7585            provider.discard(cx);
 7586        }
 7587
 7588        self.take_active_edit_prediction(cx)
 7589    }
 7590
 7591    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7592        let Some(provider) = self.edit_prediction_provider() else {
 7593            return;
 7594        };
 7595
 7596        let Some((_, buffer, _)) = self
 7597            .buffer
 7598            .read(cx)
 7599            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7600        else {
 7601            return;
 7602        };
 7603
 7604        let extension = buffer
 7605            .read(cx)
 7606            .file()
 7607            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7608
 7609        let event_type = match accepted {
 7610            true => "Edit Prediction Accepted",
 7611            false => "Edit Prediction Discarded",
 7612        };
 7613        telemetry::event!(
 7614            event_type,
 7615            provider = provider.name(),
 7616            prediction_id = id,
 7617            suggestion_accepted = accepted,
 7618            file_extension = extension,
 7619        );
 7620    }
 7621
 7622    pub fn has_active_edit_prediction(&self) -> bool {
 7623        self.active_edit_prediction.is_some()
 7624    }
 7625
 7626    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7627        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7628            return false;
 7629        };
 7630
 7631        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7632        self.clear_highlights::<EditPredictionHighlight>(cx);
 7633        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7634        true
 7635    }
 7636
 7637    /// Returns true when we're displaying the edit prediction popover below the cursor
 7638    /// like we are not previewing and the LSP autocomplete menu is visible
 7639    /// or we are in `when_holding_modifier` mode.
 7640    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7641        if self.edit_prediction_preview_is_active()
 7642            || !self.show_edit_predictions_in_menu()
 7643            || !self.edit_predictions_enabled()
 7644        {
 7645            return false;
 7646        }
 7647
 7648        if self.has_visible_completions_menu() {
 7649            return true;
 7650        }
 7651
 7652        has_completion && self.edit_prediction_requires_modifier()
 7653    }
 7654
 7655    fn handle_modifiers_changed(
 7656        &mut self,
 7657        modifiers: Modifiers,
 7658        position_map: &PositionMap,
 7659        window: &mut Window,
 7660        cx: &mut Context<Self>,
 7661    ) {
 7662        if self.show_edit_predictions_in_menu() {
 7663            self.update_edit_prediction_preview(&modifiers, window, cx);
 7664        }
 7665
 7666        self.update_selection_mode(&modifiers, position_map, window, cx);
 7667
 7668        let mouse_position = window.mouse_position();
 7669        if !position_map.text_hitbox.is_hovered(window) {
 7670            return;
 7671        }
 7672
 7673        self.update_hovered_link(
 7674            position_map.point_for_position(mouse_position),
 7675            &position_map.snapshot,
 7676            modifiers,
 7677            window,
 7678            cx,
 7679        )
 7680    }
 7681
 7682    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7683        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7684        if invert {
 7685            match multi_cursor_setting {
 7686                MultiCursorModifier::Alt => modifiers.alt,
 7687                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7688            }
 7689        } else {
 7690            match multi_cursor_setting {
 7691                MultiCursorModifier::Alt => modifiers.secondary(),
 7692                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7693            }
 7694        }
 7695    }
 7696
 7697    fn columnar_selection_mode(
 7698        modifiers: &Modifiers,
 7699        cx: &mut Context<Self>,
 7700    ) -> Option<ColumnarMode> {
 7701        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7702            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7703                Some(ColumnarMode::FromMouse)
 7704            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7705                Some(ColumnarMode::FromSelection)
 7706            } else {
 7707                None
 7708            }
 7709        } else {
 7710            None
 7711        }
 7712    }
 7713
 7714    fn update_selection_mode(
 7715        &mut self,
 7716        modifiers: &Modifiers,
 7717        position_map: &PositionMap,
 7718        window: &mut Window,
 7719        cx: &mut Context<Self>,
 7720    ) {
 7721        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7722            return;
 7723        };
 7724        if self.selections.pending_anchor().is_none() {
 7725            return;
 7726        }
 7727
 7728        let mouse_position = window.mouse_position();
 7729        let point_for_position = position_map.point_for_position(mouse_position);
 7730        let position = point_for_position.previous_valid;
 7731
 7732        self.select(
 7733            SelectPhase::BeginColumnar {
 7734                position,
 7735                reset: false,
 7736                mode,
 7737                goal_column: point_for_position.exact_unclipped.column(),
 7738            },
 7739            window,
 7740            cx,
 7741        );
 7742    }
 7743
 7744    fn update_edit_prediction_preview(
 7745        &mut self,
 7746        modifiers: &Modifiers,
 7747        window: &mut Window,
 7748        cx: &mut Context<Self>,
 7749    ) {
 7750        let mut modifiers_held = false;
 7751        if let Some(accept_keystroke) = self
 7752            .accept_edit_prediction_keybind(false, window, cx)
 7753            .keystroke()
 7754        {
 7755            modifiers_held = modifiers_held
 7756                || (accept_keystroke.modifiers() == modifiers
 7757                    && accept_keystroke.modifiers().modified());
 7758        };
 7759        if let Some(accept_partial_keystroke) = self
 7760            .accept_edit_prediction_keybind(true, window, cx)
 7761            .keystroke()
 7762        {
 7763            modifiers_held = modifiers_held
 7764                || (accept_partial_keystroke.modifiers() == modifiers
 7765                    && accept_partial_keystroke.modifiers().modified());
 7766        }
 7767
 7768        if modifiers_held {
 7769            if matches!(
 7770                self.edit_prediction_preview,
 7771                EditPredictionPreview::Inactive { .. }
 7772            ) {
 7773                self.edit_prediction_preview = EditPredictionPreview::Active {
 7774                    previous_scroll_position: None,
 7775                    since: Instant::now(),
 7776                };
 7777
 7778                self.update_visible_edit_prediction(window, cx);
 7779                cx.notify();
 7780            }
 7781        } else if let EditPredictionPreview::Active {
 7782            previous_scroll_position,
 7783            since,
 7784        } = self.edit_prediction_preview
 7785        {
 7786            if let (Some(previous_scroll_position), Some(position_map)) =
 7787                (previous_scroll_position, self.last_position_map.as_ref())
 7788            {
 7789                self.set_scroll_position(
 7790                    previous_scroll_position
 7791                        .scroll_position(&position_map.snapshot.display_snapshot),
 7792                    window,
 7793                    cx,
 7794                );
 7795            }
 7796
 7797            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7798                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7799            };
 7800            self.clear_row_highlights::<EditPredictionPreview>();
 7801            self.update_visible_edit_prediction(window, cx);
 7802            cx.notify();
 7803        }
 7804    }
 7805
 7806    fn update_visible_edit_prediction(
 7807        &mut self,
 7808        _window: &mut Window,
 7809        cx: &mut Context<Self>,
 7810    ) -> Option<()> {
 7811        if DisableAiSettings::get_global(cx).disable_ai {
 7812            return None;
 7813        }
 7814
 7815        if self.ime_transaction.is_some() {
 7816            self.discard_edit_prediction(false, cx);
 7817            return None;
 7818        }
 7819
 7820        let selection = self.selections.newest_anchor();
 7821        let cursor = selection.head();
 7822        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7823        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7824        let excerpt_id = cursor.excerpt_id;
 7825
 7826        let show_in_menu = self.show_edit_predictions_in_menu();
 7827        let completions_menu_has_precedence = !show_in_menu
 7828            && (self.context_menu.borrow().is_some()
 7829                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7830
 7831        if completions_menu_has_precedence
 7832            || !offset_selection.is_empty()
 7833            || self
 7834                .active_edit_prediction
 7835                .as_ref()
 7836                .is_some_and(|completion| {
 7837                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7838                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7839                    !invalidation_range.contains(&offset_selection.head())
 7840                })
 7841        {
 7842            self.discard_edit_prediction(false, cx);
 7843            return None;
 7844        }
 7845
 7846        self.take_active_edit_prediction(cx);
 7847        let Some(provider) = self.edit_prediction_provider() else {
 7848            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7849            return None;
 7850        };
 7851
 7852        let (buffer, cursor_buffer_position) =
 7853            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7854
 7855        self.edit_prediction_settings =
 7856            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7857
 7858        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7859
 7860        if self.edit_prediction_indent_conflict {
 7861            let cursor_point = cursor.to_point(&multibuffer);
 7862
 7863            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7864
 7865            if let Some((_, indent)) = indents.iter().next()
 7866                && indent.len == cursor_point.column
 7867            {
 7868                self.edit_prediction_indent_conflict = false;
 7869            }
 7870        }
 7871
 7872        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7873        let edits = edit_prediction
 7874            .edits
 7875            .into_iter()
 7876            .flat_map(|(range, new_text)| {
 7877                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7878                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7879                Some((start..end, new_text))
 7880            })
 7881            .collect::<Vec<_>>();
 7882        if edits.is_empty() {
 7883            return None;
 7884        }
 7885
 7886        let first_edit_start = edits.first().unwrap().0.start;
 7887        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7888        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7889
 7890        let last_edit_end = edits.last().unwrap().0.end;
 7891        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7892        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7893
 7894        let cursor_row = cursor.to_point(&multibuffer).row;
 7895
 7896        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7897
 7898        let mut inlay_ids = Vec::new();
 7899        let invalidation_row_range;
 7900        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7901            Some(cursor_row..edit_end_row)
 7902        } else if cursor_row > edit_end_row {
 7903            Some(edit_start_row..cursor_row)
 7904        } else {
 7905            None
 7906        };
 7907        let supports_jump = self
 7908            .edit_prediction_provider
 7909            .as_ref()
 7910            .map(|provider| provider.provider.supports_jump_to_edit())
 7911            .unwrap_or(true);
 7912
 7913        let is_move = supports_jump
 7914            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7915        let completion = if is_move {
 7916            invalidation_row_range =
 7917                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7918            let target = first_edit_start;
 7919            EditPrediction::Move { target, snapshot }
 7920        } else {
 7921            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7922                && !self.edit_predictions_hidden_for_vim_mode;
 7923
 7924            if show_completions_in_buffer {
 7925                if edits
 7926                    .iter()
 7927                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7928                {
 7929                    let mut inlays = Vec::new();
 7930                    for (range, new_text) in &edits {
 7931                        let inlay = Inlay::edit_prediction(
 7932                            post_inc(&mut self.next_inlay_id),
 7933                            range.start,
 7934                            new_text.as_str(),
 7935                        );
 7936                        inlay_ids.push(inlay.id);
 7937                        inlays.push(inlay);
 7938                    }
 7939
 7940                    self.splice_inlays(&[], inlays, cx);
 7941                } else {
 7942                    let background_color = cx.theme().status().deleted_background;
 7943                    self.highlight_text::<EditPredictionHighlight>(
 7944                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7945                        HighlightStyle {
 7946                            background_color: Some(background_color),
 7947                            ..Default::default()
 7948                        },
 7949                        cx,
 7950                    );
 7951                }
 7952            }
 7953
 7954            invalidation_row_range = edit_start_row..edit_end_row;
 7955
 7956            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7957                if provider.show_tab_accept_marker() {
 7958                    EditDisplayMode::TabAccept
 7959                } else {
 7960                    EditDisplayMode::Inline
 7961                }
 7962            } else {
 7963                EditDisplayMode::DiffPopover
 7964            };
 7965
 7966            EditPrediction::Edit {
 7967                edits,
 7968                edit_preview: edit_prediction.edit_preview,
 7969                display_mode,
 7970                snapshot,
 7971            }
 7972        };
 7973
 7974        let invalidation_range = multibuffer
 7975            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7976            ..multibuffer.anchor_after(Point::new(
 7977                invalidation_row_range.end,
 7978                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7979            ));
 7980
 7981        self.stale_edit_prediction_in_menu = None;
 7982        self.active_edit_prediction = Some(EditPredictionState {
 7983            inlay_ids,
 7984            completion,
 7985            completion_id: edit_prediction.id,
 7986            invalidation_range,
 7987        });
 7988
 7989        cx.notify();
 7990
 7991        Some(())
 7992    }
 7993
 7994    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7995        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7996    }
 7997
 7998    fn clear_tasks(&mut self) {
 7999        self.tasks.clear()
 8000    }
 8001
 8002    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8003        if self.tasks.insert(key, value).is_some() {
 8004            // This case should hopefully be rare, but just in case...
 8005            log::error!(
 8006                "multiple different run targets found on a single line, only the last target will be rendered"
 8007            )
 8008        }
 8009    }
 8010
 8011    /// Get all display points of breakpoints that will be rendered within editor
 8012    ///
 8013    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8014    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8015    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8016    fn active_breakpoints(
 8017        &self,
 8018        range: Range<DisplayRow>,
 8019        window: &mut Window,
 8020        cx: &mut Context<Self>,
 8021    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8022        let mut breakpoint_display_points = HashMap::default();
 8023
 8024        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8025            return breakpoint_display_points;
 8026        };
 8027
 8028        let snapshot = self.snapshot(window, cx);
 8029
 8030        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8031        let Some(project) = self.project() else {
 8032            return breakpoint_display_points;
 8033        };
 8034
 8035        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8036            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8037
 8038        for (buffer_snapshot, range, excerpt_id) in
 8039            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8040        {
 8041            let Some(buffer) = project
 8042                .read(cx)
 8043                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8044            else {
 8045                continue;
 8046            };
 8047            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8048                &buffer,
 8049                Some(
 8050                    buffer_snapshot.anchor_before(range.start)
 8051                        ..buffer_snapshot.anchor_after(range.end),
 8052                ),
 8053                buffer_snapshot,
 8054                cx,
 8055            );
 8056            for (breakpoint, state) in breakpoints {
 8057                let multi_buffer_anchor =
 8058                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8059                let position = multi_buffer_anchor
 8060                    .to_point(multi_buffer_snapshot)
 8061                    .to_display_point(&snapshot);
 8062
 8063                breakpoint_display_points.insert(
 8064                    position.row(),
 8065                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8066                );
 8067            }
 8068        }
 8069
 8070        breakpoint_display_points
 8071    }
 8072
 8073    fn breakpoint_context_menu(
 8074        &self,
 8075        anchor: Anchor,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) -> Entity<ui::ContextMenu> {
 8079        let weak_editor = cx.weak_entity();
 8080        let focus_handle = self.focus_handle(cx);
 8081
 8082        let row = self
 8083            .buffer
 8084            .read(cx)
 8085            .snapshot(cx)
 8086            .summary_for_anchor::<Point>(&anchor)
 8087            .row;
 8088
 8089        let breakpoint = self
 8090            .breakpoint_at_row(row, window, cx)
 8091            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8092
 8093        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8094            "Edit Log Breakpoint"
 8095        } else {
 8096            "Set Log Breakpoint"
 8097        };
 8098
 8099        let condition_breakpoint_msg = if breakpoint
 8100            .as_ref()
 8101            .is_some_and(|bp| bp.1.condition.is_some())
 8102        {
 8103            "Edit Condition Breakpoint"
 8104        } else {
 8105            "Set Condition Breakpoint"
 8106        };
 8107
 8108        let hit_condition_breakpoint_msg = if breakpoint
 8109            .as_ref()
 8110            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8111        {
 8112            "Edit Hit Condition Breakpoint"
 8113        } else {
 8114            "Set Hit Condition Breakpoint"
 8115        };
 8116
 8117        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8118            "Unset Breakpoint"
 8119        } else {
 8120            "Set Breakpoint"
 8121        };
 8122
 8123        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8124
 8125        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8126            BreakpointState::Enabled => Some("Disable"),
 8127            BreakpointState::Disabled => Some("Enable"),
 8128        });
 8129
 8130        let (anchor, breakpoint) =
 8131            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8132
 8133        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8134            menu.on_blur_subscription(Subscription::new(|| {}))
 8135                .context(focus_handle)
 8136                .when(run_to_cursor, |this| {
 8137                    let weak_editor = weak_editor.clone();
 8138                    this.entry("Run to cursor", None, move |window, cx| {
 8139                        weak_editor
 8140                            .update(cx, |editor, cx| {
 8141                                editor.change_selections(
 8142                                    SelectionEffects::no_scroll(),
 8143                                    window,
 8144                                    cx,
 8145                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8146                                );
 8147                            })
 8148                            .ok();
 8149
 8150                        window.dispatch_action(Box::new(RunToCursor), cx);
 8151                    })
 8152                    .separator()
 8153                })
 8154                .when_some(toggle_state_msg, |this, msg| {
 8155                    this.entry(msg, None, {
 8156                        let weak_editor = weak_editor.clone();
 8157                        let breakpoint = breakpoint.clone();
 8158                        move |_window, cx| {
 8159                            weak_editor
 8160                                .update(cx, |this, cx| {
 8161                                    this.edit_breakpoint_at_anchor(
 8162                                        anchor,
 8163                                        breakpoint.as_ref().clone(),
 8164                                        BreakpointEditAction::InvertState,
 8165                                        cx,
 8166                                    );
 8167                                })
 8168                                .log_err();
 8169                        }
 8170                    })
 8171                })
 8172                .entry(set_breakpoint_msg, None, {
 8173                    let weak_editor = weak_editor.clone();
 8174                    let breakpoint = breakpoint.clone();
 8175                    move |_window, cx| {
 8176                        weak_editor
 8177                            .update(cx, |this, cx| {
 8178                                this.edit_breakpoint_at_anchor(
 8179                                    anchor,
 8180                                    breakpoint.as_ref().clone(),
 8181                                    BreakpointEditAction::Toggle,
 8182                                    cx,
 8183                                );
 8184                            })
 8185                            .log_err();
 8186                    }
 8187                })
 8188                .entry(log_breakpoint_msg, None, {
 8189                    let breakpoint = breakpoint.clone();
 8190                    let weak_editor = weak_editor.clone();
 8191                    move |window, cx| {
 8192                        weak_editor
 8193                            .update(cx, |this, cx| {
 8194                                this.add_edit_breakpoint_block(
 8195                                    anchor,
 8196                                    breakpoint.as_ref(),
 8197                                    BreakpointPromptEditAction::Log,
 8198                                    window,
 8199                                    cx,
 8200                                );
 8201                            })
 8202                            .log_err();
 8203                    }
 8204                })
 8205                .entry(condition_breakpoint_msg, None, {
 8206                    let breakpoint = breakpoint.clone();
 8207                    let weak_editor = weak_editor.clone();
 8208                    move |window, cx| {
 8209                        weak_editor
 8210                            .update(cx, |this, cx| {
 8211                                this.add_edit_breakpoint_block(
 8212                                    anchor,
 8213                                    breakpoint.as_ref(),
 8214                                    BreakpointPromptEditAction::Condition,
 8215                                    window,
 8216                                    cx,
 8217                                );
 8218                            })
 8219                            .log_err();
 8220                    }
 8221                })
 8222                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8223                    weak_editor
 8224                        .update(cx, |this, cx| {
 8225                            this.add_edit_breakpoint_block(
 8226                                anchor,
 8227                                breakpoint.as_ref(),
 8228                                BreakpointPromptEditAction::HitCondition,
 8229                                window,
 8230                                cx,
 8231                            );
 8232                        })
 8233                        .log_err();
 8234                })
 8235        })
 8236    }
 8237
 8238    fn render_breakpoint(
 8239        &self,
 8240        position: Anchor,
 8241        row: DisplayRow,
 8242        breakpoint: &Breakpoint,
 8243        state: Option<BreakpointSessionState>,
 8244        cx: &mut Context<Self>,
 8245    ) -> IconButton {
 8246        let is_rejected = state.is_some_and(|s| !s.verified);
 8247        // Is it a breakpoint that shows up when hovering over gutter?
 8248        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8249            (false, false),
 8250            |PhantomBreakpointIndicator {
 8251                 is_active,
 8252                 display_row,
 8253                 collides_with_existing_breakpoint,
 8254             }| {
 8255                (
 8256                    is_active && display_row == row,
 8257                    collides_with_existing_breakpoint,
 8258                )
 8259            },
 8260        );
 8261
 8262        let (color, icon) = {
 8263            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8264                (false, false) => ui::IconName::DebugBreakpoint,
 8265                (true, false) => ui::IconName::DebugLogBreakpoint,
 8266                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8267                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8268            };
 8269
 8270            let color = if is_phantom {
 8271                Color::Hint
 8272            } else if is_rejected {
 8273                Color::Disabled
 8274            } else {
 8275                Color::Debugger
 8276            };
 8277
 8278            (color, icon)
 8279        };
 8280
 8281        let breakpoint = Arc::from(breakpoint.clone());
 8282
 8283        let alt_as_text = gpui::Keystroke {
 8284            modifiers: Modifiers::secondary_key(),
 8285            ..Default::default()
 8286        };
 8287        let primary_action_text = if breakpoint.is_disabled() {
 8288            "Enable breakpoint"
 8289        } else if is_phantom && !collides_with_existing {
 8290            "Set breakpoint"
 8291        } else {
 8292            "Unset breakpoint"
 8293        };
 8294        let focus_handle = self.focus_handle.clone();
 8295
 8296        let meta = if is_rejected {
 8297            SharedString::from("No executable code is associated with this line.")
 8298        } else if collides_with_existing && !breakpoint.is_disabled() {
 8299            SharedString::from(format!(
 8300                "{alt_as_text}-click to disable,\nright-click for more options."
 8301            ))
 8302        } else {
 8303            SharedString::from("Right-click for more options.")
 8304        };
 8305        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8306            .icon_size(IconSize::XSmall)
 8307            .size(ui::ButtonSize::None)
 8308            .when(is_rejected, |this| {
 8309                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8310            })
 8311            .icon_color(color)
 8312            .style(ButtonStyle::Transparent)
 8313            .on_click(cx.listener({
 8314                move |editor, event: &ClickEvent, window, cx| {
 8315                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8316                        BreakpointEditAction::InvertState
 8317                    } else {
 8318                        BreakpointEditAction::Toggle
 8319                    };
 8320
 8321                    window.focus(&editor.focus_handle(cx));
 8322                    editor.edit_breakpoint_at_anchor(
 8323                        position,
 8324                        breakpoint.as_ref().clone(),
 8325                        edit_action,
 8326                        cx,
 8327                    );
 8328                }
 8329            }))
 8330            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8331                editor.set_breakpoint_context_menu(
 8332                    row,
 8333                    Some(position),
 8334                    event.position(),
 8335                    window,
 8336                    cx,
 8337                );
 8338            }))
 8339            .tooltip(move |window, cx| {
 8340                Tooltip::with_meta_in(
 8341                    primary_action_text,
 8342                    Some(&ToggleBreakpoint),
 8343                    meta.clone(),
 8344                    &focus_handle,
 8345                    window,
 8346                    cx,
 8347                )
 8348            })
 8349    }
 8350
 8351    fn build_tasks_context(
 8352        project: &Entity<Project>,
 8353        buffer: &Entity<Buffer>,
 8354        buffer_row: u32,
 8355        tasks: &Arc<RunnableTasks>,
 8356        cx: &mut Context<Self>,
 8357    ) -> Task<Option<task::TaskContext>> {
 8358        let position = Point::new(buffer_row, tasks.column);
 8359        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8360        let location = Location {
 8361            buffer: buffer.clone(),
 8362            range: range_start..range_start,
 8363        };
 8364        // Fill in the environmental variables from the tree-sitter captures
 8365        let mut captured_task_variables = TaskVariables::default();
 8366        for (capture_name, value) in tasks.extra_variables.clone() {
 8367            captured_task_variables.insert(
 8368                task::VariableName::Custom(capture_name.into()),
 8369                value.clone(),
 8370            );
 8371        }
 8372        project.update(cx, |project, cx| {
 8373            project.task_store().update(cx, |task_store, cx| {
 8374                task_store.task_context_for_location(captured_task_variables, location, cx)
 8375            })
 8376        })
 8377    }
 8378
 8379    pub fn spawn_nearest_task(
 8380        &mut self,
 8381        action: &SpawnNearestTask,
 8382        window: &mut Window,
 8383        cx: &mut Context<Self>,
 8384    ) {
 8385        let Some((workspace, _)) = self.workspace.clone() else {
 8386            return;
 8387        };
 8388        let Some(project) = self.project.clone() else {
 8389            return;
 8390        };
 8391
 8392        // Try to find a closest, enclosing node using tree-sitter that has a task
 8393        let Some((buffer, buffer_row, tasks)) = self
 8394            .find_enclosing_node_task(cx)
 8395            // Or find the task that's closest in row-distance.
 8396            .or_else(|| self.find_closest_task(cx))
 8397        else {
 8398            return;
 8399        };
 8400
 8401        let reveal_strategy = action.reveal;
 8402        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8403        cx.spawn_in(window, async move |_, cx| {
 8404            let context = task_context.await?;
 8405            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8406
 8407            let resolved = &mut resolved_task.resolved;
 8408            resolved.reveal = reveal_strategy;
 8409
 8410            workspace
 8411                .update_in(cx, |workspace, window, cx| {
 8412                    workspace.schedule_resolved_task(
 8413                        task_source_kind,
 8414                        resolved_task,
 8415                        false,
 8416                        window,
 8417                        cx,
 8418                    );
 8419                })
 8420                .ok()
 8421        })
 8422        .detach();
 8423    }
 8424
 8425    fn find_closest_task(
 8426        &mut self,
 8427        cx: &mut Context<Self>,
 8428    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8429        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8430
 8431        let ((buffer_id, row), tasks) = self
 8432            .tasks
 8433            .iter()
 8434            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8435
 8436        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8437        let tasks = Arc::new(tasks.to_owned());
 8438        Some((buffer, *row, tasks))
 8439    }
 8440
 8441    fn find_enclosing_node_task(
 8442        &mut self,
 8443        cx: &mut Context<Self>,
 8444    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8445        let snapshot = self.buffer.read(cx).snapshot(cx);
 8446        let offset = self.selections.newest::<usize>(cx).head();
 8447        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8448        let buffer_id = excerpt.buffer().remote_id();
 8449
 8450        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8451        let mut cursor = layer.node().walk();
 8452
 8453        while cursor.goto_first_child_for_byte(offset).is_some() {
 8454            if cursor.node().end_byte() == offset {
 8455                cursor.goto_next_sibling();
 8456            }
 8457        }
 8458
 8459        // Ascend to the smallest ancestor that contains the range and has a task.
 8460        loop {
 8461            let node = cursor.node();
 8462            let node_range = node.byte_range();
 8463            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8464
 8465            // Check if this node contains our offset
 8466            if node_range.start <= offset && node_range.end >= offset {
 8467                // If it contains offset, check for task
 8468                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8469                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8470                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8471                }
 8472            }
 8473
 8474            if !cursor.goto_parent() {
 8475                break;
 8476            }
 8477        }
 8478        None
 8479    }
 8480
 8481    fn render_run_indicator(
 8482        &self,
 8483        _style: &EditorStyle,
 8484        is_active: bool,
 8485        row: DisplayRow,
 8486        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8487        cx: &mut Context<Self>,
 8488    ) -> IconButton {
 8489        let color = Color::Muted;
 8490        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8491
 8492        IconButton::new(
 8493            ("run_indicator", row.0 as usize),
 8494            ui::IconName::PlayOutlined,
 8495        )
 8496        .shape(ui::IconButtonShape::Square)
 8497        .icon_size(IconSize::XSmall)
 8498        .icon_color(color)
 8499        .toggle_state(is_active)
 8500        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8501            let quick_launch = match e {
 8502                ClickEvent::Keyboard(_) => true,
 8503                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8504            };
 8505
 8506            window.focus(&editor.focus_handle(cx));
 8507            editor.toggle_code_actions(
 8508                &ToggleCodeActions {
 8509                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8510                    quick_launch,
 8511                },
 8512                window,
 8513                cx,
 8514            );
 8515        }))
 8516        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8517            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8518        }))
 8519    }
 8520
 8521    pub fn context_menu_visible(&self) -> bool {
 8522        !self.edit_prediction_preview_is_active()
 8523            && self
 8524                .context_menu
 8525                .borrow()
 8526                .as_ref()
 8527                .is_some_and(|menu| menu.visible())
 8528    }
 8529
 8530    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8531        self.context_menu
 8532            .borrow()
 8533            .as_ref()
 8534            .map(|menu| menu.origin())
 8535    }
 8536
 8537    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8538        self.context_menu_options = Some(options);
 8539    }
 8540
 8541    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8542    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8543
 8544    fn render_edit_prediction_popover(
 8545        &mut self,
 8546        text_bounds: &Bounds<Pixels>,
 8547        content_origin: gpui::Point<Pixels>,
 8548        right_margin: Pixels,
 8549        editor_snapshot: &EditorSnapshot,
 8550        visible_row_range: Range<DisplayRow>,
 8551        scroll_top: f32,
 8552        scroll_bottom: f32,
 8553        line_layouts: &[LineWithInvisibles],
 8554        line_height: Pixels,
 8555        scroll_pixel_position: gpui::Point<Pixels>,
 8556        newest_selection_head: Option<DisplayPoint>,
 8557        editor_width: Pixels,
 8558        style: &EditorStyle,
 8559        window: &mut Window,
 8560        cx: &mut App,
 8561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8562        if self.mode().is_minimap() {
 8563            return None;
 8564        }
 8565        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8566
 8567        if self.edit_prediction_visible_in_cursor_popover(true) {
 8568            return None;
 8569        }
 8570
 8571        match &active_edit_prediction.completion {
 8572            EditPrediction::Move { target, .. } => {
 8573                let target_display_point = target.to_display_point(editor_snapshot);
 8574
 8575                if self.edit_prediction_requires_modifier() {
 8576                    if !self.edit_prediction_preview_is_active() {
 8577                        return None;
 8578                    }
 8579
 8580                    self.render_edit_prediction_modifier_jump_popover(
 8581                        text_bounds,
 8582                        content_origin,
 8583                        visible_row_range,
 8584                        line_layouts,
 8585                        line_height,
 8586                        scroll_pixel_position,
 8587                        newest_selection_head,
 8588                        target_display_point,
 8589                        window,
 8590                        cx,
 8591                    )
 8592                } else {
 8593                    self.render_edit_prediction_eager_jump_popover(
 8594                        text_bounds,
 8595                        content_origin,
 8596                        editor_snapshot,
 8597                        visible_row_range,
 8598                        scroll_top,
 8599                        scroll_bottom,
 8600                        line_height,
 8601                        scroll_pixel_position,
 8602                        target_display_point,
 8603                        editor_width,
 8604                        window,
 8605                        cx,
 8606                    )
 8607                }
 8608            }
 8609            EditPrediction::Edit {
 8610                display_mode: EditDisplayMode::Inline,
 8611                ..
 8612            } => None,
 8613            EditPrediction::Edit {
 8614                display_mode: EditDisplayMode::TabAccept,
 8615                edits,
 8616                ..
 8617            } => {
 8618                let range = &edits.first()?.0;
 8619                let target_display_point = range.end.to_display_point(editor_snapshot);
 8620
 8621                self.render_edit_prediction_end_of_line_popover(
 8622                    "Accept",
 8623                    editor_snapshot,
 8624                    visible_row_range,
 8625                    target_display_point,
 8626                    line_height,
 8627                    scroll_pixel_position,
 8628                    content_origin,
 8629                    editor_width,
 8630                    window,
 8631                    cx,
 8632                )
 8633            }
 8634            EditPrediction::Edit {
 8635                edits,
 8636                edit_preview,
 8637                display_mode: EditDisplayMode::DiffPopover,
 8638                snapshot,
 8639            } => self.render_edit_prediction_diff_popover(
 8640                text_bounds,
 8641                content_origin,
 8642                right_margin,
 8643                editor_snapshot,
 8644                visible_row_range,
 8645                line_layouts,
 8646                line_height,
 8647                scroll_pixel_position,
 8648                newest_selection_head,
 8649                editor_width,
 8650                style,
 8651                edits,
 8652                edit_preview,
 8653                snapshot,
 8654                window,
 8655                cx,
 8656            ),
 8657        }
 8658    }
 8659
 8660    fn render_edit_prediction_modifier_jump_popover(
 8661        &mut self,
 8662        text_bounds: &Bounds<Pixels>,
 8663        content_origin: gpui::Point<Pixels>,
 8664        visible_row_range: Range<DisplayRow>,
 8665        line_layouts: &[LineWithInvisibles],
 8666        line_height: Pixels,
 8667        scroll_pixel_position: gpui::Point<Pixels>,
 8668        newest_selection_head: Option<DisplayPoint>,
 8669        target_display_point: DisplayPoint,
 8670        window: &mut Window,
 8671        cx: &mut App,
 8672    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8673        let scrolled_content_origin =
 8674            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8675
 8676        const SCROLL_PADDING_Y: Pixels = px(12.);
 8677
 8678        if target_display_point.row() < visible_row_range.start {
 8679            return self.render_edit_prediction_scroll_popover(
 8680                |_| SCROLL_PADDING_Y,
 8681                IconName::ArrowUp,
 8682                visible_row_range,
 8683                line_layouts,
 8684                newest_selection_head,
 8685                scrolled_content_origin,
 8686                window,
 8687                cx,
 8688            );
 8689        } else if target_display_point.row() >= visible_row_range.end {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8692                IconName::ArrowDown,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        }
 8701
 8702        const POLE_WIDTH: Pixels = px(2.);
 8703
 8704        let line_layout =
 8705            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8706        let target_column = target_display_point.column() as usize;
 8707
 8708        let target_x = line_layout.x_for_index(target_column);
 8709        let target_y =
 8710            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8711
 8712        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8713
 8714        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8715        border_color.l += 0.001;
 8716
 8717        let mut element = v_flex()
 8718            .items_end()
 8719            .when(flag_on_right, |el| el.items_start())
 8720            .child(if flag_on_right {
 8721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8722                    .rounded_bl(px(0.))
 8723                    .rounded_tl(px(0.))
 8724                    .border_l_2()
 8725                    .border_color(border_color)
 8726            } else {
 8727                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8728                    .rounded_br(px(0.))
 8729                    .rounded_tr(px(0.))
 8730                    .border_r_2()
 8731                    .border_color(border_color)
 8732            })
 8733            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8734            .into_any();
 8735
 8736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8737
 8738        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8739            - point(
 8740                if flag_on_right {
 8741                    POLE_WIDTH
 8742                } else {
 8743                    size.width - POLE_WIDTH
 8744                },
 8745                size.height - line_height,
 8746            );
 8747
 8748        origin.x = origin.x.max(content_origin.x);
 8749
 8750        element.prepaint_at(origin, window, cx);
 8751
 8752        Some((element, origin))
 8753    }
 8754
 8755    fn render_edit_prediction_scroll_popover(
 8756        &mut self,
 8757        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8758        scroll_icon: IconName,
 8759        visible_row_range: Range<DisplayRow>,
 8760        line_layouts: &[LineWithInvisibles],
 8761        newest_selection_head: Option<DisplayPoint>,
 8762        scrolled_content_origin: gpui::Point<Pixels>,
 8763        window: &mut Window,
 8764        cx: &mut App,
 8765    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8766        let mut element = self
 8767            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8768            .into_any();
 8769
 8770        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8771
 8772        let cursor = newest_selection_head?;
 8773        let cursor_row_layout =
 8774            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8775        let cursor_column = cursor.column() as usize;
 8776
 8777        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8778
 8779        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8780
 8781        element.prepaint_at(origin, window, cx);
 8782        Some((element, origin))
 8783    }
 8784
 8785    fn render_edit_prediction_eager_jump_popover(
 8786        &mut self,
 8787        text_bounds: &Bounds<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        scroll_top: f32,
 8792        scroll_bottom: f32,
 8793        line_height: Pixels,
 8794        scroll_pixel_position: gpui::Point<Pixels>,
 8795        target_display_point: DisplayPoint,
 8796        editor_width: Pixels,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        if target_display_point.row().as_f32() < scroll_top {
 8801            let mut element = self
 8802                .render_edit_prediction_line_popover(
 8803                    "Jump to Edit",
 8804                    Some(IconName::ArrowUp),
 8805                    window,
 8806                    cx,
 8807                )?
 8808                .into_any();
 8809
 8810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8811            let offset = point(
 8812                (text_bounds.size.width - size.width) / 2.,
 8813                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8814            );
 8815
 8816            let origin = text_bounds.origin + offset;
 8817            element.prepaint_at(origin, window, cx);
 8818            Some((element, origin))
 8819        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8820            let mut element = self
 8821                .render_edit_prediction_line_popover(
 8822                    "Jump to Edit",
 8823                    Some(IconName::ArrowDown),
 8824                    window,
 8825                    cx,
 8826                )?
 8827                .into_any();
 8828
 8829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830            let offset = point(
 8831                (text_bounds.size.width - size.width) / 2.,
 8832                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8833            );
 8834
 8835            let origin = text_bounds.origin + offset;
 8836            element.prepaint_at(origin, window, cx);
 8837            Some((element, origin))
 8838        } else {
 8839            self.render_edit_prediction_end_of_line_popover(
 8840                "Jump to Edit",
 8841                editor_snapshot,
 8842                visible_row_range,
 8843                target_display_point,
 8844                line_height,
 8845                scroll_pixel_position,
 8846                content_origin,
 8847                editor_width,
 8848                window,
 8849                cx,
 8850            )
 8851        }
 8852    }
 8853
 8854    fn render_edit_prediction_end_of_line_popover(
 8855        self: &mut Editor,
 8856        label: &'static str,
 8857        editor_snapshot: &EditorSnapshot,
 8858        visible_row_range: Range<DisplayRow>,
 8859        target_display_point: DisplayPoint,
 8860        line_height: Pixels,
 8861        scroll_pixel_position: gpui::Point<Pixels>,
 8862        content_origin: gpui::Point<Pixels>,
 8863        editor_width: Pixels,
 8864        window: &mut Window,
 8865        cx: &mut App,
 8866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8867        let target_line_end = DisplayPoint::new(
 8868            target_display_point.row(),
 8869            editor_snapshot.line_len(target_display_point.row()),
 8870        );
 8871
 8872        let mut element = self
 8873            .render_edit_prediction_line_popover(label, None, window, cx)?
 8874            .into_any();
 8875
 8876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8879
 8880        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8881        let mut origin = start_point
 8882            + line_origin
 8883            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8884        origin.x = origin.x.max(content_origin.x);
 8885
 8886        let max_x = content_origin.x + editor_width - size.width;
 8887
 8888        if origin.x > max_x {
 8889            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8890
 8891            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8892                origin.y += offset;
 8893                IconName::ArrowUp
 8894            } else {
 8895                origin.y -= offset;
 8896                IconName::ArrowDown
 8897            };
 8898
 8899            element = self
 8900                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8901                .into_any();
 8902
 8903            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8904
 8905            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8906        }
 8907
 8908        element.prepaint_at(origin, window, cx);
 8909        Some((element, origin))
 8910    }
 8911
 8912    fn render_edit_prediction_diff_popover(
 8913        self: &Editor,
 8914        text_bounds: &Bounds<Pixels>,
 8915        content_origin: gpui::Point<Pixels>,
 8916        right_margin: Pixels,
 8917        editor_snapshot: &EditorSnapshot,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        line_height: Pixels,
 8921        scroll_pixel_position: gpui::Point<Pixels>,
 8922        newest_selection_head: Option<DisplayPoint>,
 8923        editor_width: Pixels,
 8924        style: &EditorStyle,
 8925        edits: &Vec<(Range<Anchor>, String)>,
 8926        edit_preview: &Option<language::EditPreview>,
 8927        snapshot: &language::BufferSnapshot,
 8928        window: &mut Window,
 8929        cx: &mut App,
 8930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8931        let edit_start = edits
 8932            .first()
 8933            .unwrap()
 8934            .0
 8935            .start
 8936            .to_display_point(editor_snapshot);
 8937        let edit_end = edits
 8938            .last()
 8939            .unwrap()
 8940            .0
 8941            .end
 8942            .to_display_point(editor_snapshot);
 8943
 8944        let is_visible = visible_row_range.contains(&edit_start.row())
 8945            || visible_row_range.contains(&edit_end.row());
 8946        if !is_visible {
 8947            return None;
 8948        }
 8949
 8950        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8951            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8952        } else {
 8953            // Fallback for providers without edit_preview
 8954            crate::edit_prediction_fallback_text(edits, cx)
 8955        };
 8956
 8957        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8958        let line_count = highlighted_edits.text.lines().count();
 8959
 8960        const BORDER_WIDTH: Pixels = px(1.);
 8961
 8962        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8963        let has_keybind = keybind.is_some();
 8964
 8965        let mut element = h_flex()
 8966            .items_start()
 8967            .child(
 8968                h_flex()
 8969                    .bg(cx.theme().colors().editor_background)
 8970                    .border(BORDER_WIDTH)
 8971                    .shadow_xs()
 8972                    .border_color(cx.theme().colors().border)
 8973                    .rounded_l_lg()
 8974                    .when(line_count > 1, |el| el.rounded_br_lg())
 8975                    .pr_1()
 8976                    .child(styled_text),
 8977            )
 8978            .child(
 8979                h_flex()
 8980                    .h(line_height + BORDER_WIDTH * 2.)
 8981                    .px_1p5()
 8982                    .gap_1()
 8983                    // Workaround: For some reason, there's a gap if we don't do this
 8984                    .ml(-BORDER_WIDTH)
 8985                    .shadow(vec![gpui::BoxShadow {
 8986                        color: gpui::black().opacity(0.05),
 8987                        offset: point(px(1.), px(1.)),
 8988                        blur_radius: px(2.),
 8989                        spread_radius: px(0.),
 8990                    }])
 8991                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8992                    .border(BORDER_WIDTH)
 8993                    .border_color(cx.theme().colors().border)
 8994                    .rounded_r_lg()
 8995                    .id("edit_prediction_diff_popover_keybind")
 8996                    .when(!has_keybind, |el| {
 8997                        let status_colors = cx.theme().status();
 8998
 8999                        el.bg(status_colors.error_background)
 9000                            .border_color(status_colors.error.opacity(0.6))
 9001                            .child(Icon::new(IconName::Info).color(Color::Error))
 9002                            .cursor_default()
 9003                            .hoverable_tooltip(move |_window, cx| {
 9004                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9005                            })
 9006                    })
 9007                    .children(keybind),
 9008            )
 9009            .into_any();
 9010
 9011        let longest_row =
 9012            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9013        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9014            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9015        } else {
 9016            layout_line(
 9017                longest_row,
 9018                editor_snapshot,
 9019                style,
 9020                editor_width,
 9021                |_| false,
 9022                window,
 9023                cx,
 9024            )
 9025            .width
 9026        };
 9027
 9028        let viewport_bounds =
 9029            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9030                right: -right_margin,
 9031                ..Default::default()
 9032            });
 9033
 9034        let x_after_longest =
 9035            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9036                - scroll_pixel_position.x;
 9037
 9038        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9039
 9040        // Fully visible if it can be displayed within the window (allow overlapping other
 9041        // panes). However, this is only allowed if the popover starts within text_bounds.
 9042        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9043            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9044
 9045        let mut origin = if can_position_to_the_right {
 9046            point(
 9047                x_after_longest,
 9048                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9049                    - scroll_pixel_position.y,
 9050            )
 9051        } else {
 9052            let cursor_row = newest_selection_head.map(|head| head.row());
 9053            let above_edit = edit_start
 9054                .row()
 9055                .0
 9056                .checked_sub(line_count as u32)
 9057                .map(DisplayRow);
 9058            let below_edit = Some(edit_end.row() + 1);
 9059            let above_cursor =
 9060                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9061            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9062
 9063            // Place the edit popover adjacent to the edit if there is a location
 9064            // available that is onscreen and does not obscure the cursor. Otherwise,
 9065            // place it adjacent to the cursor.
 9066            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9067                .into_iter()
 9068                .flatten()
 9069                .find(|&start_row| {
 9070                    let end_row = start_row + line_count as u32;
 9071                    visible_row_range.contains(&start_row)
 9072                        && visible_row_range.contains(&end_row)
 9073                        && cursor_row
 9074                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9075                })?;
 9076
 9077            content_origin
 9078                + point(
 9079                    -scroll_pixel_position.x,
 9080                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9081                )
 9082        };
 9083
 9084        origin.x -= BORDER_WIDTH;
 9085
 9086        window.defer_draw(element, origin, 1);
 9087
 9088        // Do not return an element, since it will already be drawn due to defer_draw.
 9089        None
 9090    }
 9091
 9092    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9093        px(30.)
 9094    }
 9095
 9096    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9097        if self.read_only(cx) {
 9098            cx.theme().players().read_only()
 9099        } else {
 9100            self.style.as_ref().unwrap().local_player
 9101        }
 9102    }
 9103
 9104    fn render_edit_prediction_accept_keybind(
 9105        &self,
 9106        window: &mut Window,
 9107        cx: &App,
 9108    ) -> Option<AnyElement> {
 9109        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9110        let accept_keystroke = accept_binding.keystroke()?;
 9111
 9112        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9113
 9114        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9115            Color::Accent
 9116        } else {
 9117            Color::Muted
 9118        };
 9119
 9120        h_flex()
 9121            .px_0p5()
 9122            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9123            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9124            .text_size(TextSize::XSmall.rems(cx))
 9125            .child(h_flex().children(ui::render_modifiers(
 9126                accept_keystroke.modifiers(),
 9127                PlatformStyle::platform(),
 9128                Some(modifiers_color),
 9129                Some(IconSize::XSmall.rems().into()),
 9130                true,
 9131            )))
 9132            .when(is_platform_style_mac, |parent| {
 9133                parent.child(accept_keystroke.key().to_string())
 9134            })
 9135            .when(!is_platform_style_mac, |parent| {
 9136                parent.child(
 9137                    Key::new(
 9138                        util::capitalize(accept_keystroke.key()),
 9139                        Some(Color::Default),
 9140                    )
 9141                    .size(Some(IconSize::XSmall.rems().into())),
 9142                )
 9143            })
 9144            .into_any()
 9145            .into()
 9146    }
 9147
 9148    fn render_edit_prediction_line_popover(
 9149        &self,
 9150        label: impl Into<SharedString>,
 9151        icon: Option<IconName>,
 9152        window: &mut Window,
 9153        cx: &App,
 9154    ) -> Option<Stateful<Div>> {
 9155        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        let result = h_flex()
 9161            .id("ep-line-popover")
 9162            .py_0p5()
 9163            .pl_1()
 9164            .pr(padding_right)
 9165            .gap_1()
 9166            .rounded_md()
 9167            .border_1()
 9168            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9169            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9170            .shadow_xs()
 9171            .when(!has_keybind, |el| {
 9172                let status_colors = cx.theme().status();
 9173
 9174                el.bg(status_colors.error_background)
 9175                    .border_color(status_colors.error.opacity(0.6))
 9176                    .pl_2()
 9177                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9178                    .cursor_default()
 9179                    .hoverable_tooltip(move |_window, cx| {
 9180                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9181                    })
 9182            })
 9183            .children(keybind)
 9184            .child(
 9185                Label::new(label)
 9186                    .size(LabelSize::Small)
 9187                    .when(!has_keybind, |el| {
 9188                        el.color(cx.theme().status().error.into()).strikethrough()
 9189                    }),
 9190            )
 9191            .when(!has_keybind, |el| {
 9192                el.child(
 9193                    h_flex().ml_1().child(
 9194                        Icon::new(IconName::Info)
 9195                            .size(IconSize::Small)
 9196                            .color(cx.theme().status().error.into()),
 9197                    ),
 9198                )
 9199            })
 9200            .when_some(icon, |element, icon| {
 9201                element.child(
 9202                    div()
 9203                        .mt(px(1.5))
 9204                        .child(Icon::new(icon).size(IconSize::Small)),
 9205                )
 9206            });
 9207
 9208        Some(result)
 9209    }
 9210
 9211    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9212        let accent_color = cx.theme().colors().text_accent;
 9213        let editor_bg_color = cx.theme().colors().editor_background;
 9214        editor_bg_color.blend(accent_color.opacity(0.1))
 9215    }
 9216
 9217    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9218        let accent_color = cx.theme().colors().text_accent;
 9219        let editor_bg_color = cx.theme().colors().editor_background;
 9220        editor_bg_color.blend(accent_color.opacity(0.6))
 9221    }
 9222    fn get_prediction_provider_icon_name(
 9223        provider: &Option<RegisteredEditPredictionProvider>,
 9224    ) -> IconName {
 9225        match provider {
 9226            Some(provider) => match provider.provider.name() {
 9227                "copilot" => IconName::Copilot,
 9228                "supermaven" => IconName::Supermaven,
 9229                _ => IconName::ZedPredict,
 9230            },
 9231            None => IconName::ZedPredict,
 9232        }
 9233    }
 9234
 9235    fn render_edit_prediction_cursor_popover(
 9236        &self,
 9237        min_width: Pixels,
 9238        max_width: Pixels,
 9239        cursor_point: Point,
 9240        style: &EditorStyle,
 9241        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9242        _window: &Window,
 9243        cx: &mut Context<Editor>,
 9244    ) -> Option<AnyElement> {
 9245        let provider = self.edit_prediction_provider.as_ref()?;
 9246        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9247
 9248        let is_refreshing = provider.provider.is_refreshing(cx);
 9249
 9250        fn pending_completion_container(icon: IconName) -> Div {
 9251            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9252        }
 9253
 9254        let completion = match &self.active_edit_prediction {
 9255            Some(prediction) => {
 9256                if !self.has_visible_completions_menu() {
 9257                    const RADIUS: Pixels = px(6.);
 9258                    const BORDER_WIDTH: Pixels = px(1.);
 9259
 9260                    return Some(
 9261                        h_flex()
 9262                            .elevation_2(cx)
 9263                            .border(BORDER_WIDTH)
 9264                            .border_color(cx.theme().colors().border)
 9265                            .when(accept_keystroke.is_none(), |el| {
 9266                                el.border_color(cx.theme().status().error)
 9267                            })
 9268                            .rounded(RADIUS)
 9269                            .rounded_tl(px(0.))
 9270                            .overflow_hidden()
 9271                            .child(div().px_1p5().child(match &prediction.completion {
 9272                                EditPrediction::Move { target, snapshot } => {
 9273                                    use text::ToPoint as _;
 9274                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9275                                    {
 9276                                        Icon::new(IconName::ZedPredictDown)
 9277                                    } else {
 9278                                        Icon::new(IconName::ZedPredictUp)
 9279                                    }
 9280                                }
 9281                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9282                            }))
 9283                            .child(
 9284                                h_flex()
 9285                                    .gap_1()
 9286                                    .py_1()
 9287                                    .px_2()
 9288                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9289                                    .border_l_1()
 9290                                    .border_color(cx.theme().colors().border)
 9291                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9292                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9293                                        el.child(
 9294                                            Label::new("Hold")
 9295                                                .size(LabelSize::Small)
 9296                                                .when(accept_keystroke.is_none(), |el| {
 9297                                                    el.strikethrough()
 9298                                                })
 9299                                                .line_height_style(LineHeightStyle::UiLabel),
 9300                                        )
 9301                                    })
 9302                                    .id("edit_prediction_cursor_popover_keybind")
 9303                                    .when(accept_keystroke.is_none(), |el| {
 9304                                        let status_colors = cx.theme().status();
 9305
 9306                                        el.bg(status_colors.error_background)
 9307                                            .border_color(status_colors.error.opacity(0.6))
 9308                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9309                                            .cursor_default()
 9310                                            .hoverable_tooltip(move |_window, cx| {
 9311                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9312                                                    .into()
 9313                                            })
 9314                                    })
 9315                                    .when_some(
 9316                                        accept_keystroke.as_ref(),
 9317                                        |el, accept_keystroke| {
 9318                                            el.child(h_flex().children(ui::render_modifiers(
 9319                                                accept_keystroke.modifiers(),
 9320                                                PlatformStyle::platform(),
 9321                                                Some(Color::Default),
 9322                                                Some(IconSize::XSmall.rems().into()),
 9323                                                false,
 9324                                            )))
 9325                                        },
 9326                                    ),
 9327                            )
 9328                            .into_any(),
 9329                    );
 9330                }
 9331
 9332                self.render_edit_prediction_cursor_popover_preview(
 9333                    prediction,
 9334                    cursor_point,
 9335                    style,
 9336                    cx,
 9337                )?
 9338            }
 9339
 9340            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9341                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9342                    stale_completion,
 9343                    cursor_point,
 9344                    style,
 9345                    cx,
 9346                )?,
 9347
 9348                None => pending_completion_container(provider_icon)
 9349                    .child(Label::new("...").size(LabelSize::Small)),
 9350            },
 9351
 9352            None => pending_completion_container(provider_icon)
 9353                .child(Label::new("...").size(LabelSize::Small)),
 9354        };
 9355
 9356        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9357            completion
 9358                .with_animation(
 9359                    "loading-completion",
 9360                    Animation::new(Duration::from_secs(2))
 9361                        .repeat()
 9362                        .with_easing(pulsating_between(0.4, 0.8)),
 9363                    |label, delta| label.opacity(delta),
 9364                )
 9365                .into_any_element()
 9366        } else {
 9367            completion.into_any_element()
 9368        };
 9369
 9370        let has_completion = self.active_edit_prediction.is_some();
 9371
 9372        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9373        Some(
 9374            h_flex()
 9375                .min_w(min_width)
 9376                .max_w(max_width)
 9377                .flex_1()
 9378                .elevation_2(cx)
 9379                .border_color(cx.theme().colors().border)
 9380                .child(
 9381                    div()
 9382                        .flex_1()
 9383                        .py_1()
 9384                        .px_2()
 9385                        .overflow_hidden()
 9386                        .child(completion),
 9387                )
 9388                .when_some(accept_keystroke, |el, accept_keystroke| {
 9389                    if !accept_keystroke.modifiers().modified() {
 9390                        return el;
 9391                    }
 9392
 9393                    el.child(
 9394                        h_flex()
 9395                            .h_full()
 9396                            .border_l_1()
 9397                            .rounded_r_lg()
 9398                            .border_color(cx.theme().colors().border)
 9399                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9400                            .gap_1()
 9401                            .py_1()
 9402                            .px_2()
 9403                            .child(
 9404                                h_flex()
 9405                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9406                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9407                                    .child(h_flex().children(ui::render_modifiers(
 9408                                        accept_keystroke.modifiers(),
 9409                                        PlatformStyle::platform(),
 9410                                        Some(if !has_completion {
 9411                                            Color::Muted
 9412                                        } else {
 9413                                            Color::Default
 9414                                        }),
 9415                                        None,
 9416                                        false,
 9417                                    ))),
 9418                            )
 9419                            .child(Label::new("Preview").into_any_element())
 9420                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9421                    )
 9422                })
 9423                .into_any(),
 9424        )
 9425    }
 9426
 9427    fn render_edit_prediction_cursor_popover_preview(
 9428        &self,
 9429        completion: &EditPredictionState,
 9430        cursor_point: Point,
 9431        style: &EditorStyle,
 9432        cx: &mut Context<Editor>,
 9433    ) -> Option<Div> {
 9434        use text::ToPoint as _;
 9435
 9436        fn render_relative_row_jump(
 9437            prefix: impl Into<String>,
 9438            current_row: u32,
 9439            target_row: u32,
 9440        ) -> Div {
 9441            let (row_diff, arrow) = if target_row < current_row {
 9442                (current_row - target_row, IconName::ArrowUp)
 9443            } else {
 9444                (target_row - current_row, IconName::ArrowDown)
 9445            };
 9446
 9447            h_flex()
 9448                .child(
 9449                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9450                        .color(Color::Muted)
 9451                        .size(LabelSize::Small),
 9452                )
 9453                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9454        }
 9455
 9456        let supports_jump = self
 9457            .edit_prediction_provider
 9458            .as_ref()
 9459            .map(|provider| provider.provider.supports_jump_to_edit())
 9460            .unwrap_or(true);
 9461
 9462        match &completion.completion {
 9463            EditPrediction::Move {
 9464                target, snapshot, ..
 9465            } => {
 9466                if !supports_jump {
 9467                    return None;
 9468                }
 9469
 9470                Some(
 9471                    h_flex()
 9472                        .px_2()
 9473                        .gap_2()
 9474                        .flex_1()
 9475                        .child(
 9476                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9477                                Icon::new(IconName::ZedPredictDown)
 9478                            } else {
 9479                                Icon::new(IconName::ZedPredictUp)
 9480                            },
 9481                        )
 9482                        .child(Label::new("Jump to Edit")),
 9483                )
 9484            }
 9485
 9486            EditPrediction::Edit {
 9487                edits,
 9488                edit_preview,
 9489                snapshot,
 9490                display_mode: _,
 9491            } => {
 9492                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9493
 9494                let (highlighted_edits, has_more_lines) =
 9495                    if let Some(edit_preview) = edit_preview.as_ref() {
 9496                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9497                            .first_line_preview()
 9498                    } else {
 9499                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9500                    };
 9501
 9502                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9503                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9504
 9505                let preview = h_flex()
 9506                    .gap_1()
 9507                    .min_w_16()
 9508                    .child(styled_text)
 9509                    .when(has_more_lines, |parent| parent.child(""));
 9510
 9511                let left = if supports_jump && first_edit_row != cursor_point.row {
 9512                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9513                        .into_any_element()
 9514                } else {
 9515                    let icon_name =
 9516                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9517                    Icon::new(icon_name).into_any_element()
 9518                };
 9519
 9520                Some(
 9521                    h_flex()
 9522                        .h_full()
 9523                        .flex_1()
 9524                        .gap_2()
 9525                        .pr_1()
 9526                        .overflow_x_hidden()
 9527                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9528                        .child(left)
 9529                        .child(preview),
 9530                )
 9531            }
 9532        }
 9533    }
 9534
 9535    pub fn render_context_menu(
 9536        &self,
 9537        style: &EditorStyle,
 9538        max_height_in_lines: u32,
 9539        window: &mut Window,
 9540        cx: &mut Context<Editor>,
 9541    ) -> Option<AnyElement> {
 9542        let menu = self.context_menu.borrow();
 9543        let menu = menu.as_ref()?;
 9544        if !menu.visible() {
 9545            return None;
 9546        };
 9547        Some(menu.render(style, max_height_in_lines, window, cx))
 9548    }
 9549
 9550    fn render_context_menu_aside(
 9551        &mut self,
 9552        max_size: Size<Pixels>,
 9553        window: &mut Window,
 9554        cx: &mut Context<Editor>,
 9555    ) -> Option<AnyElement> {
 9556        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9557            if menu.visible() {
 9558                menu.render_aside(max_size, window, cx)
 9559            } else {
 9560                None
 9561            }
 9562        })
 9563    }
 9564
 9565    fn hide_context_menu(
 9566        &mut self,
 9567        window: &mut Window,
 9568        cx: &mut Context<Self>,
 9569    ) -> Option<CodeContextMenu> {
 9570        cx.notify();
 9571        self.completion_tasks.clear();
 9572        let context_menu = self.context_menu.borrow_mut().take();
 9573        self.stale_edit_prediction_in_menu.take();
 9574        self.update_visible_edit_prediction(window, cx);
 9575        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9576            && let Some(completion_provider) = &self.completion_provider
 9577        {
 9578            completion_provider.selection_changed(None, window, cx);
 9579        }
 9580        context_menu
 9581    }
 9582
 9583    fn show_snippet_choices(
 9584        &mut self,
 9585        choices: &Vec<String>,
 9586        selection: Range<Anchor>,
 9587        cx: &mut Context<Self>,
 9588    ) {
 9589        let Some((_, buffer, _)) = self
 9590            .buffer()
 9591            .read(cx)
 9592            .excerpt_containing(selection.start, cx)
 9593        else {
 9594            return;
 9595        };
 9596        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9597        else {
 9598            return;
 9599        };
 9600        if buffer != end_buffer {
 9601            log::error!("expected anchor range to have matching buffer IDs");
 9602            return;
 9603        }
 9604
 9605        let id = post_inc(&mut self.next_completion_id);
 9606        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9607        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9608            CompletionsMenu::new_snippet_choices(
 9609                id,
 9610                true,
 9611                choices,
 9612                selection,
 9613                buffer,
 9614                snippet_sort_order,
 9615            ),
 9616        ));
 9617    }
 9618
 9619    pub fn insert_snippet(
 9620        &mut self,
 9621        insertion_ranges: &[Range<usize>],
 9622        snippet: Snippet,
 9623        window: &mut Window,
 9624        cx: &mut Context<Self>,
 9625    ) -> Result<()> {
 9626        struct Tabstop<T> {
 9627            is_end_tabstop: bool,
 9628            ranges: Vec<Range<T>>,
 9629            choices: Option<Vec<String>>,
 9630        }
 9631
 9632        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9633            let snippet_text: Arc<str> = snippet.text.clone().into();
 9634            let edits = insertion_ranges
 9635                .iter()
 9636                .cloned()
 9637                .map(|range| (range, snippet_text.clone()));
 9638            let autoindent_mode = AutoindentMode::Block {
 9639                original_indent_columns: Vec::new(),
 9640            };
 9641            buffer.edit(edits, Some(autoindent_mode), cx);
 9642
 9643            let snapshot = &*buffer.read(cx);
 9644            let snippet = &snippet;
 9645            snippet
 9646                .tabstops
 9647                .iter()
 9648                .map(|tabstop| {
 9649                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9650                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9651                    });
 9652                    let mut tabstop_ranges = tabstop
 9653                        .ranges
 9654                        .iter()
 9655                        .flat_map(|tabstop_range| {
 9656                            let mut delta = 0_isize;
 9657                            insertion_ranges.iter().map(move |insertion_range| {
 9658                                let insertion_start = insertion_range.start as isize + delta;
 9659                                delta +=
 9660                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9661
 9662                                let start = ((insertion_start + tabstop_range.start) as usize)
 9663                                    .min(snapshot.len());
 9664                                let end = ((insertion_start + tabstop_range.end) as usize)
 9665                                    .min(snapshot.len());
 9666                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9667                            })
 9668                        })
 9669                        .collect::<Vec<_>>();
 9670                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9671
 9672                    Tabstop {
 9673                        is_end_tabstop,
 9674                        ranges: tabstop_ranges,
 9675                        choices: tabstop.choices.clone(),
 9676                    }
 9677                })
 9678                .collect::<Vec<_>>()
 9679        });
 9680        if let Some(tabstop) = tabstops.first() {
 9681            self.change_selections(Default::default(), window, cx, |s| {
 9682                // Reverse order so that the first range is the newest created selection.
 9683                // Completions will use it and autoscroll will prioritize it.
 9684                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9685            });
 9686
 9687            if let Some(choices) = &tabstop.choices
 9688                && let Some(selection) = tabstop.ranges.first()
 9689            {
 9690                self.show_snippet_choices(choices, selection.clone(), cx)
 9691            }
 9692
 9693            // If we're already at the last tabstop and it's at the end of the snippet,
 9694            // we're done, we don't need to keep the state around.
 9695            if !tabstop.is_end_tabstop {
 9696                let choices = tabstops
 9697                    .iter()
 9698                    .map(|tabstop| tabstop.choices.clone())
 9699                    .collect();
 9700
 9701                let ranges = tabstops
 9702                    .into_iter()
 9703                    .map(|tabstop| tabstop.ranges)
 9704                    .collect::<Vec<_>>();
 9705
 9706                self.snippet_stack.push(SnippetState {
 9707                    active_index: 0,
 9708                    ranges,
 9709                    choices,
 9710                });
 9711            }
 9712
 9713            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9714            if self.autoclose_regions.is_empty() {
 9715                let snapshot = self.buffer.read(cx).snapshot(cx);
 9716                let mut all_selections = self.selections.all::<Point>(cx);
 9717                for selection in &mut all_selections {
 9718                    let selection_head = selection.head();
 9719                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9720                        continue;
 9721                    };
 9722
 9723                    let mut bracket_pair = None;
 9724                    let max_lookup_length = scope
 9725                        .brackets()
 9726                        .map(|(pair, _)| {
 9727                            pair.start
 9728                                .as_str()
 9729                                .chars()
 9730                                .count()
 9731                                .max(pair.end.as_str().chars().count())
 9732                        })
 9733                        .max();
 9734                    if let Some(max_lookup_length) = max_lookup_length {
 9735                        let next_text = snapshot
 9736                            .chars_at(selection_head)
 9737                            .take(max_lookup_length)
 9738                            .collect::<String>();
 9739                        let prev_text = snapshot
 9740                            .reversed_chars_at(selection_head)
 9741                            .take(max_lookup_length)
 9742                            .collect::<String>();
 9743
 9744                        for (pair, enabled) in scope.brackets() {
 9745                            if enabled
 9746                                && pair.close
 9747                                && prev_text.starts_with(pair.start.as_str())
 9748                                && next_text.starts_with(pair.end.as_str())
 9749                            {
 9750                                bracket_pair = Some(pair.clone());
 9751                                break;
 9752                            }
 9753                        }
 9754                    }
 9755
 9756                    if let Some(pair) = bracket_pair {
 9757                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9758                        let autoclose_enabled =
 9759                            self.use_autoclose && snapshot_settings.use_autoclose;
 9760                        if autoclose_enabled {
 9761                            let start = snapshot.anchor_after(selection_head);
 9762                            let end = snapshot.anchor_after(selection_head);
 9763                            self.autoclose_regions.push(AutocloseRegion {
 9764                                selection_id: selection.id,
 9765                                range: start..end,
 9766                                pair,
 9767                            });
 9768                        }
 9769                    }
 9770                }
 9771            }
 9772        }
 9773        Ok(())
 9774    }
 9775
 9776    pub fn move_to_next_snippet_tabstop(
 9777        &mut self,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) -> bool {
 9781        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9782    }
 9783
 9784    pub fn move_to_prev_snippet_tabstop(
 9785        &mut self,
 9786        window: &mut Window,
 9787        cx: &mut Context<Self>,
 9788    ) -> bool {
 9789        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9790    }
 9791
 9792    pub fn move_to_snippet_tabstop(
 9793        &mut self,
 9794        bias: Bias,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) -> bool {
 9798        if let Some(mut snippet) = self.snippet_stack.pop() {
 9799            match bias {
 9800                Bias::Left => {
 9801                    if snippet.active_index > 0 {
 9802                        snippet.active_index -= 1;
 9803                    } else {
 9804                        self.snippet_stack.push(snippet);
 9805                        return false;
 9806                    }
 9807                }
 9808                Bias::Right => {
 9809                    if snippet.active_index + 1 < snippet.ranges.len() {
 9810                        snippet.active_index += 1;
 9811                    } else {
 9812                        self.snippet_stack.push(snippet);
 9813                        return false;
 9814                    }
 9815                }
 9816            }
 9817            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9818                self.change_selections(Default::default(), window, cx, |s| {
 9819                    // Reverse order so that the first range is the newest created selection.
 9820                    // Completions will use it and autoscroll will prioritize it.
 9821                    s.select_ranges(current_ranges.iter().rev().cloned())
 9822                });
 9823
 9824                if let Some(choices) = &snippet.choices[snippet.active_index]
 9825                    && let Some(selection) = current_ranges.first()
 9826                {
 9827                    self.show_snippet_choices(choices, selection.clone(), cx);
 9828                }
 9829
 9830                // If snippet state is not at the last tabstop, push it back on the stack
 9831                if snippet.active_index + 1 < snippet.ranges.len() {
 9832                    self.snippet_stack.push(snippet);
 9833                }
 9834                return true;
 9835            }
 9836        }
 9837
 9838        false
 9839    }
 9840
 9841    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9842        self.transact(window, cx, |this, window, cx| {
 9843            this.select_all(&SelectAll, window, cx);
 9844            this.insert("", window, cx);
 9845        });
 9846    }
 9847
 9848    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9849        if self.read_only(cx) {
 9850            return;
 9851        }
 9852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_autoclose_pair(window, cx);
 9855            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9856            if !this.linked_edit_ranges.is_empty() {
 9857                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9858                let snapshot = this.buffer.read(cx).snapshot(cx);
 9859
 9860                for selection in selections.iter() {
 9861                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9862                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9863                    if selection_start.buffer_id != selection_end.buffer_id {
 9864                        continue;
 9865                    }
 9866                    if let Some(ranges) =
 9867                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9868                    {
 9869                        for (buffer, entries) in ranges {
 9870                            linked_ranges.entry(buffer).or_default().extend(entries);
 9871                        }
 9872                    }
 9873                }
 9874            }
 9875
 9876            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9877            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9878            for selection in &mut selections {
 9879                if selection.is_empty() {
 9880                    let old_head = selection.head();
 9881                    let mut new_head =
 9882                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9883                            .to_point(&display_map);
 9884                    if let Some((buffer, line_buffer_range)) = display_map
 9885                        .buffer_snapshot
 9886                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9887                    {
 9888                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9889                        let indent_len = match indent_size.kind {
 9890                            IndentKind::Space => {
 9891                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9892                            }
 9893                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9894                        };
 9895                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9896                            let indent_len = indent_len.get();
 9897                            new_head = cmp::min(
 9898                                new_head,
 9899                                MultiBufferPoint::new(
 9900                                    old_head.row,
 9901                                    ((old_head.column - 1) / indent_len) * indent_len,
 9902                                ),
 9903                            );
 9904                        }
 9905                    }
 9906
 9907                    selection.set_head(new_head, SelectionGoal::None);
 9908                }
 9909            }
 9910
 9911            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9912            this.insert("", window, cx);
 9913            let empty_str: Arc<str> = Arc::from("");
 9914            for (buffer, edits) in linked_ranges {
 9915                let snapshot = buffer.read(cx).snapshot();
 9916                use text::ToPoint as TP;
 9917
 9918                let edits = edits
 9919                    .into_iter()
 9920                    .map(|range| {
 9921                        let end_point = TP::to_point(&range.end, &snapshot);
 9922                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9923
 9924                        if end_point == start_point {
 9925                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9926                                .saturating_sub(1);
 9927                            start_point =
 9928                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9929                        };
 9930
 9931                        (start_point..end_point, empty_str.clone())
 9932                    })
 9933                    .sorted_by_key(|(range, _)| range.start)
 9934                    .collect::<Vec<_>>();
 9935                buffer.update(cx, |this, cx| {
 9936                    this.edit(edits, None, cx);
 9937                })
 9938            }
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.change_selections(Default::default(), window, cx, |s| {
 9951                s.move_with(|map, selection| {
 9952                    if selection.is_empty() {
 9953                        let cursor = movement::right(map, selection.head());
 9954                        selection.end = cursor;
 9955                        selection.reversed = true;
 9956                        selection.goal = SelectionGoal::None;
 9957                    }
 9958                })
 9959            });
 9960            this.insert("", window, cx);
 9961            this.refresh_edit_prediction(true, false, window, cx);
 9962        });
 9963    }
 9964
 9965    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9966        if self.mode.is_single_line() {
 9967            cx.propagate();
 9968            return;
 9969        }
 9970
 9971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9972        if self.move_to_prev_snippet_tabstop(window, cx) {
 9973            return;
 9974        }
 9975        self.outdent(&Outdent, window, cx);
 9976    }
 9977
 9978    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.mode.is_single_line() {
 9980            cx.propagate();
 9981            return;
 9982        }
 9983
 9984        if self.move_to_next_snippet_tabstop(window, cx) {
 9985            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9986            return;
 9987        }
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9992        let mut selections = self.selections.all_adjusted(cx);
 9993        let buffer = self.buffer.read(cx);
 9994        let snapshot = buffer.snapshot(cx);
 9995        let rows_iter = selections.iter().map(|s| s.head().row);
 9996        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9997
 9998        let has_some_cursor_in_whitespace = selections
 9999            .iter()
10000            .filter(|selection| selection.is_empty())
10001            .any(|selection| {
10002                let cursor = selection.head();
10003                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004                cursor.column < current_indent.len
10005            });
10006
10007        let mut edits = Vec::new();
10008        let mut prev_edited_row = 0;
10009        let mut row_delta = 0;
10010        for selection in &mut selections {
10011            if selection.start.row != prev_edited_row {
10012                row_delta = 0;
10013            }
10014            prev_edited_row = selection.end.row;
10015
10016            // If the selection is non-empty, then increase the indentation of the selected lines.
10017            if !selection.is_empty() {
10018                row_delta =
10019                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10020                continue;
10021            }
10022
10023            let cursor = selection.head();
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10025            if let Some(suggested_indent) =
10026                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10027            {
10028                // Don't do anything if already at suggested indent
10029                // and there is any other cursor which is not
10030                if has_some_cursor_in_whitespace
10031                    && cursor.column == current_indent.len
10032                    && current_indent.len == suggested_indent.len
10033                {
10034                    continue;
10035                }
10036
10037                // Adjust line and move cursor to suggested indent
10038                // if cursor is not at suggested indent
10039                if cursor.column < suggested_indent.len
10040                    && cursor.column <= current_indent.len
10041                    && current_indent.len <= suggested_indent.len
10042                {
10043                    selection.start = Point::new(cursor.row, suggested_indent.len);
10044                    selection.end = selection.start;
10045                    if row_delta == 0 {
10046                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10047                            cursor.row,
10048                            current_indent,
10049                            suggested_indent,
10050                        ));
10051                        row_delta = suggested_indent.len - current_indent.len;
10052                    }
10053                    continue;
10054                }
10055
10056                // If current indent is more than suggested indent
10057                // only move cursor to current indent and skip indent
10058                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10059                    selection.start = Point::new(cursor.row, current_indent.len);
10060                    selection.end = selection.start;
10061                    continue;
10062                }
10063            }
10064
10065            // Otherwise, insert a hard or soft tab.
10066            let settings = buffer.language_settings_at(cursor, cx);
10067            let tab_size = if settings.hard_tabs {
10068                IndentSize::tab()
10069            } else {
10070                let tab_size = settings.tab_size.get();
10071                let indent_remainder = snapshot
10072                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10073                    .flat_map(str::chars)
10074                    .fold(row_delta % tab_size, |counter: u32, c| {
10075                        if c == '\t' {
10076                            0
10077                        } else {
10078                            (counter + 1) % tab_size
10079                        }
10080                    });
10081
10082                let chars_to_next_tab_stop = tab_size - indent_remainder;
10083                IndentSize::spaces(chars_to_next_tab_stop)
10084            };
10085            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10086            selection.end = selection.start;
10087            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10088            row_delta += tab_size.len;
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.refresh_edit_prediction(true, false, window, cx);
10095        });
10096    }
10097
10098    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut selections = self.selections.all::<Point>(cx);
10109        let mut prev_edited_row = 0;
10110        let mut row_delta = 0;
10111        let mut edits = Vec::new();
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        for selection in &mut selections {
10115            if selection.start.row != prev_edited_row {
10116                row_delta = 0;
10117            }
10118            prev_edited_row = selection.end.row;
10119
10120            row_delta =
10121                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10122        }
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10126            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10127        });
10128    }
10129
10130    fn indent_selection(
10131        buffer: &MultiBuffer,
10132        snapshot: &MultiBufferSnapshot,
10133        selection: &mut Selection<Point>,
10134        edits: &mut Vec<(Range<Point>, String)>,
10135        delta_for_start_row: u32,
10136        cx: &App,
10137    ) -> u32 {
10138        let settings = buffer.language_settings_at(selection.start, cx);
10139        let tab_size = settings.tab_size.get();
10140        let indent_kind = if settings.hard_tabs {
10141            IndentKind::Tab
10142        } else {
10143            IndentKind::Space
10144        };
10145        let mut start_row = selection.start.row;
10146        let mut end_row = selection.end.row + 1;
10147
10148        // If a selection ends at the beginning of a line, don't indent
10149        // that last line.
10150        if selection.end.column == 0 && selection.end.row > selection.start.row {
10151            end_row -= 1;
10152        }
10153
10154        // Avoid re-indenting a row that has already been indented by a
10155        // previous selection, but still update this selection's column
10156        // to reflect that indentation.
10157        if delta_for_start_row > 0 {
10158            start_row += 1;
10159            selection.start.column += delta_for_start_row;
10160            if selection.end.row == selection.start.row {
10161                selection.end.column += delta_for_start_row;
10162            }
10163        }
10164
10165        let mut delta_for_end_row = 0;
10166        let has_multiple_rows = start_row + 1 != end_row;
10167        for row in start_row..end_row {
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10169            let indent_delta = match (current_indent.kind, indent_kind) {
10170                (IndentKind::Space, IndentKind::Space) => {
10171                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10172                    IndentSize::spaces(columns_to_next_tab_stop)
10173                }
10174                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10175                (_, IndentKind::Tab) => IndentSize::tab(),
10176            };
10177
10178            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10179                0
10180            } else {
10181                selection.start.column
10182            };
10183            let row_start = Point::new(row, start);
10184            edits.push((
10185                row_start..row_start,
10186                indent_delta.chars().collect::<String>(),
10187            ));
10188
10189            // Update this selection's endpoints to reflect the indentation.
10190            if row == selection.start.row {
10191                selection.start.column += indent_delta.len;
10192            }
10193            if row == selection.end.row {
10194                selection.end.column += indent_delta.len;
10195                delta_for_end_row = indent_delta.len;
10196            }
10197        }
10198
10199        if selection.start.row == selection.end.row {
10200            delta_for_start_row + delta_for_end_row
10201        } else {
10202            delta_for_end_row
10203        }
10204    }
10205
10206    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10216        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10217        let selections = self.selections.all::<Point>(cx);
10218        let mut deletion_ranges = Vec::new();
10219        let mut last_outdent = None;
10220        {
10221            let buffer = self.buffer.read(cx);
10222            let snapshot = buffer.snapshot(cx);
10223            for selection in &selections {
10224                let settings = buffer.language_settings_at(selection.start, cx);
10225                let tab_size = settings.tab_size.get();
10226                let mut rows = selection.spanned_rows(false, &display_map);
10227
10228                // Avoid re-outdenting a row that has already been outdented by a
10229                // previous selection.
10230                if let Some(last_row) = last_outdent
10231                    && last_row == rows.start
10232                {
10233                    rows.start = rows.start.next_row();
10234                }
10235                let has_multiple_rows = rows.len() > 1;
10236                for row in rows.iter_rows() {
10237                    let indent_size = snapshot.indent_size_for_line(row);
10238                    if indent_size.len > 0 {
10239                        let deletion_len = match indent_size.kind {
10240                            IndentKind::Space => {
10241                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10242                                if columns_to_prev_tab_stop == 0 {
10243                                    tab_size
10244                                } else {
10245                                    columns_to_prev_tab_stop
10246                                }
10247                            }
10248                            IndentKind::Tab => 1,
10249                        };
10250                        let start = if has_multiple_rows
10251                            || deletion_len > selection.start.column
10252                            || indent_size.len < selection.start.column
10253                        {
10254                            0
10255                        } else {
10256                            selection.start.column - deletion_len
10257                        };
10258                        deletion_ranges.push(
10259                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10260                        );
10261                        last_outdent = Some(row);
10262                    }
10263                }
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, window, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                let empty_str: Arc<str> = Arc::default();
10270                buffer.edit(
10271                    deletion_ranges
10272                        .into_iter()
10273                        .map(|range| (range, empty_str.clone())),
10274                    None,
10275                    cx,
10276                );
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10284        if self.read_only(cx) {
10285            return;
10286        }
10287        if self.mode.is_single_line() {
10288            cx.propagate();
10289            return;
10290        }
10291
10292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10293        let selections = self
10294            .selections
10295            .all::<usize>(cx)
10296            .into_iter()
10297            .map(|s| s.range());
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |buffer, cx| {
10301                buffer.autoindent_ranges(selections, cx);
10302            });
10303            let selections = this.selections.all::<usize>(cx);
10304            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10305        });
10306    }
10307
10308    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10311        let selections = self.selections.all::<Point>(cx);
10312
10313        let mut new_cursors = Vec::new();
10314        let mut edit_ranges = Vec::new();
10315        let mut selections = selections.iter().peekable();
10316        while let Some(selection) = selections.next() {
10317            let mut rows = selection.spanned_rows(false, &display_map);
10318            let goal_display_column = selection.head().to_display_point(&display_map).column();
10319
10320            // Accumulate contiguous regions of rows that we want to delete.
10321            while let Some(next_selection) = selections.peek() {
10322                let next_rows = next_selection.spanned_rows(false, &display_map);
10323                if next_rows.start <= rows.end {
10324                    rows.end = next_rows.end;
10325                    selections.next().unwrap();
10326                } else {
10327                    break;
10328                }
10329            }
10330
10331            let buffer = &display_map.buffer_snapshot;
10332            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10333            let edit_end;
10334            let cursor_buffer_row;
10335            if buffer.max_point().row >= rows.end.0 {
10336                // If there's a line after the range, delete the \n from the end of the row range
10337                // and position the cursor on the next line.
10338                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10339                cursor_buffer_row = rows.end;
10340            } else {
10341                // If there isn't a line after the range, delete the \n from the line before the
10342                // start of the row range and position the cursor there.
10343                edit_start = edit_start.saturating_sub(1);
10344                edit_end = buffer.len();
10345                cursor_buffer_row = rows.start.previous_row();
10346            }
10347
10348            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10349            *cursor.column_mut() =
10350                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10351
10352            new_cursors.push((
10353                selection.id,
10354                buffer.anchor_after(cursor.to_point(&display_map)),
10355            ));
10356            edit_ranges.push(edit_start..edit_end);
10357        }
10358
10359        self.transact(window, cx, |this, window, cx| {
10360            let buffer = this.buffer.update(cx, |buffer, cx| {
10361                let empty_str: Arc<str> = Arc::default();
10362                buffer.edit(
10363                    edit_ranges
10364                        .into_iter()
10365                        .map(|range| (range, empty_str.clone())),
10366                    None,
10367                    cx,
10368                );
10369                buffer.snapshot(cx)
10370            });
10371            let new_selections = new_cursors
10372                .into_iter()
10373                .map(|(id, cursor)| {
10374                    let cursor = cursor.to_point(&buffer);
10375                    Selection {
10376                        id,
10377                        start: cursor,
10378                        end: cursor,
10379                        reversed: false,
10380                        goal: SelectionGoal::None,
10381                    }
10382                })
10383                .collect();
10384
10385            this.change_selections(Default::default(), window, cx, |s| {
10386                s.select(new_selections);
10387            });
10388        });
10389    }
10390
10391    pub fn join_lines_impl(
10392        &mut self,
10393        insert_whitespace: bool,
10394        window: &mut Window,
10395        cx: &mut Context<Self>,
10396    ) {
10397        if self.read_only(cx) {
10398            return;
10399        }
10400        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10401        for selection in self.selections.all::<Point>(cx) {
10402            let start = MultiBufferRow(selection.start.row);
10403            // Treat single line selections as if they include the next line. Otherwise this action
10404            // would do nothing for single line selections individual cursors.
10405            let end = if selection.start.row == selection.end.row {
10406                MultiBufferRow(selection.start.row + 1)
10407            } else {
10408                MultiBufferRow(selection.end.row)
10409            };
10410
10411            if let Some(last_row_range) = row_ranges.last_mut()
10412                && start <= last_row_range.end
10413            {
10414                last_row_range.end = end;
10415                continue;
10416            }
10417            row_ranges.push(start..end);
10418        }
10419
10420        let snapshot = self.buffer.read(cx).snapshot(cx);
10421        let mut cursor_positions = Vec::new();
10422        for row_range in &row_ranges {
10423            let anchor = snapshot.anchor_before(Point::new(
10424                row_range.end.previous_row().0,
10425                snapshot.line_len(row_range.end.previous_row()),
10426            ));
10427            cursor_positions.push(anchor..anchor);
10428        }
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            for row_range in row_ranges.into_iter().rev() {
10432                for row in row_range.iter_rows().rev() {
10433                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10434                    let next_line_row = row.next_row();
10435                    let indent = snapshot.indent_size_for_line(next_line_row);
10436                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10437
10438                    let replace =
10439                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10440                            " "
10441                        } else {
10442                            ""
10443                        };
10444
10445                    this.buffer.update(cx, |buffer, cx| {
10446                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10447                    });
10448                }
10449            }
10450
10451            this.change_selections(Default::default(), window, cx, |s| {
10452                s.select_anchor_ranges(cursor_positions)
10453            });
10454        });
10455    }
10456
10457    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        self.join_lines_impl(true, window, cx);
10460    }
10461
10462    pub fn sort_lines_case_sensitive(
10463        &mut self,
10464        _: &SortLinesCaseSensitive,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10469    }
10470
10471    pub fn sort_lines_by_length(
10472        &mut self,
10473        _: &SortLinesByLength,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        self.manipulate_immutable_lines(window, cx, |lines| {
10478            lines.sort_by_key(|&line| line.chars().count())
10479        })
10480    }
10481
10482    pub fn sort_lines_case_insensitive(
10483        &mut self,
10484        _: &SortLinesCaseInsensitive,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|line| line.to_lowercase())
10490        })
10491    }
10492
10493    pub fn unique_lines_case_insensitive(
10494        &mut self,
10495        _: &UniqueLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            let mut seen = HashSet::default();
10501            lines.retain(|line| seen.insert(line.to_lowercase()));
10502        })
10503    }
10504
10505    pub fn unique_lines_case_sensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseSensitive,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_immutable_lines(window, cx, |lines| {
10512            let mut seen = HashSet::default();
10513            lines.retain(|line| seen.insert(*line));
10514        })
10515    }
10516
10517    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10518        let snapshot = self.buffer.read(cx).snapshot(cx);
10519        for selection in self.selections.disjoint_anchors_arc().iter() {
10520            if snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.as_ref())
10523                .is_some()
10524            {
10525                return true;
10526            }
10527        }
10528        false
10529    }
10530
10531    fn wrap_selections_in_tag(
10532        &mut self,
10533        _: &WrapSelectionsInTag,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) {
10537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10538
10539        let snapshot = self.buffer.read(cx).snapshot(cx);
10540
10541        let mut edits = Vec::new();
10542        let mut boundaries = Vec::new();
10543
10544        for selection in self.selections.all::<Point>(cx).iter() {
10545            let Some(wrap_config) = snapshot
10546                .language_at(selection.start)
10547                .and_then(|lang| lang.config().wrap_characters.clone())
10548            else {
10549                continue;
10550            };
10551
10552            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10553            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10554
10555            let start_before = snapshot.anchor_before(selection.start);
10556            let end_after = snapshot.anchor_after(selection.end);
10557
10558            edits.push((start_before..start_before, open_tag));
10559            edits.push((end_after..end_after, close_tag));
10560
10561            boundaries.push((
10562                start_before,
10563                end_after,
10564                wrap_config.start_prefix.len(),
10565                wrap_config.end_suffix.len(),
10566            ));
10567        }
10568
10569        if edits.is_empty() {
10570            return;
10571        }
10572
10573        self.transact(window, cx, |this, window, cx| {
10574            let buffer = this.buffer.update(cx, |buffer, cx| {
10575                buffer.edit(edits, None, cx);
10576                buffer.snapshot(cx)
10577            });
10578
10579            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10580            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10581                boundaries.into_iter()
10582            {
10583                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10584                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10585                new_selections.push(open_offset..open_offset);
10586                new_selections.push(close_offset..close_offset);
10587            }
10588
10589            this.change_selections(Default::default(), window, cx, |s| {
10590                s.select_ranges(new_selections);
10591            });
10592
10593            this.request_autoscroll(Autoscroll::fit(), cx);
10594        });
10595    }
10596
10597    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10598        let Some(project) = self.project.clone() else {
10599            return;
10600        };
10601        self.reload(project, window, cx)
10602            .detach_and_notify_err(window, cx);
10603    }
10604
10605    pub fn restore_file(
10606        &mut self,
10607        _: &::git::RestoreFile,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let mut buffer_ids = HashSet::default();
10613        let snapshot = self.buffer().read(cx).snapshot(cx);
10614        for selection in self.selections.all::<usize>(cx) {
10615            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10616        }
10617
10618        let buffer = self.buffer().read(cx);
10619        let ranges = buffer_ids
10620            .into_iter()
10621            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10622            .collect::<Vec<_>>();
10623
10624        self.restore_hunks_in_ranges(ranges, window, cx);
10625    }
10626
10627    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629        let selections = self
10630            .selections
10631            .all(cx)
10632            .into_iter()
10633            .map(|s| s.range())
10634            .collect();
10635        self.restore_hunks_in_ranges(selections, window, cx);
10636    }
10637
10638    pub fn restore_hunks_in_ranges(
10639        &mut self,
10640        ranges: Vec<Range<Point>>,
10641        window: &mut Window,
10642        cx: &mut Context<Editor>,
10643    ) {
10644        let mut revert_changes = HashMap::default();
10645        let chunk_by = self
10646            .snapshot(window, cx)
10647            .hunks_for_ranges(ranges)
10648            .into_iter()
10649            .chunk_by(|hunk| hunk.buffer_id);
10650        for (buffer_id, hunks) in &chunk_by {
10651            let hunks = hunks.collect::<Vec<_>>();
10652            for hunk in &hunks {
10653                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10654            }
10655            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10656        }
10657        drop(chunk_by);
10658        if !revert_changes.is_empty() {
10659            self.transact(window, cx, |editor, window, cx| {
10660                editor.restore(revert_changes, window, cx);
10661            });
10662        }
10663    }
10664
10665    pub fn open_active_item_in_terminal(
10666        &mut self,
10667        _: &OpenInTerminal,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10672            let project_path = buffer.read(cx).project_path(cx)?;
10673            let project = self.project()?.read(cx);
10674            let entry = project.entry_for_path(&project_path, cx)?;
10675            let parent = match &entry.canonical_path {
10676                Some(canonical_path) => canonical_path.to_path_buf(),
10677                None => project.absolute_path(&project_path, cx)?,
10678            }
10679            .parent()?
10680            .to_path_buf();
10681            Some(parent)
10682        }) {
10683            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10684        }
10685    }
10686
10687    fn set_breakpoint_context_menu(
10688        &mut self,
10689        display_row: DisplayRow,
10690        position: Option<Anchor>,
10691        clicked_point: gpui::Point<Pixels>,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let source = self
10696            .buffer
10697            .read(cx)
10698            .snapshot(cx)
10699            .anchor_before(Point::new(display_row.0, 0u32));
10700
10701        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10702
10703        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10704            self,
10705            source,
10706            clicked_point,
10707            context_menu,
10708            window,
10709            cx,
10710        );
10711    }
10712
10713    fn add_edit_breakpoint_block(
10714        &mut self,
10715        anchor: Anchor,
10716        breakpoint: &Breakpoint,
10717        edit_action: BreakpointPromptEditAction,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        let weak_editor = cx.weak_entity();
10722        let bp_prompt = cx.new(|cx| {
10723            BreakpointPromptEditor::new(
10724                weak_editor,
10725                anchor,
10726                breakpoint.clone(),
10727                edit_action,
10728                window,
10729                cx,
10730            )
10731        });
10732
10733        let height = bp_prompt.update(cx, |this, cx| {
10734            this.prompt
10735                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10736        });
10737        let cloned_prompt = bp_prompt.clone();
10738        let blocks = vec![BlockProperties {
10739            style: BlockStyle::Sticky,
10740            placement: BlockPlacement::Above(anchor),
10741            height: Some(height),
10742            render: Arc::new(move |cx| {
10743                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10744                cloned_prompt.clone().into_any_element()
10745            }),
10746            priority: 0,
10747        }];
10748
10749        let focus_handle = bp_prompt.focus_handle(cx);
10750        window.focus(&focus_handle);
10751
10752        let block_ids = self.insert_blocks(blocks, None, cx);
10753        bp_prompt.update(cx, |prompt, _| {
10754            prompt.add_block_ids(block_ids);
10755        });
10756    }
10757
10758    pub(crate) fn breakpoint_at_row(
10759        &self,
10760        row: u32,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) -> Option<(Anchor, Breakpoint)> {
10764        let snapshot = self.snapshot(window, cx);
10765        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10766
10767        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10768    }
10769
10770    pub(crate) fn breakpoint_at_anchor(
10771        &self,
10772        breakpoint_position: Anchor,
10773        snapshot: &EditorSnapshot,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let buffer = self
10777            .buffer
10778            .read(cx)
10779            .buffer_for_anchor(breakpoint_position, cx)?;
10780
10781        let enclosing_excerpt = breakpoint_position.excerpt_id;
10782        let buffer_snapshot = buffer.read(cx).snapshot();
10783
10784        let row = buffer_snapshot
10785            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10786            .row;
10787
10788        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10789        let anchor_end = snapshot
10790            .buffer_snapshot
10791            .anchor_after(Point::new(row, line_len));
10792
10793        self.breakpoint_store
10794            .as_ref()?
10795            .read_with(cx, |breakpoint_store, cx| {
10796                breakpoint_store
10797                    .breakpoints(
10798                        &buffer,
10799                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10800                        &buffer_snapshot,
10801                        cx,
10802                    )
10803                    .next()
10804                    .and_then(|(bp, _)| {
10805                        let breakpoint_row = buffer_snapshot
10806                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10807                            .row;
10808
10809                        if breakpoint_row == row {
10810                            snapshot
10811                                .buffer_snapshot
10812                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10813                                .map(|position| (position, bp.bp.clone()))
10814                        } else {
10815                            None
10816                        }
10817                    })
10818            })
10819    }
10820
10821    pub fn edit_log_breakpoint(
10822        &mut self,
10823        _: &EditLogBreakpoint,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10828            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10829                message: None,
10830                state: BreakpointState::Enabled,
10831                condition: None,
10832                hit_condition: None,
10833            });
10834
10835            self.add_edit_breakpoint_block(
10836                anchor,
10837                &breakpoint,
10838                BreakpointPromptEditAction::Log,
10839                window,
10840                cx,
10841            );
10842        }
10843    }
10844
10845    fn breakpoints_at_cursors(
10846        &self,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10850        let snapshot = self.snapshot(window, cx);
10851        let cursors = self
10852            .selections
10853            .disjoint_anchors_arc()
10854            .iter()
10855            .map(|selection| {
10856                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10857
10858                let breakpoint_position = self
10859                    .breakpoint_at_row(cursor_position.row, window, cx)
10860                    .map(|bp| bp.0)
10861                    .unwrap_or_else(|| {
10862                        snapshot
10863                            .display_snapshot
10864                            .buffer_snapshot
10865                            .anchor_after(Point::new(cursor_position.row, 0))
10866                    });
10867
10868                let breakpoint = self
10869                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10870                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10871
10872                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10873            })
10874            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
10875            .collect::<HashMap<Anchor, _>>();
10876
10877        cursors.into_iter().collect()
10878    }
10879
10880    pub fn enable_breakpoint(
10881        &mut self,
10882        _: &crate::actions::EnableBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10888                continue;
10889            };
10890            self.edit_breakpoint_at_anchor(
10891                anchor,
10892                breakpoint,
10893                BreakpointEditAction::InvertState,
10894                cx,
10895            );
10896        }
10897    }
10898
10899    pub fn disable_breakpoint(
10900        &mut self,
10901        _: &crate::actions::DisableBreakpoint,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10906            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10907                continue;
10908            };
10909            self.edit_breakpoint_at_anchor(
10910                anchor,
10911                breakpoint,
10912                BreakpointEditAction::InvertState,
10913                cx,
10914            );
10915        }
10916    }
10917
10918    pub fn toggle_breakpoint(
10919        &mut self,
10920        _: &crate::actions::ToggleBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            if let Some(breakpoint) = breakpoint {
10926                self.edit_breakpoint_at_anchor(
10927                    anchor,
10928                    breakpoint,
10929                    BreakpointEditAction::Toggle,
10930                    cx,
10931                );
10932            } else {
10933                self.edit_breakpoint_at_anchor(
10934                    anchor,
10935                    Breakpoint::new_standard(),
10936                    BreakpointEditAction::Toggle,
10937                    cx,
10938                );
10939            }
10940        }
10941    }
10942
10943    pub fn edit_breakpoint_at_anchor(
10944        &mut self,
10945        breakpoint_position: Anchor,
10946        breakpoint: Breakpoint,
10947        edit_action: BreakpointEditAction,
10948        cx: &mut Context<Self>,
10949    ) {
10950        let Some(breakpoint_store) = &self.breakpoint_store else {
10951            return;
10952        };
10953
10954        let Some(buffer) = self
10955            .buffer
10956            .read(cx)
10957            .buffer_for_anchor(breakpoint_position, cx)
10958        else {
10959            return;
10960        };
10961
10962        breakpoint_store.update(cx, |breakpoint_store, cx| {
10963            breakpoint_store.toggle_breakpoint(
10964                buffer,
10965                BreakpointWithPosition {
10966                    position: breakpoint_position.text_anchor,
10967                    bp: breakpoint,
10968                },
10969                edit_action,
10970                cx,
10971            );
10972        });
10973
10974        cx.notify();
10975    }
10976
10977    #[cfg(any(test, feature = "test-support"))]
10978    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10979        self.breakpoint_store.clone()
10980    }
10981
10982    pub fn prepare_restore_change(
10983        &self,
10984        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10985        hunk: &MultiBufferDiffHunk,
10986        cx: &mut App,
10987    ) -> Option<()> {
10988        if hunk.is_created_file() {
10989            return None;
10990        }
10991        let buffer = self.buffer.read(cx);
10992        let diff = buffer.diff_for(hunk.buffer_id)?;
10993        let buffer = buffer.buffer(hunk.buffer_id)?;
10994        let buffer = buffer.read(cx);
10995        let original_text = diff
10996            .read(cx)
10997            .base_text()
10998            .as_rope()
10999            .slice(hunk.diff_base_byte_range.clone());
11000        let buffer_snapshot = buffer.snapshot();
11001        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11002        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11003            probe
11004                .0
11005                .start
11006                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11007                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11008        }) {
11009            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11010            Some(())
11011        } else {
11012            None
11013        }
11014    }
11015
11016    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11018    }
11019
11020    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11022    }
11023
11024    fn manipulate_lines<M>(
11025        &mut self,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028        mut manipulate: M,
11029    ) where
11030        M: FnMut(&str) -> LineManipulationResult,
11031    {
11032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11033
11034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11035        let buffer = self.buffer.read(cx).snapshot(cx);
11036
11037        let mut edits = Vec::new();
11038
11039        let selections = self.selections.all::<Point>(cx);
11040        let mut selections = selections.iter().peekable();
11041        let mut contiguous_row_selections = Vec::new();
11042        let mut new_selections = Vec::new();
11043        let mut added_lines = 0;
11044        let mut removed_lines = 0;
11045
11046        while let Some(selection) = selections.next() {
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            let start_point = Point::new(start_row.0, 0);
11055            let end_point = Point::new(
11056                end_row.previous_row().0,
11057                buffer.line_len(end_row.previous_row()),
11058            );
11059            let text = buffer
11060                .text_for_range(start_point..end_point)
11061                .collect::<String>();
11062
11063            let LineManipulationResult {
11064                new_text,
11065                line_count_before,
11066                line_count_after,
11067            } = manipulate(&text);
11068
11069            edits.push((start_point..end_point, new_text));
11070
11071            // Selections must change based on added and removed line count
11072            let start_row =
11073                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11074            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11075            new_selections.push(Selection {
11076                id: selection.id,
11077                start: start_row,
11078                end: end_row,
11079                goal: SelectionGoal::None,
11080                reversed: selection.reversed,
11081            });
11082
11083            if line_count_after > line_count_before {
11084                added_lines += line_count_after - line_count_before;
11085            } else if line_count_before > line_count_after {
11086                removed_lines += line_count_before - line_count_after;
11087            }
11088        }
11089
11090        self.transact(window, cx, |this, window, cx| {
11091            let buffer = this.buffer.update(cx, |buffer, cx| {
11092                buffer.edit(edits, None, cx);
11093                buffer.snapshot(cx)
11094            });
11095
11096            // Recalculate offsets on newly edited buffer
11097            let new_selections = new_selections
11098                .iter()
11099                .map(|s| {
11100                    let start_point = Point::new(s.start.0, 0);
11101                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11102                    Selection {
11103                        id: s.id,
11104                        start: buffer.point_to_offset(start_point),
11105                        end: buffer.point_to_offset(end_point),
11106                        goal: s.goal,
11107                        reversed: s.reversed,
11108                    }
11109                })
11110                .collect();
11111
11112            this.change_selections(Default::default(), window, cx, |s| {
11113                s.select(new_selections);
11114            });
11115
11116            this.request_autoscroll(Autoscroll::fit(), cx);
11117        });
11118    }
11119
11120    fn manipulate_immutable_lines<Fn>(
11121        &mut self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124        mut callback: Fn,
11125    ) where
11126        Fn: FnMut(&mut Vec<&str>),
11127    {
11128        self.manipulate_lines(window, cx, |text| {
11129            let mut lines: Vec<&str> = text.split('\n').collect();
11130            let line_count_before = lines.len();
11131
11132            callback(&mut lines);
11133
11134            LineManipulationResult {
11135                new_text: lines.join("\n"),
11136                line_count_before,
11137                line_count_after: lines.len(),
11138            }
11139        });
11140    }
11141
11142    fn manipulate_mutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    pub fn convert_indentation_to_spaces(
11165        &mut self,
11166        _: &ConvertIndentationToSpaces,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let settings = self.buffer.read(cx).language_settings(cx);
11171        let tab_size = settings.tab_size.get() as usize;
11172
11173        self.manipulate_mutable_lines(window, cx, |lines| {
11174            // Allocates a reasonably sized scratch buffer once for the whole loop
11175            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11176            // Avoids recomputing spaces that could be inserted many times
11177            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11178                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11179                .collect();
11180
11181            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11182                let mut chars = line.as_ref().chars();
11183                let mut col = 0;
11184                let mut changed = false;
11185
11186                for ch in chars.by_ref() {
11187                    match ch {
11188                        ' ' => {
11189                            reindented_line.push(' ');
11190                            col += 1;
11191                        }
11192                        '\t' => {
11193                            // \t are converted to spaces depending on the current column
11194                            let spaces_len = tab_size - (col % tab_size);
11195                            reindented_line.extend(&space_cache[spaces_len - 1]);
11196                            col += spaces_len;
11197                            changed = true;
11198                        }
11199                        _ => {
11200                            // If we dont append before break, the character is consumed
11201                            reindented_line.push(ch);
11202                            break;
11203                        }
11204                    }
11205                }
11206
11207                if !changed {
11208                    reindented_line.clear();
11209                    continue;
11210                }
11211                // Append the rest of the line and replace old reference with new one
11212                reindented_line.extend(chars);
11213                *line = Cow::Owned(reindented_line.clone());
11214                reindented_line.clear();
11215            }
11216        });
11217    }
11218
11219    pub fn convert_indentation_to_tabs(
11220        &mut self,
11221        _: &ConvertIndentationToTabs,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        let settings = self.buffer.read(cx).language_settings(cx);
11226        let tab_size = settings.tab_size.get() as usize;
11227
11228        self.manipulate_mutable_lines(window, cx, |lines| {
11229            // Allocates a reasonably sized buffer once for the whole loop
11230            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11231            // Avoids recomputing spaces that could be inserted many times
11232            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11233                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11234                .collect();
11235
11236            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11237                let mut chars = line.chars();
11238                let mut spaces_count = 0;
11239                let mut first_non_indent_char = None;
11240                let mut changed = false;
11241
11242                for ch in chars.by_ref() {
11243                    match ch {
11244                        ' ' => {
11245                            // Keep track of spaces. Append \t when we reach tab_size
11246                            spaces_count += 1;
11247                            changed = true;
11248                            if spaces_count == tab_size {
11249                                reindented_line.push('\t');
11250                                spaces_count = 0;
11251                            }
11252                        }
11253                        '\t' => {
11254                            reindented_line.push('\t');
11255                            spaces_count = 0;
11256                        }
11257                        _ => {
11258                            // Dont append it yet, we might have remaining spaces
11259                            first_non_indent_char = Some(ch);
11260                            break;
11261                        }
11262                    }
11263                }
11264
11265                if !changed {
11266                    reindented_line.clear();
11267                    continue;
11268                }
11269                // Remaining spaces that didn't make a full tab stop
11270                if spaces_count > 0 {
11271                    reindented_line.extend(&space_cache[spaces_count - 1]);
11272                }
11273                // If we consume an extra character that was not indentation, add it back
11274                if let Some(extra_char) = first_non_indent_char {
11275                    reindented_line.push(extra_char);
11276                }
11277                // Append the rest of the line and replace old reference with new one
11278                reindented_line.extend(chars);
11279                *line = Cow::Owned(reindented_line.clone());
11280                reindented_line.clear();
11281            }
11282        });
11283    }
11284
11285    pub fn convert_to_upper_case(
11286        &mut self,
11287        _: &ConvertToUpperCase,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.manipulate_text(window, cx, |text| text.to_uppercase())
11292    }
11293
11294    pub fn convert_to_lower_case(
11295        &mut self,
11296        _: &ConvertToLowerCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_lowercase())
11301    }
11302
11303    pub fn convert_to_title_case(
11304        &mut self,
11305        _: &ConvertToTitleCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.split('\n')
11311                .map(|line| line.to_case(Case::Title))
11312                .join("\n")
11313        })
11314    }
11315
11316    pub fn convert_to_snake_case(
11317        &mut self,
11318        _: &ConvertToSnakeCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11323    }
11324
11325    pub fn convert_to_kebab_case(
11326        &mut self,
11327        _: &ConvertToKebabCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11332    }
11333
11334    pub fn convert_to_upper_camel_case(
11335        &mut self,
11336        _: &ConvertToUpperCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| {
11341            text.split('\n')
11342                .map(|line| line.to_case(Case::UpperCamel))
11343                .join("\n")
11344        })
11345    }
11346
11347    pub fn convert_to_lower_camel_case(
11348        &mut self,
11349        _: &ConvertToLowerCamelCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11354    }
11355
11356    pub fn convert_to_opposite_case(
11357        &mut self,
11358        _: &ConvertToOppositeCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.chars()
11364                .fold(String::with_capacity(text.len()), |mut t, c| {
11365                    if c.is_uppercase() {
11366                        t.extend(c.to_lowercase());
11367                    } else {
11368                        t.extend(c.to_uppercase());
11369                    }
11370                    t
11371                })
11372        })
11373    }
11374
11375    pub fn convert_to_sentence_case(
11376        &mut self,
11377        _: &ConvertToSentenceCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11382    }
11383
11384    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11385        self.manipulate_text(window, cx, |text| {
11386            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11387            if has_upper_case_characters {
11388                text.to_lowercase()
11389            } else {
11390                text.to_uppercase()
11391            }
11392        })
11393    }
11394
11395    pub fn convert_to_rot13(
11396        &mut self,
11397        _: &ConvertToRot13,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.manipulate_text(window, cx, |text| {
11402            text.chars()
11403                .map(|c| match c {
11404                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11405                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11406                    _ => c,
11407                })
11408                .collect()
11409        })
11410    }
11411
11412    pub fn convert_to_rot47(
11413        &mut self,
11414        _: &ConvertToRot47,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.chars()
11420                .map(|c| {
11421                    let code_point = c as u32;
11422                    if code_point >= 33 && code_point <= 126 {
11423                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11424                    }
11425                    c
11426                })
11427                .collect()
11428        })
11429    }
11430
11431    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11432    where
11433        Fn: FnMut(&str) -> String,
11434    {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut new_selections = Vec::new();
11438        let mut edits = Vec::new();
11439        let mut selection_adjustment = 0i32;
11440
11441        for selection in self.selections.all_adjusted(cx) {
11442            let selection_is_empty = selection.is_empty();
11443
11444            let (start, end) = if selection_is_empty {
11445                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11446                (word_range.start, word_range.end)
11447            } else {
11448                (
11449                    buffer.point_to_offset(selection.start),
11450                    buffer.point_to_offset(selection.end),
11451                )
11452            };
11453
11454            let text = buffer.text_for_range(start..end).collect::<String>();
11455            let old_length = text.len() as i32;
11456            let text = callback(&text);
11457
11458            new_selections.push(Selection {
11459                start: (start as i32 - selection_adjustment) as usize,
11460                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11461                goal: SelectionGoal::None,
11462                id: selection.id,
11463                reversed: selection.reversed,
11464            });
11465
11466            selection_adjustment += old_length - text.len() as i32;
11467
11468            edits.push((start..end, text));
11469        }
11470
11471        self.transact(window, cx, |this, window, cx| {
11472            this.buffer.update(cx, |buffer, cx| {
11473                buffer.edit(edits, None, cx);
11474            });
11475
11476            this.change_selections(Default::default(), window, cx, |s| {
11477                s.select(new_selections);
11478            });
11479
11480            this.request_autoscroll(Autoscroll::fit(), cx);
11481        });
11482    }
11483
11484    pub fn move_selection_on_drop(
11485        &mut self,
11486        selection: &Selection<Anchor>,
11487        target: DisplayPoint,
11488        is_cut: bool,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11493        let buffer = &display_map.buffer_snapshot;
11494        let mut edits = Vec::new();
11495        let insert_point = display_map
11496            .clip_point(target, Bias::Left)
11497            .to_point(&display_map);
11498        let text = buffer
11499            .text_for_range(selection.start..selection.end)
11500            .collect::<String>();
11501        if is_cut {
11502            edits.push(((selection.start..selection.end), String::new()));
11503        }
11504        let insert_anchor = buffer.anchor_before(insert_point);
11505        edits.push(((insert_anchor..insert_anchor), text));
11506        let last_edit_start = insert_anchor.bias_left(buffer);
11507        let last_edit_end = insert_anchor.bias_right(buffer);
11508        self.transact(window, cx, |this, window, cx| {
11509            this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511            });
11512            this.change_selections(Default::default(), window, cx, |s| {
11513                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11514            });
11515        });
11516    }
11517
11518    pub fn clear_selection_drag_state(&mut self) {
11519        self.selection_drag_state = SelectionDragState::None;
11520    }
11521
11522    pub fn duplicate(
11523        &mut self,
11524        upwards: bool,
11525        whole_lines: bool,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11530
11531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11532        let buffer = &display_map.buffer_snapshot;
11533        let selections = self.selections.all::<Point>(cx);
11534
11535        let mut edits = Vec::new();
11536        let mut selections_iter = selections.iter().peekable();
11537        while let Some(selection) = selections_iter.next() {
11538            let mut rows = selection.spanned_rows(false, &display_map);
11539            // duplicate line-wise
11540            if whole_lines || selection.start == selection.end {
11541                // Avoid duplicating the same lines twice.
11542                while let Some(next_selection) = selections_iter.peek() {
11543                    let next_rows = next_selection.spanned_rows(false, &display_map);
11544                    if next_rows.start < rows.end {
11545                        rows.end = next_rows.end;
11546                        selections_iter.next().unwrap();
11547                    } else {
11548                        break;
11549                    }
11550                }
11551
11552                // Copy the text from the selected row region and splice it either at the start
11553                // or end of the region.
11554                let start = Point::new(rows.start.0, 0);
11555                let end = Point::new(
11556                    rows.end.previous_row().0,
11557                    buffer.line_len(rows.end.previous_row()),
11558                );
11559                let text = buffer
11560                    .text_for_range(start..end)
11561                    .chain(Some("\n"))
11562                    .collect::<String>();
11563                let insert_location = if upwards {
11564                    Point::new(rows.end.0, 0)
11565                } else {
11566                    start
11567                };
11568                edits.push((insert_location..insert_location, text));
11569            } else {
11570                // duplicate character-wise
11571                let start = selection.start;
11572                let end = selection.end;
11573                let text = buffer.text_for_range(start..end).collect::<String>();
11574                edits.push((selection.end..selection.end, text));
11575            }
11576        }
11577
11578        self.transact(window, cx, |this, _, cx| {
11579            this.buffer.update(cx, |buffer, cx| {
11580                buffer.edit(edits, None, cx);
11581            });
11582
11583            this.request_autoscroll(Autoscroll::fit(), cx);
11584        });
11585    }
11586
11587    pub fn duplicate_line_up(
11588        &mut self,
11589        _: &DuplicateLineUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.duplicate(true, true, window, cx);
11594    }
11595
11596    pub fn duplicate_line_down(
11597        &mut self,
11598        _: &DuplicateLineDown,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.duplicate(false, true, window, cx);
11603    }
11604
11605    pub fn duplicate_selection(
11606        &mut self,
11607        _: &DuplicateSelection,
11608        window: &mut Window,
11609        cx: &mut Context<Self>,
11610    ) {
11611        self.duplicate(false, false, window, cx);
11612    }
11613
11614    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616        if self.mode.is_single_line() {
11617            cx.propagate();
11618            return;
11619        }
11620
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut edits = Vec::new();
11625        let mut unfold_ranges = Vec::new();
11626        let mut refold_creases = Vec::new();
11627
11628        let selections = self.selections.all::<Point>(cx);
11629        let mut selections = selections.iter().peekable();
11630        let mut contiguous_row_selections = Vec::new();
11631        let mut new_selections = Vec::new();
11632
11633        while let Some(selection) = selections.next() {
11634            // Find all the selections that span a contiguous row range
11635            let (start_row, end_row) = consume_contiguous_rows(
11636                &mut contiguous_row_selections,
11637                selection,
11638                &display_map,
11639                &mut selections,
11640            );
11641
11642            // Move the text spanned by the row range to be before the line preceding the row range
11643            if start_row.0 > 0 {
11644                let range_to_move = Point::new(
11645                    start_row.previous_row().0,
11646                    buffer.line_len(start_row.previous_row()),
11647                )
11648                    ..Point::new(
11649                        end_row.previous_row().0,
11650                        buffer.line_len(end_row.previous_row()),
11651                    );
11652                let insertion_point = display_map
11653                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11654                    .0;
11655
11656                // Don't move lines across excerpts
11657                if buffer
11658                    .excerpt_containing(insertion_point..range_to_move.end)
11659                    .is_some()
11660                {
11661                    let text = buffer
11662                        .text_for_range(range_to_move.clone())
11663                        .flat_map(|s| s.chars())
11664                        .skip(1)
11665                        .chain(['\n'])
11666                        .collect::<String>();
11667
11668                    edits.push((
11669                        buffer.anchor_after(range_to_move.start)
11670                            ..buffer.anchor_before(range_to_move.end),
11671                        String::new(),
11672                    ));
11673                    let insertion_anchor = buffer.anchor_after(insertion_point);
11674                    edits.push((insertion_anchor..insertion_anchor, text));
11675
11676                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11677
11678                    // Move selections up
11679                    new_selections.extend(contiguous_row_selections.drain(..).map(
11680                        |mut selection| {
11681                            selection.start.row -= row_delta;
11682                            selection.end.row -= row_delta;
11683                            selection
11684                        },
11685                    ));
11686
11687                    // Move folds up
11688                    unfold_ranges.push(range_to_move.clone());
11689                    for fold in display_map.folds_in_range(
11690                        buffer.anchor_before(range_to_move.start)
11691                            ..buffer.anchor_after(range_to_move.end),
11692                    ) {
11693                        let mut start = fold.range.start.to_point(&buffer);
11694                        let mut end = fold.range.end.to_point(&buffer);
11695                        start.row -= row_delta;
11696                        end.row -= row_delta;
11697                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11698                    }
11699                }
11700            }
11701
11702            // If we didn't move line(s), preserve the existing selections
11703            new_selections.append(&mut contiguous_row_selections);
11704        }
11705
11706        self.transact(window, cx, |this, window, cx| {
11707            this.unfold_ranges(&unfold_ranges, true, true, cx);
11708            this.buffer.update(cx, |buffer, cx| {
11709                for (range, text) in edits {
11710                    buffer.edit([(range, text)], None, cx);
11711                }
11712            });
11713            this.fold_creases(refold_creases, true, window, cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(new_selections);
11716            })
11717        });
11718    }
11719
11720    pub fn move_line_down(
11721        &mut self,
11722        _: &MoveLineDown,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11727        if self.mode.is_single_line() {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = self.buffer.read(cx).snapshot(cx);
11734
11735        let mut edits = Vec::new();
11736        let mut unfold_ranges = Vec::new();
11737        let mut refold_creases = Vec::new();
11738
11739        let selections = self.selections.all::<Point>(cx);
11740        let mut selections = selections.iter().peekable();
11741        let mut contiguous_row_selections = Vec::new();
11742        let mut new_selections = Vec::new();
11743
11744        while let Some(selection) = selections.next() {
11745            // Find all the selections that span a contiguous row range
11746            let (start_row, end_row) = consume_contiguous_rows(
11747                &mut contiguous_row_selections,
11748                selection,
11749                &display_map,
11750                &mut selections,
11751            );
11752
11753            // Move the text spanned by the row range to be after the last line of the row range
11754            if end_row.0 <= buffer.max_point().row {
11755                let range_to_move =
11756                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11757                let insertion_point = display_map
11758                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11759                    .0;
11760
11761                // Don't move lines across excerpt boundaries
11762                if buffer
11763                    .excerpt_containing(range_to_move.start..insertion_point)
11764                    .is_some()
11765                {
11766                    let mut text = String::from("\n");
11767                    text.extend(buffer.text_for_range(range_to_move.clone()));
11768                    text.pop(); // Drop trailing newline
11769                    edits.push((
11770                        buffer.anchor_after(range_to_move.start)
11771                            ..buffer.anchor_before(range_to_move.end),
11772                        String::new(),
11773                    ));
11774                    let insertion_anchor = buffer.anchor_after(insertion_point);
11775                    edits.push((insertion_anchor..insertion_anchor, text));
11776
11777                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11778
11779                    // Move selections down
11780                    new_selections.extend(contiguous_row_selections.drain(..).map(
11781                        |mut selection| {
11782                            selection.start.row += row_delta;
11783                            selection.end.row += row_delta;
11784                            selection
11785                        },
11786                    ));
11787
11788                    // Move folds down
11789                    unfold_ranges.push(range_to_move.clone());
11790                    for fold in display_map.folds_in_range(
11791                        buffer.anchor_before(range_to_move.start)
11792                            ..buffer.anchor_after(range_to_move.end),
11793                    ) {
11794                        let mut start = fold.range.start.to_point(&buffer);
11795                        let mut end = fold.range.end.to_point(&buffer);
11796                        start.row += row_delta;
11797                        end.row += row_delta;
11798                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11799                    }
11800                }
11801            }
11802
11803            // If we didn't move line(s), preserve the existing selections
11804            new_selections.append(&mut contiguous_row_selections);
11805        }
11806
11807        self.transact(window, cx, |this, window, cx| {
11808            this.unfold_ranges(&unfold_ranges, true, true, cx);
11809            this.buffer.update(cx, |buffer, cx| {
11810                for (range, text) in edits {
11811                    buffer.edit([(range, text)], None, cx);
11812                }
11813            });
11814            this.fold_creases(refold_creases, true, window, cx);
11815            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11816        });
11817    }
11818
11819    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        let text_layout_details = &self.text_layout_details(window);
11822        self.transact(window, cx, |this, window, cx| {
11823            let edits = this.change_selections(Default::default(), window, cx, |s| {
11824                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11825                s.move_with(|display_map, selection| {
11826                    if !selection.is_empty() {
11827                        return;
11828                    }
11829
11830                    let mut head = selection.head();
11831                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11832                    if head.column() == display_map.line_len(head.row()) {
11833                        transpose_offset = display_map
11834                            .buffer_snapshot
11835                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11836                    }
11837
11838                    if transpose_offset == 0 {
11839                        return;
11840                    }
11841
11842                    *head.column_mut() += 1;
11843                    head = display_map.clip_point(head, Bias::Right);
11844                    let goal = SelectionGoal::HorizontalPosition(
11845                        display_map
11846                            .x_for_display_point(head, text_layout_details)
11847                            .into(),
11848                    );
11849                    selection.collapse_to(head, goal);
11850
11851                    let transpose_start = display_map
11852                        .buffer_snapshot
11853                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11854                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11855                        let transpose_end = display_map
11856                            .buffer_snapshot
11857                            .clip_offset(transpose_offset + 1, Bias::Right);
11858                        if let Some(ch) =
11859                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11860                        {
11861                            edits.push((transpose_start..transpose_offset, String::new()));
11862                            edits.push((transpose_end..transpose_end, ch.to_string()));
11863                        }
11864                    }
11865                });
11866                edits
11867            });
11868            this.buffer
11869                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11870            let selections = this.selections.all::<usize>(cx);
11871            this.change_selections(Default::default(), window, cx, |s| {
11872                s.select(selections);
11873            });
11874        });
11875    }
11876
11877    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11879        if self.mode.is_single_line() {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.rewrap_impl(RewrapOptions::default(), cx)
11885    }
11886
11887    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11888        let buffer = self.buffer.read(cx).snapshot(cx);
11889        let selections = self.selections.all::<Point>(cx);
11890
11891        #[derive(Clone, Debug, PartialEq)]
11892        enum CommentFormat {
11893            /// single line comment, with prefix for line
11894            Line(String),
11895            /// single line within a block comment, with prefix for line
11896            BlockLine(String),
11897            /// a single line of a block comment that includes the initial delimiter
11898            BlockCommentWithStart(BlockCommentConfig),
11899            /// a single line of a block comment that includes the ending delimiter
11900            BlockCommentWithEnd(BlockCommentConfig),
11901        }
11902
11903        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11904        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11905            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11906                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11907                .peekable();
11908
11909            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11910                row
11911            } else {
11912                return Vec::new();
11913            };
11914
11915            let language_settings = buffer.language_settings_at(selection.head(), cx);
11916            let language_scope = buffer.language_scope_at(selection.head());
11917
11918            let indent_and_prefix_for_row =
11919                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11920                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11921                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11922                        &language_scope
11923                    {
11924                        let indent_end = Point::new(row, indent.len);
11925                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11926                        let line_text_after_indent = buffer
11927                            .text_for_range(indent_end..line_end)
11928                            .collect::<String>();
11929
11930                        let is_within_comment_override = buffer
11931                            .language_scope_at(indent_end)
11932                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11933                        let comment_delimiters = if is_within_comment_override {
11934                            // we are within a comment syntax node, but we don't
11935                            // yet know what kind of comment: block, doc or line
11936                            match (
11937                                language_scope.documentation_comment(),
11938                                language_scope.block_comment(),
11939                            ) {
11940                                (Some(config), _) | (_, Some(config))
11941                                    if buffer.contains_str_at(indent_end, &config.start) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11947                                {
11948                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11949                                }
11950                                (Some(config), _) | (_, Some(config))
11951                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11952                                {
11953                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11954                                }
11955                                (_, _) => language_scope
11956                                    .line_comment_prefixes()
11957                                    .iter()
11958                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11959                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11960                            }
11961                        } else {
11962                            // we not in an overridden comment node, but we may
11963                            // be within a non-overridden line comment node
11964                            language_scope
11965                                .line_comment_prefixes()
11966                                .iter()
11967                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11968                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11969                        };
11970
11971                        let rewrap_prefix = language_scope
11972                            .rewrap_prefixes()
11973                            .iter()
11974                            .find_map(|prefix_regex| {
11975                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11976                                    if mat.start() == 0 {
11977                                        Some(mat.as_str().to_string())
11978                                    } else {
11979                                        None
11980                                    }
11981                                })
11982                            })
11983                            .flatten();
11984                        (comment_delimiters, rewrap_prefix)
11985                    } else {
11986                        (None, None)
11987                    };
11988                    (indent, comment_prefix, rewrap_prefix)
11989                };
11990
11991            let mut ranges = Vec::new();
11992            let from_empty_selection = selection.is_empty();
11993
11994            let mut current_range_start = first_row;
11995            let mut prev_row = first_row;
11996            let (
11997                mut current_range_indent,
11998                mut current_range_comment_delimiters,
11999                mut current_range_rewrap_prefix,
12000            ) = indent_and_prefix_for_row(first_row);
12001
12002            for row in non_blank_rows_iter.skip(1) {
12003                let has_paragraph_break = row > prev_row + 1;
12004
12005                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12006                    indent_and_prefix_for_row(row);
12007
12008                let has_indent_change = row_indent != current_range_indent;
12009                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12010
12011                let has_boundary_change = has_comment_change
12012                    || row_rewrap_prefix.is_some()
12013                    || (has_indent_change && current_range_comment_delimiters.is_some());
12014
12015                if has_paragraph_break || has_boundary_change {
12016                    ranges.push((
12017                        language_settings.clone(),
12018                        Point::new(current_range_start, 0)
12019                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12020                        current_range_indent,
12021                        current_range_comment_delimiters.clone(),
12022                        current_range_rewrap_prefix.clone(),
12023                        from_empty_selection,
12024                    ));
12025                    current_range_start = row;
12026                    current_range_indent = row_indent;
12027                    current_range_comment_delimiters = row_comment_delimiters;
12028                    current_range_rewrap_prefix = row_rewrap_prefix;
12029                }
12030                prev_row = row;
12031            }
12032
12033            ranges.push((
12034                language_settings.clone(),
12035                Point::new(current_range_start, 0)
12036                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12037                current_range_indent,
12038                current_range_comment_delimiters,
12039                current_range_rewrap_prefix,
12040                from_empty_selection,
12041            ));
12042
12043            ranges
12044        });
12045
12046        let mut edits = Vec::new();
12047        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12048
12049        for (
12050            language_settings,
12051            wrap_range,
12052            mut indent_size,
12053            comment_prefix,
12054            rewrap_prefix,
12055            from_empty_selection,
12056        ) in wrap_ranges
12057        {
12058            let mut start_row = wrap_range.start.row;
12059            let mut end_row = wrap_range.end.row;
12060
12061            // Skip selections that overlap with a range that has already been rewrapped.
12062            let selection_range = start_row..end_row;
12063            if rewrapped_row_ranges
12064                .iter()
12065                .any(|range| range.overlaps(&selection_range))
12066            {
12067                continue;
12068            }
12069
12070            let tab_size = language_settings.tab_size;
12071
12072            let (line_prefix, inside_comment) = match &comment_prefix {
12073                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12074                    (Some(prefix.as_str()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12077                    (Some(prefix.as_ref()), true)
12078                }
12079                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12080                    start: _,
12081                    end: _,
12082                    prefix,
12083                    tab_size,
12084                })) => {
12085                    indent_size.len += tab_size;
12086                    (Some(prefix.as_ref()), true)
12087                }
12088                None => (None, false),
12089            };
12090            let indent_prefix = indent_size.chars().collect::<String>();
12091            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12092
12093            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12094                RewrapBehavior::InComments => inside_comment,
12095                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12096                RewrapBehavior::Anywhere => true,
12097            };
12098
12099            let should_rewrap = options.override_language_settings
12100                || allow_rewrap_based_on_language
12101                || self.hard_wrap.is_some();
12102            if !should_rewrap {
12103                continue;
12104            }
12105
12106            if from_empty_selection {
12107                'expand_upwards: while start_row > 0 {
12108                    let prev_row = start_row - 1;
12109                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12110                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12111                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12112                    {
12113                        start_row = prev_row;
12114                    } else {
12115                        break 'expand_upwards;
12116                    }
12117                }
12118
12119                'expand_downwards: while end_row < buffer.max_point().row {
12120                    let next_row = end_row + 1;
12121                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12122                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12123                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12124                    {
12125                        end_row = next_row;
12126                    } else {
12127                        break 'expand_downwards;
12128                    }
12129                }
12130            }
12131
12132            let start = Point::new(start_row, 0);
12133            let start_offset = start.to_offset(&buffer);
12134            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12135            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12136            let mut first_line_delimiter = None;
12137            let mut last_line_delimiter = None;
12138            let Some(lines_without_prefixes) = selection_text
12139                .lines()
12140                .enumerate()
12141                .map(|(ix, line)| {
12142                    let line_trimmed = line.trim_start();
12143                    if rewrap_prefix.is_some() && ix > 0 {
12144                        Ok(line_trimmed)
12145                    } else if let Some(
12146                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12147                            start,
12148                            prefix,
12149                            end,
12150                            tab_size,
12151                        })
12152                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12153                            start,
12154                            prefix,
12155                            end,
12156                            tab_size,
12157                        }),
12158                    ) = &comment_prefix
12159                    {
12160                        let line_trimmed = line_trimmed
12161                            .strip_prefix(start.as_ref())
12162                            .map(|s| {
12163                                let mut indent_size = indent_size;
12164                                indent_size.len -= tab_size;
12165                                let indent_prefix: String = indent_size.chars().collect();
12166                                first_line_delimiter = Some((indent_prefix, start));
12167                                s.trim_start()
12168                            })
12169                            .unwrap_or(line_trimmed);
12170                        let line_trimmed = line_trimmed
12171                            .strip_suffix(end.as_ref())
12172                            .map(|s| {
12173                                last_line_delimiter = Some(end);
12174                                s.trim_end()
12175                            })
12176                            .unwrap_or(line_trimmed);
12177                        let line_trimmed = line_trimmed
12178                            .strip_prefix(prefix.as_ref())
12179                            .unwrap_or(line_trimmed);
12180                        Ok(line_trimmed)
12181                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12182                        line_trimmed.strip_prefix(prefix).with_context(|| {
12183                            format!("line did not start with prefix {prefix:?}: {line:?}")
12184                        })
12185                    } else {
12186                        line_trimmed
12187                            .strip_prefix(&line_prefix.trim_start())
12188                            .with_context(|| {
12189                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12190                            })
12191                    }
12192                })
12193                .collect::<Result<Vec<_>, _>>()
12194                .log_err()
12195            else {
12196                continue;
12197            };
12198
12199            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12200                buffer
12201                    .language_settings_at(Point::new(start_row, 0), cx)
12202                    .preferred_line_length as usize
12203            });
12204
12205            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12206                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12207            } else {
12208                line_prefix.clone()
12209            };
12210
12211            let wrapped_text = {
12212                let mut wrapped_text = wrap_with_prefix(
12213                    line_prefix,
12214                    subsequent_lines_prefix,
12215                    lines_without_prefixes.join("\n"),
12216                    wrap_column,
12217                    tab_size,
12218                    options.preserve_existing_whitespace,
12219                );
12220
12221                if let Some((indent, delimiter)) = first_line_delimiter {
12222                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12223                }
12224                if let Some(last_line) = last_line_delimiter {
12225                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12226                }
12227
12228                wrapped_text
12229            };
12230
12231            // TODO: should always use char-based diff while still supporting cursor behavior that
12232            // matches vim.
12233            let mut diff_options = DiffOptions::default();
12234            if options.override_language_settings {
12235                diff_options.max_word_diff_len = 0;
12236                diff_options.max_word_diff_line_count = 0;
12237            } else {
12238                diff_options.max_word_diff_len = usize::MAX;
12239                diff_options.max_word_diff_line_count = usize::MAX;
12240            }
12241
12242            for (old_range, new_text) in
12243                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12244            {
12245                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12246                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12247                edits.push((edit_start..edit_end, new_text));
12248            }
12249
12250            rewrapped_row_ranges.push(start_row..=end_row);
12251        }
12252
12253        self.buffer
12254            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12255    }
12256
12257    pub fn cut_common(
12258        &mut self,
12259        cut_no_selection_line: bool,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) -> ClipboardItem {
12263        let mut text = String::new();
12264        let buffer = self.buffer.read(cx).snapshot(cx);
12265        let mut selections = self.selections.all::<Point>(cx);
12266        let mut clipboard_selections = Vec::with_capacity(selections.len());
12267        {
12268            let max_point = buffer.max_point();
12269            let mut is_first = true;
12270            for selection in &mut selections {
12271                let is_entire_line =
12272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12273                if is_entire_line {
12274                    selection.start = Point::new(selection.start.row, 0);
12275                    if !selection.is_empty() && selection.end.column == 0 {
12276                        selection.end = cmp::min(max_point, selection.end);
12277                    } else {
12278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12279                    }
12280                    selection.goal = SelectionGoal::None;
12281                }
12282                if is_first {
12283                    is_first = false;
12284                } else {
12285                    text += "\n";
12286                }
12287                let mut len = 0;
12288                for chunk in buffer.text_for_range(selection.start..selection.end) {
12289                    text.push_str(chunk);
12290                    len += chunk.len();
12291                }
12292                clipboard_selections.push(ClipboardSelection {
12293                    len,
12294                    is_entire_line,
12295                    first_line_indent: buffer
12296                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12297                        .len,
12298                });
12299            }
12300        }
12301
12302        self.transact(window, cx, |this, window, cx| {
12303            this.change_selections(Default::default(), window, cx, |s| {
12304                s.select(selections);
12305            });
12306            this.insert("", window, cx);
12307        });
12308        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12309    }
12310
12311    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12313        let item = self.cut_common(true, window, cx);
12314        cx.write_to_clipboard(item);
12315    }
12316
12317    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12319        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12320            s.move_with(|snapshot, sel| {
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12323                }
12324                if sel.is_empty() {
12325                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12326                }
12327            });
12328        });
12329        let item = self.cut_common(true, window, cx);
12330        cx.set_global(KillRing(item))
12331    }
12332
12333    pub fn kill_ring_yank(
12334        &mut self,
12335        _: &KillRingYank,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12341            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12342                (kill_ring.text().to_string(), kill_ring.metadata_json())
12343            } else {
12344                return;
12345            }
12346        } else {
12347            return;
12348        };
12349        self.do_paste(&text, metadata, false, window, cx);
12350    }
12351
12352    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12353        self.do_copy(true, cx);
12354    }
12355
12356    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12357        self.do_copy(false, cx);
12358    }
12359
12360    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12361        let selections = self.selections.all::<Point>(cx);
12362        let buffer = self.buffer.read(cx).read(cx);
12363        let mut text = String::new();
12364
12365        let mut clipboard_selections = Vec::with_capacity(selections.len());
12366        {
12367            let max_point = buffer.max_point();
12368            let mut is_first = true;
12369            for selection in &selections {
12370                let mut start = selection.start;
12371                let mut end = selection.end;
12372                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12373                if is_entire_line {
12374                    start = Point::new(start.row, 0);
12375                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12376                }
12377
12378                let mut trimmed_selections = Vec::new();
12379                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12380                    let row = MultiBufferRow(start.row);
12381                    let first_indent = buffer.indent_size_for_line(row);
12382                    if first_indent.len == 0 || start.column > first_indent.len {
12383                        trimmed_selections.push(start..end);
12384                    } else {
12385                        trimmed_selections.push(
12386                            Point::new(row.0, first_indent.len)
12387                                ..Point::new(row.0, buffer.line_len(row)),
12388                        );
12389                        for row in start.row + 1..=end.row {
12390                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12391                            if row == end.row {
12392                                line_len = end.column;
12393                            }
12394                            if line_len == 0 {
12395                                trimmed_selections
12396                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12397                                continue;
12398                            }
12399                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12400                            if row_indent_size.len >= first_indent.len {
12401                                trimmed_selections.push(
12402                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12403                                );
12404                            } else {
12405                                trimmed_selections.clear();
12406                                trimmed_selections.push(start..end);
12407                                break;
12408                            }
12409                        }
12410                    }
12411                } else {
12412                    trimmed_selections.push(start..end);
12413                }
12414
12415                for trimmed_range in trimmed_selections {
12416                    if is_first {
12417                        is_first = false;
12418                    } else {
12419                        text += "\n";
12420                    }
12421                    let mut len = 0;
12422                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12423                        text.push_str(chunk);
12424                        len += chunk.len();
12425                    }
12426                    clipboard_selections.push(ClipboardSelection {
12427                        len,
12428                        is_entire_line,
12429                        first_line_indent: buffer
12430                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12431                            .len,
12432                    });
12433                }
12434            }
12435        }
12436
12437        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12438            text,
12439            clipboard_selections,
12440        ));
12441    }
12442
12443    pub fn do_paste(
12444        &mut self,
12445        text: &String,
12446        clipboard_selections: Option<Vec<ClipboardSelection>>,
12447        handle_entire_lines: bool,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if self.read_only(cx) {
12452            return;
12453        }
12454
12455        let clipboard_text = Cow::Borrowed(text.as_str());
12456
12457        self.transact(window, cx, |this, window, cx| {
12458            let had_active_edit_prediction = this.has_active_edit_prediction();
12459            let old_selections = this.selections.all::<usize>(cx);
12460            let cursor_offset = this.selections.last::<usize>(cx).head();
12461
12462            if let Some(mut clipboard_selections) = clipboard_selections {
12463                let all_selections_were_entire_line =
12464                    clipboard_selections.iter().all(|s| s.is_entire_line);
12465                let first_selection_indent_column =
12466                    clipboard_selections.first().map(|s| s.first_line_indent);
12467                if clipboard_selections.len() != old_selections.len() {
12468                    clipboard_selections.drain(..);
12469                }
12470                let mut auto_indent_on_paste = true;
12471
12472                this.buffer.update(cx, |buffer, cx| {
12473                    let snapshot = buffer.read(cx);
12474                    auto_indent_on_paste = snapshot
12475                        .language_settings_at(cursor_offset, cx)
12476                        .auto_indent_on_paste;
12477
12478                    let mut start_offset = 0;
12479                    let mut edits = Vec::new();
12480                    let mut original_indent_columns = Vec::new();
12481                    for (ix, selection) in old_selections.iter().enumerate() {
12482                        let to_insert;
12483                        let entire_line;
12484                        let original_indent_column;
12485                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12486                            let end_offset = start_offset + clipboard_selection.len;
12487                            to_insert = &clipboard_text[start_offset..end_offset];
12488                            entire_line = clipboard_selection.is_entire_line;
12489                            start_offset = end_offset + 1;
12490                            original_indent_column = Some(clipboard_selection.first_line_indent);
12491                        } else {
12492                            to_insert = &*clipboard_text;
12493                            entire_line = all_selections_were_entire_line;
12494                            original_indent_column = first_selection_indent_column
12495                        }
12496
12497                        let (range, to_insert) =
12498                            if selection.is_empty() && handle_entire_lines && entire_line {
12499                                // If the corresponding selection was empty when this slice of the
12500                                // clipboard text was written, then the entire line containing the
12501                                // selection was copied. If this selection is also currently empty,
12502                                // then paste the line before the current line of the buffer.
12503                                let column = selection.start.to_point(&snapshot).column as usize;
12504                                let line_start = selection.start - column;
12505                                (line_start..line_start, Cow::Borrowed(to_insert))
12506                            } else {
12507                                let language = snapshot.language_at(selection.head());
12508                                let range = selection.range();
12509                                if let Some(language) = language
12510                                    && language.name() == "Markdown".into()
12511                                {
12512                                    edit_for_markdown_paste(
12513                                        &snapshot,
12514                                        range,
12515                                        to_insert,
12516                                        url::Url::parse(to_insert).ok(),
12517                                    )
12518                                } else {
12519                                    (range, Cow::Borrowed(to_insert))
12520                                }
12521                            };
12522
12523                        edits.push((range, to_insert));
12524                        original_indent_columns.push(original_indent_column);
12525                    }
12526                    drop(snapshot);
12527
12528                    buffer.edit(
12529                        edits,
12530                        if auto_indent_on_paste {
12531                            Some(AutoindentMode::Block {
12532                                original_indent_columns,
12533                            })
12534                        } else {
12535                            None
12536                        },
12537                        cx,
12538                    );
12539                });
12540
12541                let selections = this.selections.all::<usize>(cx);
12542                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12543            } else {
12544                let url = url::Url::parse(&clipboard_text).ok();
12545
12546                let auto_indent_mode = if !clipboard_text.is_empty() {
12547                    Some(AutoindentMode::Block {
12548                        original_indent_columns: Vec::new(),
12549                    })
12550                } else {
12551                    None
12552                };
12553
12554                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12555                    let snapshot = buffer.snapshot(cx);
12556
12557                    let anchors = old_selections
12558                        .iter()
12559                        .map(|s| {
12560                            let anchor = snapshot.anchor_after(s.head());
12561                            s.map(|_| anchor)
12562                        })
12563                        .collect::<Vec<_>>();
12564
12565                    let mut edits = Vec::new();
12566
12567                    for selection in old_selections.iter() {
12568                        let language = snapshot.language_at(selection.head());
12569                        let range = selection.range();
12570
12571                        let (edit_range, edit_text) = if let Some(language) = language
12572                            && language.name() == "Markdown".into()
12573                        {
12574                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12575                        } else {
12576                            (range, clipboard_text.clone())
12577                        };
12578
12579                        edits.push((edit_range, edit_text));
12580                    }
12581
12582                    drop(snapshot);
12583                    buffer.edit(edits, auto_indent_mode, cx);
12584
12585                    anchors
12586                });
12587
12588                this.change_selections(Default::default(), window, cx, |s| {
12589                    s.select_anchors(selection_anchors);
12590                });
12591            }
12592
12593            let trigger_in_words =
12594                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12595
12596            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12597        });
12598    }
12599
12600    pub fn diff_clipboard_with_selection(
12601        &mut self,
12602        _: &DiffClipboardWithSelection,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let selections = self.selections.all::<usize>(cx);
12607
12608        if selections.is_empty() {
12609            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12610            return;
12611        };
12612
12613        let clipboard_text = match cx.read_from_clipboard() {
12614            Some(item) => match item.entries().first() {
12615                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12616                _ => None,
12617            },
12618            None => None,
12619        };
12620
12621        let Some(clipboard_text) = clipboard_text else {
12622            log::warn!("Clipboard doesn't contain text.");
12623            return;
12624        };
12625
12626        window.dispatch_action(
12627            Box::new(DiffClipboardWithSelectionData {
12628                clipboard_text,
12629                editor: cx.entity(),
12630            }),
12631            cx,
12632        );
12633    }
12634
12635    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12637        if let Some(item) = cx.read_from_clipboard() {
12638            let entries = item.entries();
12639
12640            match entries.first() {
12641                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12642                // of all the pasted entries.
12643                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12644                    .do_paste(
12645                        clipboard_string.text(),
12646                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12647                        true,
12648                        window,
12649                        cx,
12650                    ),
12651                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12652            }
12653        }
12654    }
12655
12656    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12657        if self.read_only(cx) {
12658            return;
12659        }
12660
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12662
12663        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12664            if let Some((selections, _)) =
12665                self.selection_history.transaction(transaction_id).cloned()
12666            {
12667                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12668                    s.select_anchors(selections.to_vec());
12669                });
12670            } else {
12671                log::error!(
12672                    "No entry in selection_history found for undo. \
12673                     This may correspond to a bug where undo does not update the selection. \
12674                     If this is occurring, please add details to \
12675                     https://github.com/zed-industries/zed/issues/22692"
12676                );
12677            }
12678            self.request_autoscroll(Autoscroll::fit(), cx);
12679            self.unmark_text(window, cx);
12680            self.refresh_edit_prediction(true, false, window, cx);
12681            cx.emit(EditorEvent::Edited { transaction_id });
12682            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12683        }
12684    }
12685
12686    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12687        if self.read_only(cx) {
12688            return;
12689        }
12690
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12692
12693        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12694            if let Some((_, Some(selections))) =
12695                self.selection_history.transaction(transaction_id).cloned()
12696            {
12697                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12698                    s.select_anchors(selections.to_vec());
12699                });
12700            } else {
12701                log::error!(
12702                    "No entry in selection_history found for redo. \
12703                     This may correspond to a bug where undo does not update the selection. \
12704                     If this is occurring, please add details to \
12705                     https://github.com/zed-industries/zed/issues/22692"
12706                );
12707            }
12708            self.request_autoscroll(Autoscroll::fit(), cx);
12709            self.unmark_text(window, cx);
12710            self.refresh_edit_prediction(true, false, window, cx);
12711            cx.emit(EditorEvent::Edited { transaction_id });
12712        }
12713    }
12714
12715    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12716        self.buffer
12717            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12718    }
12719
12720    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12721        self.buffer
12722            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12723    }
12724
12725    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727        self.change_selections(Default::default(), window, cx, |s| {
12728            s.move_with(|map, selection| {
12729                let cursor = if selection.is_empty() {
12730                    movement::left(map, selection.start)
12731                } else {
12732                    selection.start
12733                };
12734                selection.collapse_to(cursor, SelectionGoal::None);
12735            });
12736        })
12737    }
12738
12739    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12741        self.change_selections(Default::default(), window, cx, |s| {
12742            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12743        })
12744    }
12745
12746    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12748        self.change_selections(Default::default(), window, cx, |s| {
12749            s.move_with(|map, selection| {
12750                let cursor = if selection.is_empty() {
12751                    movement::right(map, selection.end)
12752                } else {
12753                    selection.end
12754                };
12755                selection.collapse_to(cursor, SelectionGoal::None)
12756            });
12757        })
12758    }
12759
12760    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12762        self.change_selections(Default::default(), window, cx, |s| {
12763            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12764        })
12765    }
12766
12767    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12768        if self.take_rename(true, window, cx).is_some() {
12769            return;
12770        }
12771
12772        if self.mode.is_single_line() {
12773            cx.propagate();
12774            return;
12775        }
12776
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12778
12779        let text_layout_details = &self.text_layout_details(window);
12780        let selection_count = self.selections.count();
12781        let first_selection = self.selections.first_anchor();
12782
12783        self.change_selections(Default::default(), window, cx, |s| {
12784            s.move_with(|map, selection| {
12785                if !selection.is_empty() {
12786                    selection.goal = SelectionGoal::None;
12787                }
12788                let (cursor, goal) = movement::up(
12789                    map,
12790                    selection.start,
12791                    selection.goal,
12792                    false,
12793                    text_layout_details,
12794                );
12795                selection.collapse_to(cursor, goal);
12796            });
12797        });
12798
12799        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12800        {
12801            cx.propagate();
12802        }
12803    }
12804
12805    pub fn move_up_by_lines(
12806        &mut self,
12807        action: &MoveUpByLines,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) {
12811        if self.take_rename(true, window, cx).is_some() {
12812            return;
12813        }
12814
12815        if self.mode.is_single_line() {
12816            cx.propagate();
12817            return;
12818        }
12819
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821
12822        let text_layout_details = &self.text_layout_details(window);
12823
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_with(|map, selection| {
12826                if !selection.is_empty() {
12827                    selection.goal = SelectionGoal::None;
12828                }
12829                let (cursor, goal) = movement::up_by_rows(
12830                    map,
12831                    selection.start,
12832                    action.lines,
12833                    selection.goal,
12834                    false,
12835                    text_layout_details,
12836                );
12837                selection.collapse_to(cursor, goal);
12838            });
12839        })
12840    }
12841
12842    pub fn move_down_by_lines(
12843        &mut self,
12844        action: &MoveDownByLines,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        if self.take_rename(true, window, cx).is_some() {
12849            return;
12850        }
12851
12852        if self.mode.is_single_line() {
12853            cx.propagate();
12854            return;
12855        }
12856
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858
12859        let text_layout_details = &self.text_layout_details(window);
12860
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_with(|map, selection| {
12863                if !selection.is_empty() {
12864                    selection.goal = SelectionGoal::None;
12865                }
12866                let (cursor, goal) = movement::down_by_rows(
12867                    map,
12868                    selection.start,
12869                    action.lines,
12870                    selection.goal,
12871                    false,
12872                    text_layout_details,
12873                );
12874                selection.collapse_to(cursor, goal);
12875            });
12876        })
12877    }
12878
12879    pub fn select_down_by_lines(
12880        &mut self,
12881        action: &SelectDownByLines,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        let text_layout_details = &self.text_layout_details(window);
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_heads_with(|map, head, goal| {
12889                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12890            })
12891        })
12892    }
12893
12894    pub fn select_up_by_lines(
12895        &mut self,
12896        action: &SelectUpByLines,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12901        let text_layout_details = &self.text_layout_details(window);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, goal| {
12904                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12905            })
12906        })
12907    }
12908
12909    pub fn select_page_up(
12910        &mut self,
12911        _: &SelectPageUp,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        let Some(row_count) = self.visible_row_count() else {
12916            return;
12917        };
12918
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920
12921        let text_layout_details = &self.text_layout_details(window);
12922
12923        self.change_selections(Default::default(), window, cx, |s| {
12924            s.move_heads_with(|map, head, goal| {
12925                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12926            })
12927        })
12928    }
12929
12930    pub fn move_page_up(
12931        &mut self,
12932        action: &MovePageUp,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if self.take_rename(true, window, cx).is_some() {
12937            return;
12938        }
12939
12940        if self
12941            .context_menu
12942            .borrow_mut()
12943            .as_mut()
12944            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12945            .unwrap_or(false)
12946        {
12947            return;
12948        }
12949
12950        if matches!(self.mode, EditorMode::SingleLine) {
12951            cx.propagate();
12952            return;
12953        }
12954
12955        let Some(row_count) = self.visible_row_count() else {
12956            return;
12957        };
12958
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12960
12961        let effects = if action.center_cursor {
12962            SelectionEffects::scroll(Autoscroll::center())
12963        } else {
12964            SelectionEffects::default()
12965        };
12966
12967        let text_layout_details = &self.text_layout_details(window);
12968
12969        self.change_selections(effects, window, cx, |s| {
12970            s.move_with(|map, selection| {
12971                if !selection.is_empty() {
12972                    selection.goal = SelectionGoal::None;
12973                }
12974                let (cursor, goal) = movement::up_by_rows(
12975                    map,
12976                    selection.end,
12977                    row_count,
12978                    selection.goal,
12979                    false,
12980                    text_layout_details,
12981                );
12982                selection.collapse_to(cursor, goal);
12983            });
12984        });
12985    }
12986
12987    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989        let text_layout_details = &self.text_layout_details(window);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_heads_with(|map, head, goal| {
12992                movement::up(map, head, goal, false, text_layout_details)
12993            })
12994        })
12995    }
12996
12997    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12998        self.take_rename(true, window, cx);
12999
13000        if self.mode.is_single_line() {
13001            cx.propagate();
13002            return;
13003        }
13004
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006
13007        let text_layout_details = &self.text_layout_details(window);
13008        let selection_count = self.selections.count();
13009        let first_selection = self.selections.first_anchor();
13010
13011        self.change_selections(Default::default(), window, cx, |s| {
13012            s.move_with(|map, selection| {
13013                if !selection.is_empty() {
13014                    selection.goal = SelectionGoal::None;
13015                }
13016                let (cursor, goal) = movement::down(
13017                    map,
13018                    selection.end,
13019                    selection.goal,
13020                    false,
13021                    text_layout_details,
13022                );
13023                selection.collapse_to(cursor, goal);
13024            });
13025        });
13026
13027        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13028        {
13029            cx.propagate();
13030        }
13031    }
13032
13033    pub fn select_page_down(
13034        &mut self,
13035        _: &SelectPageDown,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        let Some(row_count) = self.visible_row_count() else {
13040            return;
13041        };
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_heads_with(|map, head, goal| {
13049                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13050            })
13051        })
13052    }
13053
13054    pub fn move_page_down(
13055        &mut self,
13056        action: &MovePageDown,
13057        window: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if self.take_rename(true, window, cx).is_some() {
13061            return;
13062        }
13063
13064        if self
13065            .context_menu
13066            .borrow_mut()
13067            .as_mut()
13068            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13069            .unwrap_or(false)
13070        {
13071            return;
13072        }
13073
13074        if matches!(self.mode, EditorMode::SingleLine) {
13075            cx.propagate();
13076            return;
13077        }
13078
13079        let Some(row_count) = self.visible_row_count() else {
13080            return;
13081        };
13082
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084
13085        let effects = if action.center_cursor {
13086            SelectionEffects::scroll(Autoscroll::center())
13087        } else {
13088            SelectionEffects::default()
13089        };
13090
13091        let text_layout_details = &self.text_layout_details(window);
13092        self.change_selections(effects, window, cx, |s| {
13093            s.move_with(|map, selection| {
13094                if !selection.is_empty() {
13095                    selection.goal = SelectionGoal::None;
13096                }
13097                let (cursor, goal) = movement::down_by_rows(
13098                    map,
13099                    selection.end,
13100                    row_count,
13101                    selection.goal,
13102                    false,
13103                    text_layout_details,
13104                );
13105                selection.collapse_to(cursor, goal);
13106            });
13107        });
13108    }
13109
13110    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112        let text_layout_details = &self.text_layout_details(window);
13113        self.change_selections(Default::default(), window, cx, |s| {
13114            s.move_heads_with(|map, head, goal| {
13115                movement::down(map, head, goal, false, text_layout_details)
13116            })
13117        });
13118    }
13119
13120    pub fn context_menu_first(
13121        &mut self,
13122        _: &ContextMenuFirst,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13127            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13128        }
13129    }
13130
13131    pub fn context_menu_prev(
13132        &mut self,
13133        _: &ContextMenuPrevious,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13138            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13139        }
13140    }
13141
13142    pub fn context_menu_next(
13143        &mut self,
13144        _: &ContextMenuNext,
13145        window: &mut Window,
13146        cx: &mut Context<Self>,
13147    ) {
13148        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13149            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13150        }
13151    }
13152
13153    pub fn context_menu_last(
13154        &mut self,
13155        _: &ContextMenuLast,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13160            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13161        }
13162    }
13163
13164    pub fn signature_help_prev(
13165        &mut self,
13166        _: &SignatureHelpPrevious,
13167        _: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if let Some(popover) = self.signature_help_state.popover_mut() {
13171            if popover.current_signature == 0 {
13172                popover.current_signature = popover.signatures.len() - 1;
13173            } else {
13174                popover.current_signature -= 1;
13175            }
13176            cx.notify();
13177        }
13178    }
13179
13180    pub fn signature_help_next(
13181        &mut self,
13182        _: &SignatureHelpNext,
13183        _: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        if let Some(popover) = self.signature_help_state.popover_mut() {
13187            if popover.current_signature + 1 == popover.signatures.len() {
13188                popover.current_signature = 0;
13189            } else {
13190                popover.current_signature += 1;
13191            }
13192            cx.notify();
13193        }
13194    }
13195
13196    pub fn move_to_previous_word_start(
13197        &mut self,
13198        _: &MoveToPreviousWordStart,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203        self.change_selections(Default::default(), window, cx, |s| {
13204            s.move_cursors_with(|map, head, _| {
13205                (
13206                    movement::previous_word_start(map, head),
13207                    SelectionGoal::None,
13208                )
13209            });
13210        })
13211    }
13212
13213    pub fn move_to_previous_subword_start(
13214        &mut self,
13215        _: &MoveToPreviousSubwordStart,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        self.change_selections(Default::default(), window, cx, |s| {
13221            s.move_cursors_with(|map, head, _| {
13222                (
13223                    movement::previous_subword_start(map, head),
13224                    SelectionGoal::None,
13225                )
13226            });
13227        })
13228    }
13229
13230    pub fn select_to_previous_word_start(
13231        &mut self,
13232        _: &SelectToPreviousWordStart,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13237        self.change_selections(Default::default(), window, cx, |s| {
13238            s.move_heads_with(|map, head, _| {
13239                (
13240                    movement::previous_word_start(map, head),
13241                    SelectionGoal::None,
13242                )
13243            });
13244        })
13245    }
13246
13247    pub fn select_to_previous_subword_start(
13248        &mut self,
13249        _: &SelectToPreviousSubwordStart,
13250        window: &mut Window,
13251        cx: &mut Context<Self>,
13252    ) {
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_heads_with(|map, head, _| {
13256                (
13257                    movement::previous_subword_start(map, head),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn delete_to_previous_word_start(
13265        &mut self,
13266        action: &DeleteToPreviousWordStart,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13271        self.transact(window, cx, |this, window, cx| {
13272            this.select_autoclose_pair(window, cx);
13273            this.change_selections(Default::default(), window, cx, |s| {
13274                s.move_with(|map, selection| {
13275                    if selection.is_empty() {
13276                        let mut cursor = if action.ignore_newlines {
13277                            movement::previous_word_start(map, selection.head())
13278                        } else {
13279                            movement::previous_word_start_or_newline(map, selection.head())
13280                        };
13281                        cursor = movement::adjust_greedy_deletion(
13282                            map,
13283                            selection.head(),
13284                            cursor,
13285                            action.ignore_brackets,
13286                        );
13287                        selection.set_head(cursor, SelectionGoal::None);
13288                    }
13289                });
13290            });
13291            this.insert("", window, cx);
13292        });
13293    }
13294
13295    pub fn delete_to_previous_subword_start(
13296        &mut self,
13297        _: &DeleteToPreviousSubwordStart,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13302        self.transact(window, cx, |this, window, cx| {
13303            this.select_autoclose_pair(window, cx);
13304            this.change_selections(Default::default(), window, cx, |s| {
13305                s.move_with(|map, selection| {
13306                    if selection.is_empty() {
13307                        let mut cursor = movement::previous_subword_start(map, selection.head());
13308                        cursor =
13309                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13310                        selection.set_head(cursor, SelectionGoal::None);
13311                    }
13312                });
13313            });
13314            this.insert("", window, cx);
13315        });
13316    }
13317
13318    pub fn move_to_next_word_end(
13319        &mut self,
13320        _: &MoveToNextWordEnd,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        self.change_selections(Default::default(), window, cx, |s| {
13326            s.move_cursors_with(|map, head, _| {
13327                (movement::next_word_end(map, head), SelectionGoal::None)
13328            });
13329        })
13330    }
13331
13332    pub fn move_to_next_subword_end(
13333        &mut self,
13334        _: &MoveToNextSubwordEnd,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (movement::next_subword_end(map, head), SelectionGoal::None)
13342            });
13343        })
13344    }
13345
13346    pub fn select_to_next_word_end(
13347        &mut self,
13348        _: &SelectToNextWordEnd,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.move_heads_with(|map, head, _| {
13355                (movement::next_word_end(map, head), SelectionGoal::None)
13356            });
13357        })
13358    }
13359
13360    pub fn select_to_next_subword_end(
13361        &mut self,
13362        _: &SelectToNextSubwordEnd,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (movement::next_subword_end(map, head), SelectionGoal::None)
13370            });
13371        })
13372    }
13373
13374    pub fn delete_to_next_word_end(
13375        &mut self,
13376        action: &DeleteToNextWordEnd,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13381        self.transact(window, cx, |this, window, cx| {
13382            this.change_selections(Default::default(), window, cx, |s| {
13383                s.move_with(|map, selection| {
13384                    if selection.is_empty() {
13385                        let mut cursor = if action.ignore_newlines {
13386                            movement::next_word_end(map, selection.head())
13387                        } else {
13388                            movement::next_word_end_or_newline(map, selection.head())
13389                        };
13390                        cursor = movement::adjust_greedy_deletion(
13391                            map,
13392                            selection.head(),
13393                            cursor,
13394                            action.ignore_brackets,
13395                        );
13396                        selection.set_head(cursor, SelectionGoal::None);
13397                    }
13398                });
13399            });
13400            this.insert("", window, cx);
13401        });
13402    }
13403
13404    pub fn delete_to_next_subword_end(
13405        &mut self,
13406        _: &DeleteToNextSubwordEnd,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13411        self.transact(window, cx, |this, window, cx| {
13412            this.change_selections(Default::default(), window, cx, |s| {
13413                s.move_with(|map, selection| {
13414                    if selection.is_empty() {
13415                        let mut cursor = movement::next_subword_end(map, selection.head());
13416                        cursor =
13417                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13418                        selection.set_head(cursor, SelectionGoal::None);
13419                    }
13420                });
13421            });
13422            this.insert("", window, cx);
13423        });
13424    }
13425
13426    pub fn move_to_beginning_of_line(
13427        &mut self,
13428        action: &MoveToBeginningOfLine,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13433        self.change_selections(Default::default(), window, cx, |s| {
13434            s.move_cursors_with(|map, head, _| {
13435                (
13436                    movement::indented_line_beginning(
13437                        map,
13438                        head,
13439                        action.stop_at_soft_wraps,
13440                        action.stop_at_indent,
13441                    ),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_beginning_of_line(
13449        &mut self,
13450        action: &SelectToBeginningOfLine,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        self.change_selections(Default::default(), window, cx, |s| {
13456            s.move_heads_with(|map, head, _| {
13457                (
13458                    movement::indented_line_beginning(
13459                        map,
13460                        head,
13461                        action.stop_at_soft_wraps,
13462                        action.stop_at_indent,
13463                    ),
13464                    SelectionGoal::None,
13465                )
13466            });
13467        });
13468    }
13469
13470    pub fn delete_to_beginning_of_line(
13471        &mut self,
13472        action: &DeleteToBeginningOfLine,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13477        self.transact(window, cx, |this, window, cx| {
13478            this.change_selections(Default::default(), window, cx, |s| {
13479                s.move_with(|_, selection| {
13480                    selection.reversed = true;
13481                });
13482            });
13483
13484            this.select_to_beginning_of_line(
13485                &SelectToBeginningOfLine {
13486                    stop_at_soft_wraps: false,
13487                    stop_at_indent: action.stop_at_indent,
13488                },
13489                window,
13490                cx,
13491            );
13492            this.backspace(&Backspace, window, cx);
13493        });
13494    }
13495
13496    pub fn move_to_end_of_line(
13497        &mut self,
13498        action: &MoveToEndOfLine,
13499        window: &mut Window,
13500        cx: &mut Context<Self>,
13501    ) {
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503        self.change_selections(Default::default(), window, cx, |s| {
13504            s.move_cursors_with(|map, head, _| {
13505                (
13506                    movement::line_end(map, head, action.stop_at_soft_wraps),
13507                    SelectionGoal::None,
13508                )
13509            });
13510        })
13511    }
13512
13513    pub fn select_to_end_of_line(
13514        &mut self,
13515        action: &SelectToEndOfLine,
13516        window: &mut Window,
13517        cx: &mut Context<Self>,
13518    ) {
13519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13520        self.change_selections(Default::default(), window, cx, |s| {
13521            s.move_heads_with(|map, head, _| {
13522                (
13523                    movement::line_end(map, head, action.stop_at_soft_wraps),
13524                    SelectionGoal::None,
13525                )
13526            });
13527        })
13528    }
13529
13530    pub fn delete_to_end_of_line(
13531        &mut self,
13532        _: &DeleteToEndOfLine,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13537        self.transact(window, cx, |this, window, cx| {
13538            this.select_to_end_of_line(
13539                &SelectToEndOfLine {
13540                    stop_at_soft_wraps: false,
13541                },
13542                window,
13543                cx,
13544            );
13545            this.delete(&Delete, window, cx);
13546        });
13547    }
13548
13549    pub fn cut_to_end_of_line(
13550        &mut self,
13551        action: &CutToEndOfLine,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        self.transact(window, cx, |this, window, cx| {
13557            this.select_to_end_of_line(
13558                &SelectToEndOfLine {
13559                    stop_at_soft_wraps: false,
13560                },
13561                window,
13562                cx,
13563            );
13564            if !action.stop_at_newlines {
13565                this.change_selections(Default::default(), window, cx, |s| {
13566                    s.move_with(|_, sel| {
13567                        if sel.is_empty() {
13568                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13569                        }
13570                    });
13571                });
13572            }
13573            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13574            let item = this.cut_common(false, window, cx);
13575            cx.write_to_clipboard(item);
13576        });
13577    }
13578
13579    pub fn move_to_start_of_paragraph(
13580        &mut self,
13581        _: &MoveToStartOfParagraph,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if matches!(self.mode, EditorMode::SingleLine) {
13586            cx.propagate();
13587            return;
13588        }
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_with(|map, selection| {
13592                selection.collapse_to(
13593                    movement::start_of_paragraph(map, selection.head(), 1),
13594                    SelectionGoal::None,
13595                )
13596            });
13597        })
13598    }
13599
13600    pub fn move_to_end_of_paragraph(
13601        &mut self,
13602        _: &MoveToEndOfParagraph,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        if matches!(self.mode, EditorMode::SingleLine) {
13607            cx.propagate();
13608            return;
13609        }
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                selection.collapse_to(
13614                    movement::end_of_paragraph(map, selection.head(), 1),
13615                    SelectionGoal::None,
13616                )
13617            });
13618        })
13619    }
13620
13621    pub fn select_to_start_of_paragraph(
13622        &mut self,
13623        _: &SelectToStartOfParagraph,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        if matches!(self.mode, EditorMode::SingleLine) {
13628            cx.propagate();
13629            return;
13630        }
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_heads_with(|map, head, _| {
13634                (
13635                    movement::start_of_paragraph(map, head, 1),
13636                    SelectionGoal::None,
13637                )
13638            });
13639        })
13640    }
13641
13642    pub fn select_to_end_of_paragraph(
13643        &mut self,
13644        _: &SelectToEndOfParagraph,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        if matches!(self.mode, EditorMode::SingleLine) {
13649            cx.propagate();
13650            return;
13651        }
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, _| {
13655                (
13656                    movement::end_of_paragraph(map, head, 1),
13657                    SelectionGoal::None,
13658                )
13659            });
13660        })
13661    }
13662
13663    pub fn move_to_start_of_excerpt(
13664        &mut self,
13665        _: &MoveToStartOfExcerpt,
13666        window: &mut Window,
13667        cx: &mut Context<Self>,
13668    ) {
13669        if matches!(self.mode, EditorMode::SingleLine) {
13670            cx.propagate();
13671            return;
13672        }
13673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13674        self.change_selections(Default::default(), window, cx, |s| {
13675            s.move_with(|map, selection| {
13676                selection.collapse_to(
13677                    movement::start_of_excerpt(
13678                        map,
13679                        selection.head(),
13680                        workspace::searchable::Direction::Prev,
13681                    ),
13682                    SelectionGoal::None,
13683                )
13684            });
13685        })
13686    }
13687
13688    pub fn move_to_start_of_next_excerpt(
13689        &mut self,
13690        _: &MoveToStartOfNextExcerpt,
13691        window: &mut Window,
13692        cx: &mut Context<Self>,
13693    ) {
13694        if matches!(self.mode, EditorMode::SingleLine) {
13695            cx.propagate();
13696            return;
13697        }
13698
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.move_with(|map, selection| {
13701                selection.collapse_to(
13702                    movement::start_of_excerpt(
13703                        map,
13704                        selection.head(),
13705                        workspace::searchable::Direction::Next,
13706                    ),
13707                    SelectionGoal::None,
13708                )
13709            });
13710        })
13711    }
13712
13713    pub fn move_to_end_of_excerpt(
13714        &mut self,
13715        _: &MoveToEndOfExcerpt,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if matches!(self.mode, EditorMode::SingleLine) {
13720            cx.propagate();
13721            return;
13722        }
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                selection.collapse_to(
13727                    movement::end_of_excerpt(
13728                        map,
13729                        selection.head(),
13730                        workspace::searchable::Direction::Next,
13731                    ),
13732                    SelectionGoal::None,
13733                )
13734            });
13735        })
13736    }
13737
13738    pub fn move_to_end_of_previous_excerpt(
13739        &mut self,
13740        _: &MoveToEndOfPreviousExcerpt,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if matches!(self.mode, EditorMode::SingleLine) {
13745            cx.propagate();
13746            return;
13747        }
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        self.change_selections(Default::default(), window, cx, |s| {
13750            s.move_with(|map, selection| {
13751                selection.collapse_to(
13752                    movement::end_of_excerpt(
13753                        map,
13754                        selection.head(),
13755                        workspace::searchable::Direction::Prev,
13756                    ),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_start_of_excerpt(
13764        &mut self,
13765        _: &SelectToStartOfExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn select_to_start_of_next_excerpt(
13785        &mut self,
13786        _: &SelectToStartOfNextExcerpt,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_heads_with(|map, head, _| {
13797                (
13798                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13799                    SelectionGoal::None,
13800                )
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_end_of_excerpt(
13806        &mut self,
13807        _: &SelectToEndOfExcerpt,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        if matches!(self.mode, EditorMode::SingleLine) {
13812            cx.propagate();
13813            return;
13814        }
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (
13819                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn select_to_end_of_previous_excerpt(
13827        &mut self,
13828        _: &SelectToEndOfPreviousExcerpt,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_heads_with(|map, head, _| {
13839                (
13840                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_beginning(
13848        &mut self,
13849        _: &MoveToBeginning,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.select_ranges(vec![0..0]);
13860        });
13861    }
13862
13863    pub fn select_to_beginning(
13864        &mut self,
13865        _: &SelectToBeginning,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        let mut selection = self.selections.last::<Point>(cx);
13870        selection.set_head(Point::zero(), SelectionGoal::None);
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.select(vec![selection]);
13874        });
13875    }
13876
13877    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        let cursor = self.buffer.read(cx).read(cx).len();
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.select_ranges(vec![cursor..cursor])
13886        });
13887    }
13888
13889    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13890        self.nav_history = nav_history;
13891    }
13892
13893    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13894        self.nav_history.as_ref()
13895    }
13896
13897    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13898        self.push_to_nav_history(
13899            self.selections.newest_anchor().head(),
13900            None,
13901            false,
13902            true,
13903            cx,
13904        );
13905    }
13906
13907    fn push_to_nav_history(
13908        &mut self,
13909        cursor_anchor: Anchor,
13910        new_position: Option<Point>,
13911        is_deactivate: bool,
13912        always: bool,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if let Some(nav_history) = self.nav_history.as_mut() {
13916            let buffer = self.buffer.read(cx).read(cx);
13917            let cursor_position = cursor_anchor.to_point(&buffer);
13918            let scroll_state = self.scroll_manager.anchor();
13919            let scroll_top_row = scroll_state.top_row(&buffer);
13920            drop(buffer);
13921
13922            if let Some(new_position) = new_position {
13923                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13924                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13925                    return;
13926                }
13927            }
13928
13929            nav_history.push(
13930                Some(NavigationData {
13931                    cursor_anchor,
13932                    cursor_position,
13933                    scroll_anchor: scroll_state,
13934                    scroll_top_row,
13935                }),
13936                cx,
13937            );
13938            cx.emit(EditorEvent::PushedToNavHistory {
13939                anchor: cursor_anchor,
13940                is_deactivate,
13941            })
13942        }
13943    }
13944
13945    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        let buffer = self.buffer.read(cx).snapshot(cx);
13948        let mut selection = self.selections.first::<usize>(cx);
13949        selection.set_head(buffer.len(), SelectionGoal::None);
13950        self.change_selections(Default::default(), window, cx, |s| {
13951            s.select(vec![selection]);
13952        });
13953    }
13954
13955    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13957        let end = self.buffer.read(cx).read(cx).len();
13958        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13959            s.select_ranges(vec![0..end]);
13960        });
13961    }
13962
13963    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13965        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13966        let mut selections = self.selections.all::<Point>(cx);
13967        let max_point = display_map.buffer_snapshot.max_point();
13968        for selection in &mut selections {
13969            let rows = selection.spanned_rows(true, &display_map);
13970            selection.start = Point::new(rows.start.0, 0);
13971            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13972            selection.reversed = false;
13973        }
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.select(selections);
13976        });
13977    }
13978
13979    pub fn split_selection_into_lines(
13980        &mut self,
13981        action: &SplitSelectionIntoLines,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        let selections = self
13986            .selections
13987            .all::<Point>(cx)
13988            .into_iter()
13989            .map(|selection| selection.start..selection.end)
13990            .collect::<Vec<_>>();
13991        self.unfold_ranges(&selections, true, true, cx);
13992
13993        let mut new_selection_ranges = Vec::new();
13994        {
13995            let buffer = self.buffer.read(cx).read(cx);
13996            for selection in selections {
13997                for row in selection.start.row..selection.end.row {
13998                    let line_start = Point::new(row, 0);
13999                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14000
14001                    if action.keep_selections {
14002                        // Keep the selection range for each line
14003                        let selection_start = if row == selection.start.row {
14004                            selection.start
14005                        } else {
14006                            line_start
14007                        };
14008                        new_selection_ranges.push(selection_start..line_end);
14009                    } else {
14010                        // Collapse to cursor at end of line
14011                        new_selection_ranges.push(line_end..line_end);
14012                    }
14013                }
14014
14015                let is_multiline_selection = selection.start.row != selection.end.row;
14016                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14017                // so this action feels more ergonomic when paired with other selection operations
14018                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14019                if !should_skip_last {
14020                    if action.keep_selections {
14021                        if is_multiline_selection {
14022                            let line_start = Point::new(selection.end.row, 0);
14023                            new_selection_ranges.push(line_start..selection.end);
14024                        } else {
14025                            new_selection_ranges.push(selection.start..selection.end);
14026                        }
14027                    } else {
14028                        new_selection_ranges.push(selection.end..selection.end);
14029                    }
14030                }
14031            }
14032        }
14033        self.change_selections(Default::default(), window, cx, |s| {
14034            s.select_ranges(new_selection_ranges);
14035        });
14036    }
14037
14038    pub fn add_selection_above(
14039        &mut self,
14040        _: &AddSelectionAbove,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        self.add_selection(true, window, cx);
14045    }
14046
14047    pub fn add_selection_below(
14048        &mut self,
14049        _: &AddSelectionBelow,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        self.add_selection(false, window, cx);
14054    }
14055
14056    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14058
14059        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14060        let all_selections = self.selections.all::<Point>(cx);
14061        let text_layout_details = self.text_layout_details(window);
14062
14063        let (mut columnar_selections, new_selections_to_columnarize) = {
14064            if let Some(state) = self.add_selections_state.as_ref() {
14065                let columnar_selection_ids: HashSet<_> = state
14066                    .groups
14067                    .iter()
14068                    .flat_map(|group| group.stack.iter())
14069                    .copied()
14070                    .collect();
14071
14072                all_selections
14073                    .into_iter()
14074                    .partition(|s| columnar_selection_ids.contains(&s.id))
14075            } else {
14076                (Vec::new(), all_selections)
14077            }
14078        };
14079
14080        let mut state = self
14081            .add_selections_state
14082            .take()
14083            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14084
14085        for selection in new_selections_to_columnarize {
14086            let range = selection.display_range(&display_map).sorted();
14087            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14088            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14089            let positions = start_x.min(end_x)..start_x.max(end_x);
14090            let mut stack = Vec::new();
14091            for row in range.start.row().0..=range.end.row().0 {
14092                if let Some(selection) = self.selections.build_columnar_selection(
14093                    &display_map,
14094                    DisplayRow(row),
14095                    &positions,
14096                    selection.reversed,
14097                    &text_layout_details,
14098                ) {
14099                    stack.push(selection.id);
14100                    columnar_selections.push(selection);
14101                }
14102            }
14103            if !stack.is_empty() {
14104                if above {
14105                    stack.reverse();
14106                }
14107                state.groups.push(AddSelectionsGroup { above, stack });
14108            }
14109        }
14110
14111        let mut final_selections = Vec::new();
14112        let end_row = if above {
14113            DisplayRow(0)
14114        } else {
14115            display_map.max_point().row()
14116        };
14117
14118        let mut last_added_item_per_group = HashMap::default();
14119        for group in state.groups.iter_mut() {
14120            if let Some(last_id) = group.stack.last() {
14121                last_added_item_per_group.insert(*last_id, group);
14122            }
14123        }
14124
14125        for selection in columnar_selections {
14126            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14127                if above == group.above {
14128                    let range = selection.display_range(&display_map).sorted();
14129                    debug_assert_eq!(range.start.row(), range.end.row());
14130                    let mut row = range.start.row();
14131                    let positions =
14132                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14133                            px(start)..px(end)
14134                        } else {
14135                            let start_x =
14136                                display_map.x_for_display_point(range.start, &text_layout_details);
14137                            let end_x =
14138                                display_map.x_for_display_point(range.end, &text_layout_details);
14139                            start_x.min(end_x)..start_x.max(end_x)
14140                        };
14141
14142                    let mut maybe_new_selection = None;
14143                    while row != end_row {
14144                        if above {
14145                            row.0 -= 1;
14146                        } else {
14147                            row.0 += 1;
14148                        }
14149                        if let Some(new_selection) = self.selections.build_columnar_selection(
14150                            &display_map,
14151                            row,
14152                            &positions,
14153                            selection.reversed,
14154                            &text_layout_details,
14155                        ) {
14156                            maybe_new_selection = Some(new_selection);
14157                            break;
14158                        }
14159                    }
14160
14161                    if let Some(new_selection) = maybe_new_selection {
14162                        group.stack.push(new_selection.id);
14163                        if above {
14164                            final_selections.push(new_selection);
14165                            final_selections.push(selection);
14166                        } else {
14167                            final_selections.push(selection);
14168                            final_selections.push(new_selection);
14169                        }
14170                    } else {
14171                        final_selections.push(selection);
14172                    }
14173                } else {
14174                    group.stack.pop();
14175                }
14176            } else {
14177                final_selections.push(selection);
14178            }
14179        }
14180
14181        self.change_selections(Default::default(), window, cx, |s| {
14182            s.select(final_selections);
14183        });
14184
14185        let final_selection_ids: HashSet<_> = self
14186            .selections
14187            .all::<Point>(cx)
14188            .iter()
14189            .map(|s| s.id)
14190            .collect();
14191        state.groups.retain_mut(|group| {
14192            // selections might get merged above so we remove invalid items from stacks
14193            group.stack.retain(|id| final_selection_ids.contains(id));
14194
14195            // single selection in stack can be treated as initial state
14196            group.stack.len() > 1
14197        });
14198
14199        if !state.groups.is_empty() {
14200            self.add_selections_state = Some(state);
14201        }
14202    }
14203
14204    fn select_match_ranges(
14205        &mut self,
14206        range: Range<usize>,
14207        reversed: bool,
14208        replace_newest: bool,
14209        auto_scroll: Option<Autoscroll>,
14210        window: &mut Window,
14211        cx: &mut Context<Editor>,
14212    ) {
14213        self.unfold_ranges(
14214            std::slice::from_ref(&range),
14215            false,
14216            auto_scroll.is_some(),
14217            cx,
14218        );
14219        let effects = if let Some(scroll) = auto_scroll {
14220            SelectionEffects::scroll(scroll)
14221        } else {
14222            SelectionEffects::no_scroll()
14223        };
14224        self.change_selections(effects, window, cx, |s| {
14225            if replace_newest {
14226                s.delete(s.newest_anchor().id);
14227            }
14228            if reversed {
14229                s.insert_range(range.end..range.start);
14230            } else {
14231                s.insert_range(range);
14232            }
14233        });
14234    }
14235
14236    pub fn select_next_match_internal(
14237        &mut self,
14238        display_map: &DisplaySnapshot,
14239        replace_newest: bool,
14240        autoscroll: Option<Autoscroll>,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Result<()> {
14244        let buffer = &display_map.buffer_snapshot;
14245        let mut selections = self.selections.all::<usize>(cx);
14246        if let Some(mut select_next_state) = self.select_next_state.take() {
14247            let query = &select_next_state.query;
14248            if !select_next_state.done {
14249                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14250                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14251                let mut next_selected_range = None;
14252
14253                let bytes_after_last_selection =
14254                    buffer.bytes_in_range(last_selection.end..buffer.len());
14255                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14256                let query_matches = query
14257                    .stream_find_iter(bytes_after_last_selection)
14258                    .map(|result| (last_selection.end, result))
14259                    .chain(
14260                        query
14261                            .stream_find_iter(bytes_before_first_selection)
14262                            .map(|result| (0, result)),
14263                    );
14264
14265                for (start_offset, query_match) in query_matches {
14266                    let query_match = query_match.unwrap(); // can only fail due to I/O
14267                    let offset_range =
14268                        start_offset + query_match.start()..start_offset + query_match.end();
14269
14270                    if !select_next_state.wordwise
14271                        || (!buffer.is_inside_word(offset_range.start, None)
14272                            && !buffer.is_inside_word(offset_range.end, None))
14273                    {
14274                        // TODO: This is n^2, because we might check all the selections
14275                        if !selections
14276                            .iter()
14277                            .any(|selection| selection.range().overlaps(&offset_range))
14278                        {
14279                            next_selected_range = Some(offset_range);
14280                            break;
14281                        }
14282                    }
14283                }
14284
14285                if let Some(next_selected_range) = next_selected_range {
14286                    self.select_match_ranges(
14287                        next_selected_range,
14288                        last_selection.reversed,
14289                        replace_newest,
14290                        autoscroll,
14291                        window,
14292                        cx,
14293                    );
14294                } else {
14295                    select_next_state.done = true;
14296                }
14297            }
14298
14299            self.select_next_state = Some(select_next_state);
14300        } else {
14301            let mut only_carets = true;
14302            let mut same_text_selected = true;
14303            let mut selected_text = None;
14304
14305            let mut selections_iter = selections.iter().peekable();
14306            while let Some(selection) = selections_iter.next() {
14307                if selection.start != selection.end {
14308                    only_carets = false;
14309                }
14310
14311                if same_text_selected {
14312                    if selected_text.is_none() {
14313                        selected_text =
14314                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14315                    }
14316
14317                    if let Some(next_selection) = selections_iter.peek() {
14318                        if next_selection.range().len() == selection.range().len() {
14319                            let next_selected_text = buffer
14320                                .text_for_range(next_selection.range())
14321                                .collect::<String>();
14322                            if Some(next_selected_text) != selected_text {
14323                                same_text_selected = false;
14324                                selected_text = None;
14325                            }
14326                        } else {
14327                            same_text_selected = false;
14328                            selected_text = None;
14329                        }
14330                    }
14331                }
14332            }
14333
14334            if only_carets {
14335                for selection in &mut selections {
14336                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14337                    selection.start = word_range.start;
14338                    selection.end = word_range.end;
14339                    selection.goal = SelectionGoal::None;
14340                    selection.reversed = false;
14341                    self.select_match_ranges(
14342                        selection.start..selection.end,
14343                        selection.reversed,
14344                        replace_newest,
14345                        autoscroll,
14346                        window,
14347                        cx,
14348                    );
14349                }
14350
14351                if selections.len() == 1 {
14352                    let selection = selections
14353                        .last()
14354                        .expect("ensured that there's only one selection");
14355                    let query = buffer
14356                        .text_for_range(selection.start..selection.end)
14357                        .collect::<String>();
14358                    let is_empty = query.is_empty();
14359                    let select_state = SelectNextState {
14360                        query: AhoCorasick::new(&[query])?,
14361                        wordwise: true,
14362                        done: is_empty,
14363                    };
14364                    self.select_next_state = Some(select_state);
14365                } else {
14366                    self.select_next_state = None;
14367                }
14368            } else if let Some(selected_text) = selected_text {
14369                self.select_next_state = Some(SelectNextState {
14370                    query: AhoCorasick::new(&[selected_text])?,
14371                    wordwise: false,
14372                    done: false,
14373                });
14374                self.select_next_match_internal(
14375                    display_map,
14376                    replace_newest,
14377                    autoscroll,
14378                    window,
14379                    cx,
14380                )?;
14381            }
14382        }
14383        Ok(())
14384    }
14385
14386    pub fn select_all_matches(
14387        &mut self,
14388        _action: &SelectAllMatches,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) -> Result<()> {
14392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14393
14394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14395
14396        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14397        let Some(select_next_state) = self.select_next_state.as_mut() else {
14398            return Ok(());
14399        };
14400        if select_next_state.done {
14401            return Ok(());
14402        }
14403
14404        let mut new_selections = Vec::new();
14405
14406        let reversed = self.selections.oldest::<usize>(cx).reversed;
14407        let buffer = &display_map.buffer_snapshot;
14408        let query_matches = select_next_state
14409            .query
14410            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14411
14412        for query_match in query_matches.into_iter() {
14413            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14414            let offset_range = if reversed {
14415                query_match.end()..query_match.start()
14416            } else {
14417                query_match.start()..query_match.end()
14418            };
14419
14420            if !select_next_state.wordwise
14421                || (!buffer.is_inside_word(offset_range.start, None)
14422                    && !buffer.is_inside_word(offset_range.end, None))
14423            {
14424                new_selections.push(offset_range.start..offset_range.end);
14425            }
14426        }
14427
14428        select_next_state.done = true;
14429
14430        if new_selections.is_empty() {
14431            log::error!("bug: new_selections is empty in select_all_matches");
14432            return Ok(());
14433        }
14434
14435        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14436        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14437            selections.select_ranges(new_selections)
14438        });
14439
14440        Ok(())
14441    }
14442
14443    pub fn select_next(
14444        &mut self,
14445        action: &SelectNext,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) -> Result<()> {
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14451        self.select_next_match_internal(
14452            &display_map,
14453            action.replace_newest,
14454            Some(Autoscroll::newest()),
14455            window,
14456            cx,
14457        )?;
14458        Ok(())
14459    }
14460
14461    pub fn select_previous(
14462        &mut self,
14463        action: &SelectPrevious,
14464        window: &mut Window,
14465        cx: &mut Context<Self>,
14466    ) -> Result<()> {
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14469        let buffer = &display_map.buffer_snapshot;
14470        let mut selections = self.selections.all::<usize>(cx);
14471        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14472            let query = &select_prev_state.query;
14473            if !select_prev_state.done {
14474                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14475                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14476                let mut next_selected_range = None;
14477                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14478                let bytes_before_last_selection =
14479                    buffer.reversed_bytes_in_range(0..last_selection.start);
14480                let bytes_after_first_selection =
14481                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14482                let query_matches = query
14483                    .stream_find_iter(bytes_before_last_selection)
14484                    .map(|result| (last_selection.start, result))
14485                    .chain(
14486                        query
14487                            .stream_find_iter(bytes_after_first_selection)
14488                            .map(|result| (buffer.len(), result)),
14489                    );
14490                for (end_offset, query_match) in query_matches {
14491                    let query_match = query_match.unwrap(); // can only fail due to I/O
14492                    let offset_range =
14493                        end_offset - query_match.end()..end_offset - query_match.start();
14494
14495                    if !select_prev_state.wordwise
14496                        || (!buffer.is_inside_word(offset_range.start, None)
14497                            && !buffer.is_inside_word(offset_range.end, None))
14498                    {
14499                        next_selected_range = Some(offset_range);
14500                        break;
14501                    }
14502                }
14503
14504                if let Some(next_selected_range) = next_selected_range {
14505                    self.select_match_ranges(
14506                        next_selected_range,
14507                        last_selection.reversed,
14508                        action.replace_newest,
14509                        Some(Autoscroll::newest()),
14510                        window,
14511                        cx,
14512                    );
14513                } else {
14514                    select_prev_state.done = true;
14515                }
14516            }
14517
14518            self.select_prev_state = Some(select_prev_state);
14519        } else {
14520            let mut only_carets = true;
14521            let mut same_text_selected = true;
14522            let mut selected_text = None;
14523
14524            let mut selections_iter = selections.iter().peekable();
14525            while let Some(selection) = selections_iter.next() {
14526                if selection.start != selection.end {
14527                    only_carets = false;
14528                }
14529
14530                if same_text_selected {
14531                    if selected_text.is_none() {
14532                        selected_text =
14533                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14534                    }
14535
14536                    if let Some(next_selection) = selections_iter.peek() {
14537                        if next_selection.range().len() == selection.range().len() {
14538                            let next_selected_text = buffer
14539                                .text_for_range(next_selection.range())
14540                                .collect::<String>();
14541                            if Some(next_selected_text) != selected_text {
14542                                same_text_selected = false;
14543                                selected_text = None;
14544                            }
14545                        } else {
14546                            same_text_selected = false;
14547                            selected_text = None;
14548                        }
14549                    }
14550                }
14551            }
14552
14553            if only_carets {
14554                for selection in &mut selections {
14555                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14556                    selection.start = word_range.start;
14557                    selection.end = word_range.end;
14558                    selection.goal = SelectionGoal::None;
14559                    selection.reversed = false;
14560                    self.select_match_ranges(
14561                        selection.start..selection.end,
14562                        selection.reversed,
14563                        action.replace_newest,
14564                        Some(Autoscroll::newest()),
14565                        window,
14566                        cx,
14567                    );
14568                }
14569                if selections.len() == 1 {
14570                    let selection = selections
14571                        .last()
14572                        .expect("ensured that there's only one selection");
14573                    let query = buffer
14574                        .text_for_range(selection.start..selection.end)
14575                        .collect::<String>();
14576                    let is_empty = query.is_empty();
14577                    let select_state = SelectNextState {
14578                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14579                        wordwise: true,
14580                        done: is_empty,
14581                    };
14582                    self.select_prev_state = Some(select_state);
14583                } else {
14584                    self.select_prev_state = None;
14585                }
14586            } else if let Some(selected_text) = selected_text {
14587                self.select_prev_state = Some(SelectNextState {
14588                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14589                    wordwise: false,
14590                    done: false,
14591                });
14592                self.select_previous(action, window, cx)?;
14593            }
14594        }
14595        Ok(())
14596    }
14597
14598    pub fn find_next_match(
14599        &mut self,
14600        _: &FindNextMatch,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) -> Result<()> {
14604        let selections = self.selections.disjoint_anchors_arc();
14605        match selections.first() {
14606            Some(first) if selections.len() >= 2 => {
14607                self.change_selections(Default::default(), window, cx, |s| {
14608                    s.select_ranges([first.range()]);
14609                });
14610            }
14611            _ => self.select_next(
14612                &SelectNext {
14613                    replace_newest: true,
14614                },
14615                window,
14616                cx,
14617            )?,
14618        }
14619        Ok(())
14620    }
14621
14622    pub fn find_previous_match(
14623        &mut self,
14624        _: &FindPreviousMatch,
14625        window: &mut Window,
14626        cx: &mut Context<Self>,
14627    ) -> Result<()> {
14628        let selections = self.selections.disjoint_anchors_arc();
14629        match selections.last() {
14630            Some(last) if selections.len() >= 2 => {
14631                self.change_selections(Default::default(), window, cx, |s| {
14632                    s.select_ranges([last.range()]);
14633                });
14634            }
14635            _ => self.select_previous(
14636                &SelectPrevious {
14637                    replace_newest: true,
14638                },
14639                window,
14640                cx,
14641            )?,
14642        }
14643        Ok(())
14644    }
14645
14646    pub fn toggle_comments(
14647        &mut self,
14648        action: &ToggleComments,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) {
14652        if self.read_only(cx) {
14653            return;
14654        }
14655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14656        let text_layout_details = &self.text_layout_details(window);
14657        self.transact(window, cx, |this, window, cx| {
14658            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14659            let mut edits = Vec::new();
14660            let mut selection_edit_ranges = Vec::new();
14661            let mut last_toggled_row = None;
14662            let snapshot = this.buffer.read(cx).read(cx);
14663            let empty_str: Arc<str> = Arc::default();
14664            let mut suffixes_inserted = Vec::new();
14665            let ignore_indent = action.ignore_indent;
14666
14667            fn comment_prefix_range(
14668                snapshot: &MultiBufferSnapshot,
14669                row: MultiBufferRow,
14670                comment_prefix: &str,
14671                comment_prefix_whitespace: &str,
14672                ignore_indent: bool,
14673            ) -> Range<Point> {
14674                let indent_size = if ignore_indent {
14675                    0
14676                } else {
14677                    snapshot.indent_size_for_line(row).len
14678                };
14679
14680                let start = Point::new(row.0, indent_size);
14681
14682                let mut line_bytes = snapshot
14683                    .bytes_in_range(start..snapshot.max_point())
14684                    .flatten()
14685                    .copied();
14686
14687                // If this line currently begins with the line comment prefix, then record
14688                // the range containing the prefix.
14689                if line_bytes
14690                    .by_ref()
14691                    .take(comment_prefix.len())
14692                    .eq(comment_prefix.bytes())
14693                {
14694                    // Include any whitespace that matches the comment prefix.
14695                    let matching_whitespace_len = line_bytes
14696                        .zip(comment_prefix_whitespace.bytes())
14697                        .take_while(|(a, b)| a == b)
14698                        .count() as u32;
14699                    let end = Point::new(
14700                        start.row,
14701                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14702                    );
14703                    start..end
14704                } else {
14705                    start..start
14706                }
14707            }
14708
14709            fn comment_suffix_range(
14710                snapshot: &MultiBufferSnapshot,
14711                row: MultiBufferRow,
14712                comment_suffix: &str,
14713                comment_suffix_has_leading_space: bool,
14714            ) -> Range<Point> {
14715                let end = Point::new(row.0, snapshot.line_len(row));
14716                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14717
14718                let mut line_end_bytes = snapshot
14719                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14720                    .flatten()
14721                    .copied();
14722
14723                let leading_space_len = if suffix_start_column > 0
14724                    && line_end_bytes.next() == Some(b' ')
14725                    && comment_suffix_has_leading_space
14726                {
14727                    1
14728                } else {
14729                    0
14730                };
14731
14732                // If this line currently begins with the line comment prefix, then record
14733                // the range containing the prefix.
14734                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14735                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14736                    start..end
14737                } else {
14738                    end..end
14739                }
14740            }
14741
14742            // TODO: Handle selections that cross excerpts
14743            for selection in &mut selections {
14744                let start_column = snapshot
14745                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14746                    .len;
14747                let language = if let Some(language) =
14748                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14749                {
14750                    language
14751                } else {
14752                    continue;
14753                };
14754
14755                selection_edit_ranges.clear();
14756
14757                // If multiple selections contain a given row, avoid processing that
14758                // row more than once.
14759                let mut start_row = MultiBufferRow(selection.start.row);
14760                if last_toggled_row == Some(start_row) {
14761                    start_row = start_row.next_row();
14762                }
14763                let end_row =
14764                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14765                        MultiBufferRow(selection.end.row - 1)
14766                    } else {
14767                        MultiBufferRow(selection.end.row)
14768                    };
14769                last_toggled_row = Some(end_row);
14770
14771                if start_row > end_row {
14772                    continue;
14773                }
14774
14775                // If the language has line comments, toggle those.
14776                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14777
14778                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14779                if ignore_indent {
14780                    full_comment_prefixes = full_comment_prefixes
14781                        .into_iter()
14782                        .map(|s| Arc::from(s.trim_end()))
14783                        .collect();
14784                }
14785
14786                if !full_comment_prefixes.is_empty() {
14787                    let first_prefix = full_comment_prefixes
14788                        .first()
14789                        .expect("prefixes is non-empty");
14790                    let prefix_trimmed_lengths = full_comment_prefixes
14791                        .iter()
14792                        .map(|p| p.trim_end_matches(' ').len())
14793                        .collect::<SmallVec<[usize; 4]>>();
14794
14795                    let mut all_selection_lines_are_comments = true;
14796
14797                    for row in start_row.0..=end_row.0 {
14798                        let row = MultiBufferRow(row);
14799                        if start_row < end_row && snapshot.is_line_blank(row) {
14800                            continue;
14801                        }
14802
14803                        let prefix_range = full_comment_prefixes
14804                            .iter()
14805                            .zip(prefix_trimmed_lengths.iter().copied())
14806                            .map(|(prefix, trimmed_prefix_len)| {
14807                                comment_prefix_range(
14808                                    snapshot.deref(),
14809                                    row,
14810                                    &prefix[..trimmed_prefix_len],
14811                                    &prefix[trimmed_prefix_len..],
14812                                    ignore_indent,
14813                                )
14814                            })
14815                            .max_by_key(|range| range.end.column - range.start.column)
14816                            .expect("prefixes is non-empty");
14817
14818                        if prefix_range.is_empty() {
14819                            all_selection_lines_are_comments = false;
14820                        }
14821
14822                        selection_edit_ranges.push(prefix_range);
14823                    }
14824
14825                    if all_selection_lines_are_comments {
14826                        edits.extend(
14827                            selection_edit_ranges
14828                                .iter()
14829                                .cloned()
14830                                .map(|range| (range, empty_str.clone())),
14831                        );
14832                    } else {
14833                        let min_column = selection_edit_ranges
14834                            .iter()
14835                            .map(|range| range.start.column)
14836                            .min()
14837                            .unwrap_or(0);
14838                        edits.extend(selection_edit_ranges.iter().map(|range| {
14839                            let position = Point::new(range.start.row, min_column);
14840                            (position..position, first_prefix.clone())
14841                        }));
14842                    }
14843                } else if let Some(BlockCommentConfig {
14844                    start: full_comment_prefix,
14845                    end: comment_suffix,
14846                    ..
14847                }) = language.block_comment()
14848                {
14849                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14850                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14851                    let prefix_range = comment_prefix_range(
14852                        snapshot.deref(),
14853                        start_row,
14854                        comment_prefix,
14855                        comment_prefix_whitespace,
14856                        ignore_indent,
14857                    );
14858                    let suffix_range = comment_suffix_range(
14859                        snapshot.deref(),
14860                        end_row,
14861                        comment_suffix.trim_start_matches(' '),
14862                        comment_suffix.starts_with(' '),
14863                    );
14864
14865                    if prefix_range.is_empty() || suffix_range.is_empty() {
14866                        edits.push((
14867                            prefix_range.start..prefix_range.start,
14868                            full_comment_prefix.clone(),
14869                        ));
14870                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14871                        suffixes_inserted.push((end_row, comment_suffix.len()));
14872                    } else {
14873                        edits.push((prefix_range, empty_str.clone()));
14874                        edits.push((suffix_range, empty_str.clone()));
14875                    }
14876                } else {
14877                    continue;
14878                }
14879            }
14880
14881            drop(snapshot);
14882            this.buffer.update(cx, |buffer, cx| {
14883                buffer.edit(edits, None, cx);
14884            });
14885
14886            // Adjust selections so that they end before any comment suffixes that
14887            // were inserted.
14888            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14889            let mut selections = this.selections.all::<Point>(cx);
14890            let snapshot = this.buffer.read(cx).read(cx);
14891            for selection in &mut selections {
14892                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14893                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14894                        Ordering::Less => {
14895                            suffixes_inserted.next();
14896                            continue;
14897                        }
14898                        Ordering::Greater => break,
14899                        Ordering::Equal => {
14900                            if selection.end.column == snapshot.line_len(row) {
14901                                if selection.is_empty() {
14902                                    selection.start.column -= suffix_len as u32;
14903                                }
14904                                selection.end.column -= suffix_len as u32;
14905                            }
14906                            break;
14907                        }
14908                    }
14909                }
14910            }
14911
14912            drop(snapshot);
14913            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14914
14915            let selections = this.selections.all::<Point>(cx);
14916            let selections_on_single_row = selections.windows(2).all(|selections| {
14917                selections[0].start.row == selections[1].start.row
14918                    && selections[0].end.row == selections[1].end.row
14919                    && selections[0].start.row == selections[0].end.row
14920            });
14921            let selections_selecting = selections
14922                .iter()
14923                .any(|selection| selection.start != selection.end);
14924            let advance_downwards = action.advance_downwards
14925                && selections_on_single_row
14926                && !selections_selecting
14927                && !matches!(this.mode, EditorMode::SingleLine);
14928
14929            if advance_downwards {
14930                let snapshot = this.buffer.read(cx).snapshot(cx);
14931
14932                this.change_selections(Default::default(), window, cx, |s| {
14933                    s.move_cursors_with(|display_snapshot, display_point, _| {
14934                        let mut point = display_point.to_point(display_snapshot);
14935                        point.row += 1;
14936                        point = snapshot.clip_point(point, Bias::Left);
14937                        let display_point = point.to_display_point(display_snapshot);
14938                        let goal = SelectionGoal::HorizontalPosition(
14939                            display_snapshot
14940                                .x_for_display_point(display_point, text_layout_details)
14941                                .into(),
14942                        );
14943                        (display_point, goal)
14944                    })
14945                });
14946            }
14947        });
14948    }
14949
14950    pub fn select_enclosing_symbol(
14951        &mut self,
14952        _: &SelectEnclosingSymbol,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957
14958        let buffer = self.buffer.read(cx).snapshot(cx);
14959        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14960
14961        fn update_selection(
14962            selection: &Selection<usize>,
14963            buffer_snap: &MultiBufferSnapshot,
14964        ) -> Option<Selection<usize>> {
14965            let cursor = selection.head();
14966            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14967            for symbol in symbols.iter().rev() {
14968                let start = symbol.range.start.to_offset(buffer_snap);
14969                let end = symbol.range.end.to_offset(buffer_snap);
14970                let new_range = start..end;
14971                if start < selection.start || end > selection.end {
14972                    return Some(Selection {
14973                        id: selection.id,
14974                        start: new_range.start,
14975                        end: new_range.end,
14976                        goal: SelectionGoal::None,
14977                        reversed: selection.reversed,
14978                    });
14979                }
14980            }
14981            None
14982        }
14983
14984        let mut selected_larger_symbol = false;
14985        let new_selections = old_selections
14986            .iter()
14987            .map(|selection| match update_selection(selection, &buffer) {
14988                Some(new_selection) => {
14989                    if new_selection.range() != selection.range() {
14990                        selected_larger_symbol = true;
14991                    }
14992                    new_selection
14993                }
14994                None => selection.clone(),
14995            })
14996            .collect::<Vec<_>>();
14997
14998        if selected_larger_symbol {
14999            self.change_selections(Default::default(), window, cx, |s| {
15000                s.select(new_selections);
15001            });
15002        }
15003    }
15004
15005    pub fn select_larger_syntax_node(
15006        &mut self,
15007        _: &SelectLargerSyntaxNode,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) {
15011        let Some(visible_row_count) = self.visible_row_count() else {
15012            return;
15013        };
15014        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15015        if old_selections.is_empty() {
15016            return;
15017        }
15018
15019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15020
15021        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15022        let buffer = self.buffer.read(cx).snapshot(cx);
15023
15024        let mut selected_larger_node = false;
15025        let mut new_selections = old_selections
15026            .iter()
15027            .map(|selection| {
15028                let old_range = selection.start..selection.end;
15029
15030                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15031                    // manually select word at selection
15032                    if ["string_content", "inline"].contains(&node.kind()) {
15033                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15034                        // ignore if word is already selected
15035                        if !word_range.is_empty() && old_range != word_range {
15036                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15037                            // only select word if start and end point belongs to same word
15038                            if word_range == last_word_range {
15039                                selected_larger_node = true;
15040                                return Selection {
15041                                    id: selection.id,
15042                                    start: word_range.start,
15043                                    end: word_range.end,
15044                                    goal: SelectionGoal::None,
15045                                    reversed: selection.reversed,
15046                                };
15047                            }
15048                        }
15049                    }
15050                }
15051
15052                let mut new_range = old_range.clone();
15053                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15054                {
15055                    new_range = match containing_range {
15056                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15057                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15058                    };
15059                    if !node.is_named() {
15060                        continue;
15061                    }
15062                    if !display_map.intersects_fold(new_range.start)
15063                        && !display_map.intersects_fold(new_range.end)
15064                    {
15065                        break;
15066                    }
15067                }
15068
15069                selected_larger_node |= new_range != old_range;
15070                Selection {
15071                    id: selection.id,
15072                    start: new_range.start,
15073                    end: new_range.end,
15074                    goal: SelectionGoal::None,
15075                    reversed: selection.reversed,
15076                }
15077            })
15078            .collect::<Vec<_>>();
15079
15080        if !selected_larger_node {
15081            return; // don't put this call in the history
15082        }
15083
15084        // scroll based on transformation done to the last selection created by the user
15085        let (last_old, last_new) = old_selections
15086            .last()
15087            .zip(new_selections.last().cloned())
15088            .expect("old_selections isn't empty");
15089
15090        // revert selection
15091        let is_selection_reversed = {
15092            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15093            new_selections.last_mut().expect("checked above").reversed =
15094                should_newest_selection_be_reversed;
15095            should_newest_selection_be_reversed
15096        };
15097
15098        if selected_larger_node {
15099            self.select_syntax_node_history.disable_clearing = true;
15100            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15101                s.select(new_selections.clone());
15102            });
15103            self.select_syntax_node_history.disable_clearing = false;
15104        }
15105
15106        let start_row = last_new.start.to_display_point(&display_map).row().0;
15107        let end_row = last_new.end.to_display_point(&display_map).row().0;
15108        let selection_height = end_row - start_row + 1;
15109        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15110
15111        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15112        let scroll_behavior = if fits_on_the_screen {
15113            self.request_autoscroll(Autoscroll::fit(), cx);
15114            SelectSyntaxNodeScrollBehavior::FitSelection
15115        } else if is_selection_reversed {
15116            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15117            SelectSyntaxNodeScrollBehavior::CursorTop
15118        } else {
15119            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15120            SelectSyntaxNodeScrollBehavior::CursorBottom
15121        };
15122
15123        self.select_syntax_node_history.push((
15124            old_selections,
15125            scroll_behavior,
15126            is_selection_reversed,
15127        ));
15128    }
15129
15130    pub fn select_smaller_syntax_node(
15131        &mut self,
15132        _: &SelectSmallerSyntaxNode,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15137
15138        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15139            self.select_syntax_node_history.pop()
15140        {
15141            if let Some(selection) = selections.last_mut() {
15142                selection.reversed = is_selection_reversed;
15143            }
15144
15145            self.select_syntax_node_history.disable_clearing = true;
15146            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15147                s.select(selections.to_vec());
15148            });
15149            self.select_syntax_node_history.disable_clearing = false;
15150
15151            match scroll_behavior {
15152                SelectSyntaxNodeScrollBehavior::CursorTop => {
15153                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15154                }
15155                SelectSyntaxNodeScrollBehavior::FitSelection => {
15156                    self.request_autoscroll(Autoscroll::fit(), cx);
15157                }
15158                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15159                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15160                }
15161            }
15162        }
15163    }
15164
15165    pub fn unwrap_syntax_node(
15166        &mut self,
15167        _: &UnwrapSyntaxNode,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) {
15171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15172
15173        let buffer = self.buffer.read(cx).snapshot(cx);
15174        let selections = self
15175            .selections
15176            .all::<usize>(cx)
15177            .into_iter()
15178            // subtracting the offset requires sorting
15179            .sorted_by_key(|i| i.start);
15180
15181        let full_edits = selections
15182            .into_iter()
15183            .filter_map(|selection| {
15184                let child = if selection.is_empty()
15185                    && let Some((_, ancestor_range)) =
15186                        buffer.syntax_ancestor(selection.start..selection.end)
15187                {
15188                    match ancestor_range {
15189                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15190                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15191                    }
15192                } else {
15193                    selection.range()
15194                };
15195
15196                let mut parent = child.clone();
15197                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15198                    parent = match ancestor_range {
15199                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15200                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15201                    };
15202                    if parent.start < child.start || parent.end > child.end {
15203                        break;
15204                    }
15205                }
15206
15207                if parent == child {
15208                    return None;
15209                }
15210                let text = buffer.text_for_range(child).collect::<String>();
15211                Some((selection.id, parent, text))
15212            })
15213            .collect::<Vec<_>>();
15214        if full_edits.is_empty() {
15215            return;
15216        }
15217
15218        self.transact(window, cx, |this, window, cx| {
15219            this.buffer.update(cx, |buffer, cx| {
15220                buffer.edit(
15221                    full_edits
15222                        .iter()
15223                        .map(|(_, p, t)| (p.clone(), t.clone()))
15224                        .collect::<Vec<_>>(),
15225                    None,
15226                    cx,
15227                );
15228            });
15229            this.change_selections(Default::default(), window, cx, |s| {
15230                let mut offset = 0;
15231                let mut selections = vec![];
15232                for (id, parent, text) in full_edits {
15233                    let start = parent.start - offset;
15234                    offset += parent.len() - text.len();
15235                    selections.push(Selection {
15236                        id,
15237                        start,
15238                        end: start + text.len(),
15239                        reversed: false,
15240                        goal: Default::default(),
15241                    });
15242                }
15243                s.select(selections);
15244            });
15245        });
15246    }
15247
15248    pub fn select_next_syntax_node(
15249        &mut self,
15250        _: &SelectNextSyntaxNode,
15251        window: &mut Window,
15252        cx: &mut Context<Self>,
15253    ) {
15254        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15255        if old_selections.is_empty() {
15256            return;
15257        }
15258
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262        let mut selected_sibling = false;
15263
15264        let new_selections = old_selections
15265            .iter()
15266            .map(|selection| {
15267                let old_range = selection.start..selection.end;
15268
15269                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15270                    let new_range = node.byte_range();
15271                    selected_sibling = true;
15272                    Selection {
15273                        id: selection.id,
15274                        start: new_range.start,
15275                        end: new_range.end,
15276                        goal: SelectionGoal::None,
15277                        reversed: selection.reversed,
15278                    }
15279                } else {
15280                    selection.clone()
15281                }
15282            })
15283            .collect::<Vec<_>>();
15284
15285        if selected_sibling {
15286            self.change_selections(
15287                SelectionEffects::scroll(Autoscroll::fit()),
15288                window,
15289                cx,
15290                |s| {
15291                    s.select(new_selections);
15292                },
15293            );
15294        }
15295    }
15296
15297    pub fn select_prev_syntax_node(
15298        &mut self,
15299        _: &SelectPreviousSyntaxNode,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15304        if old_selections.is_empty() {
15305            return;
15306        }
15307
15308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15309
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311        let mut selected_sibling = false;
15312
15313        let new_selections = old_selections
15314            .iter()
15315            .map(|selection| {
15316                let old_range = selection.start..selection.end;
15317
15318                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15319                    let new_range = node.byte_range();
15320                    selected_sibling = true;
15321                    Selection {
15322                        id: selection.id,
15323                        start: new_range.start,
15324                        end: new_range.end,
15325                        goal: SelectionGoal::None,
15326                        reversed: selection.reversed,
15327                    }
15328                } else {
15329                    selection.clone()
15330                }
15331            })
15332            .collect::<Vec<_>>();
15333
15334        if selected_sibling {
15335            self.change_selections(
15336                SelectionEffects::scroll(Autoscroll::fit()),
15337                window,
15338                cx,
15339                |s| {
15340                    s.select(new_selections);
15341                },
15342            );
15343        }
15344    }
15345
15346    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15347        if !EditorSettings::get_global(cx).gutter.runnables {
15348            self.clear_tasks();
15349            return Task::ready(());
15350        }
15351        let project = self.project().map(Entity::downgrade);
15352        let task_sources = self.lsp_task_sources(cx);
15353        let multi_buffer = self.buffer.downgrade();
15354        cx.spawn_in(window, async move |editor, cx| {
15355            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15356            let Some(project) = project.and_then(|p| p.upgrade()) else {
15357                return;
15358            };
15359            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15360                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15361            }) else {
15362                return;
15363            };
15364
15365            let hide_runnables = project
15366                .update(cx, |project, _| project.is_via_collab())
15367                .unwrap_or(true);
15368            if hide_runnables {
15369                return;
15370            }
15371            let new_rows =
15372                cx.background_spawn({
15373                    let snapshot = display_snapshot.clone();
15374                    async move {
15375                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15376                    }
15377                })
15378                    .await;
15379            let Ok(lsp_tasks) =
15380                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15381            else {
15382                return;
15383            };
15384            let lsp_tasks = lsp_tasks.await;
15385
15386            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15387                lsp_tasks
15388                    .into_iter()
15389                    .flat_map(|(kind, tasks)| {
15390                        tasks.into_iter().filter_map(move |(location, task)| {
15391                            Some((kind.clone(), location?, task))
15392                        })
15393                    })
15394                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15395                        let buffer = location.target.buffer;
15396                        let buffer_snapshot = buffer.read(cx).snapshot();
15397                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15398                            |(excerpt_id, snapshot, _)| {
15399                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15400                                    display_snapshot
15401                                        .buffer_snapshot
15402                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15403                                } else {
15404                                    None
15405                                }
15406                            },
15407                        );
15408                        if let Some(offset) = offset {
15409                            let task_buffer_range =
15410                                location.target.range.to_point(&buffer_snapshot);
15411                            let context_buffer_range =
15412                                task_buffer_range.to_offset(&buffer_snapshot);
15413                            let context_range = BufferOffset(context_buffer_range.start)
15414                                ..BufferOffset(context_buffer_range.end);
15415
15416                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15417                                .or_insert_with(|| RunnableTasks {
15418                                    templates: Vec::new(),
15419                                    offset,
15420                                    column: task_buffer_range.start.column,
15421                                    extra_variables: HashMap::default(),
15422                                    context_range,
15423                                })
15424                                .templates
15425                                .push((kind, task.original_task().clone()));
15426                        }
15427
15428                        acc
15429                    })
15430            }) else {
15431                return;
15432            };
15433
15434            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15435                buffer.language_settings(cx).tasks.prefer_lsp
15436            }) else {
15437                return;
15438            };
15439
15440            let rows = Self::runnable_rows(
15441                project,
15442                display_snapshot,
15443                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15444                new_rows,
15445                cx.clone(),
15446            )
15447            .await;
15448            editor
15449                .update(cx, |editor, _| {
15450                    editor.clear_tasks();
15451                    for (key, mut value) in rows {
15452                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15453                            value.templates.extend(lsp_tasks.templates);
15454                        }
15455
15456                        editor.insert_tasks(key, value);
15457                    }
15458                    for (key, value) in lsp_tasks_by_rows {
15459                        editor.insert_tasks(key, value);
15460                    }
15461                })
15462                .ok();
15463        })
15464    }
15465    fn fetch_runnable_ranges(
15466        snapshot: &DisplaySnapshot,
15467        range: Range<Anchor>,
15468    ) -> Vec<language::RunnableRange> {
15469        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15470    }
15471
15472    fn runnable_rows(
15473        project: Entity<Project>,
15474        snapshot: DisplaySnapshot,
15475        prefer_lsp: bool,
15476        runnable_ranges: Vec<RunnableRange>,
15477        cx: AsyncWindowContext,
15478    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15479        cx.spawn(async move |cx| {
15480            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15481            for mut runnable in runnable_ranges {
15482                let Some(tasks) = cx
15483                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15484                    .ok()
15485                else {
15486                    continue;
15487                };
15488                let mut tasks = tasks.await;
15489
15490                if prefer_lsp {
15491                    tasks.retain(|(task_kind, _)| {
15492                        !matches!(task_kind, TaskSourceKind::Language { .. })
15493                    });
15494                }
15495                if tasks.is_empty() {
15496                    continue;
15497                }
15498
15499                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15500                let Some(row) = snapshot
15501                    .buffer_snapshot
15502                    .buffer_line_for_row(MultiBufferRow(point.row))
15503                    .map(|(_, range)| range.start.row)
15504                else {
15505                    continue;
15506                };
15507
15508                let context_range =
15509                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15510                runnable_rows.push((
15511                    (runnable.buffer_id, row),
15512                    RunnableTasks {
15513                        templates: tasks,
15514                        offset: snapshot
15515                            .buffer_snapshot
15516                            .anchor_before(runnable.run_range.start),
15517                        context_range,
15518                        column: point.column,
15519                        extra_variables: runnable.extra_captures,
15520                    },
15521                ));
15522            }
15523            runnable_rows
15524        })
15525    }
15526
15527    fn templates_with_tags(
15528        project: &Entity<Project>,
15529        runnable: &mut Runnable,
15530        cx: &mut App,
15531    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15532        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15533            let (worktree_id, file) = project
15534                .buffer_for_id(runnable.buffer, cx)
15535                .and_then(|buffer| buffer.read(cx).file())
15536                .map(|file| (file.worktree_id(cx), file.clone()))
15537                .unzip();
15538
15539            (
15540                project.task_store().read(cx).task_inventory().cloned(),
15541                worktree_id,
15542                file,
15543            )
15544        });
15545
15546        let tags = mem::take(&mut runnable.tags);
15547        let language = runnable.language.clone();
15548        cx.spawn(async move |cx| {
15549            let mut templates_with_tags = Vec::new();
15550            if let Some(inventory) = inventory {
15551                for RunnableTag(tag) in tags {
15552                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15553                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15554                    }) else {
15555                        return templates_with_tags;
15556                    };
15557                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15558                        move |(_, template)| {
15559                            template.tags.iter().any(|source_tag| source_tag == &tag)
15560                        },
15561                    ));
15562                }
15563            }
15564            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15565
15566            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15567                // Strongest source wins; if we have worktree tag binding, prefer that to
15568                // global and language bindings;
15569                // if we have a global binding, prefer that to language binding.
15570                let first_mismatch = templates_with_tags
15571                    .iter()
15572                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15573                if let Some(index) = first_mismatch {
15574                    templates_with_tags.truncate(index);
15575                }
15576            }
15577
15578            templates_with_tags
15579        })
15580    }
15581
15582    pub fn move_to_enclosing_bracket(
15583        &mut self,
15584        _: &MoveToEnclosingBracket,
15585        window: &mut Window,
15586        cx: &mut Context<Self>,
15587    ) {
15588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15589        self.change_selections(Default::default(), window, cx, |s| {
15590            s.move_offsets_with(|snapshot, selection| {
15591                let Some(enclosing_bracket_ranges) =
15592                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15593                else {
15594                    return;
15595                };
15596
15597                let mut best_length = usize::MAX;
15598                let mut best_inside = false;
15599                let mut best_in_bracket_range = false;
15600                let mut best_destination = None;
15601                for (open, close) in enclosing_bracket_ranges {
15602                    let close = close.to_inclusive();
15603                    let length = close.end() - open.start;
15604                    let inside = selection.start >= open.end && selection.end <= *close.start();
15605                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15606                        || close.contains(&selection.head());
15607
15608                    // If best is next to a bracket and current isn't, skip
15609                    if !in_bracket_range && best_in_bracket_range {
15610                        continue;
15611                    }
15612
15613                    // Prefer smaller lengths unless best is inside and current isn't
15614                    if length > best_length && (best_inside || !inside) {
15615                        continue;
15616                    }
15617
15618                    best_length = length;
15619                    best_inside = inside;
15620                    best_in_bracket_range = in_bracket_range;
15621                    best_destination = Some(
15622                        if close.contains(&selection.start) && close.contains(&selection.end) {
15623                            if inside { open.end } else { open.start }
15624                        } else if inside {
15625                            *close.start()
15626                        } else {
15627                            *close.end()
15628                        },
15629                    );
15630                }
15631
15632                if let Some(destination) = best_destination {
15633                    selection.collapse_to(destination, SelectionGoal::None);
15634                }
15635            })
15636        });
15637    }
15638
15639    pub fn undo_selection(
15640        &mut self,
15641        _: &UndoSelection,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15646        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15647            self.selection_history.mode = SelectionHistoryMode::Undoing;
15648            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15649                this.end_selection(window, cx);
15650                this.change_selections(
15651                    SelectionEffects::scroll(Autoscroll::newest()),
15652                    window,
15653                    cx,
15654                    |s| s.select_anchors(entry.selections.to_vec()),
15655                );
15656            });
15657            self.selection_history.mode = SelectionHistoryMode::Normal;
15658
15659            self.select_next_state = entry.select_next_state;
15660            self.select_prev_state = entry.select_prev_state;
15661            self.add_selections_state = entry.add_selections_state;
15662        }
15663    }
15664
15665    pub fn redo_selection(
15666        &mut self,
15667        _: &RedoSelection,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) {
15671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15672        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15673            self.selection_history.mode = SelectionHistoryMode::Redoing;
15674            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15675                this.end_selection(window, cx);
15676                this.change_selections(
15677                    SelectionEffects::scroll(Autoscroll::newest()),
15678                    window,
15679                    cx,
15680                    |s| s.select_anchors(entry.selections.to_vec()),
15681                );
15682            });
15683            self.selection_history.mode = SelectionHistoryMode::Normal;
15684
15685            self.select_next_state = entry.select_next_state;
15686            self.select_prev_state = entry.select_prev_state;
15687            self.add_selections_state = entry.add_selections_state;
15688        }
15689    }
15690
15691    pub fn expand_excerpts(
15692        &mut self,
15693        action: &ExpandExcerpts,
15694        _: &mut Window,
15695        cx: &mut Context<Self>,
15696    ) {
15697        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15698    }
15699
15700    pub fn expand_excerpts_down(
15701        &mut self,
15702        action: &ExpandExcerptsDown,
15703        _: &mut Window,
15704        cx: &mut Context<Self>,
15705    ) {
15706        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15707    }
15708
15709    pub fn expand_excerpts_up(
15710        &mut self,
15711        action: &ExpandExcerptsUp,
15712        _: &mut Window,
15713        cx: &mut Context<Self>,
15714    ) {
15715        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15716    }
15717
15718    pub fn expand_excerpts_for_direction(
15719        &mut self,
15720        lines: u32,
15721        direction: ExpandExcerptDirection,
15722
15723        cx: &mut Context<Self>,
15724    ) {
15725        let selections = self.selections.disjoint_anchors_arc();
15726
15727        let lines = if lines == 0 {
15728            EditorSettings::get_global(cx).expand_excerpt_lines
15729        } else {
15730            lines
15731        };
15732
15733        self.buffer.update(cx, |buffer, cx| {
15734            let snapshot = buffer.snapshot(cx);
15735            let mut excerpt_ids = selections
15736                .iter()
15737                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15738                .collect::<Vec<_>>();
15739            excerpt_ids.sort();
15740            excerpt_ids.dedup();
15741            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15742        })
15743    }
15744
15745    pub fn expand_excerpt(
15746        &mut self,
15747        excerpt: ExcerptId,
15748        direction: ExpandExcerptDirection,
15749        window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        let current_scroll_position = self.scroll_position(cx);
15753        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15754        let mut should_scroll_up = false;
15755
15756        if direction == ExpandExcerptDirection::Down {
15757            let multi_buffer = self.buffer.read(cx);
15758            let snapshot = multi_buffer.snapshot(cx);
15759            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15760                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15761                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15762            {
15763                let buffer_snapshot = buffer.read(cx).snapshot();
15764                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15765                let last_row = buffer_snapshot.max_point().row;
15766                let lines_below = last_row.saturating_sub(excerpt_end_row);
15767                should_scroll_up = lines_below >= lines_to_expand;
15768            }
15769        }
15770
15771        self.buffer.update(cx, |buffer, cx| {
15772            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15773        });
15774
15775        if should_scroll_up {
15776            let new_scroll_position =
15777                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15778            self.set_scroll_position(new_scroll_position, window, cx);
15779        }
15780    }
15781
15782    pub fn go_to_singleton_buffer_point(
15783        &mut self,
15784        point: Point,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        self.go_to_singleton_buffer_range(point..point, window, cx);
15789    }
15790
15791    pub fn go_to_singleton_buffer_range(
15792        &mut self,
15793        range: Range<Point>,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        let multibuffer = self.buffer().read(cx);
15798        let Some(buffer) = multibuffer.as_singleton() else {
15799            return;
15800        };
15801        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15802            return;
15803        };
15804        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15805            return;
15806        };
15807        self.change_selections(
15808            SelectionEffects::default().nav_history(true),
15809            window,
15810            cx,
15811            |s| s.select_anchor_ranges([start..end]),
15812        );
15813    }
15814
15815    pub fn go_to_diagnostic(
15816        &mut self,
15817        action: &GoToDiagnostic,
15818        window: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        if !self.diagnostics_enabled() {
15822            return;
15823        }
15824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15825        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15826    }
15827
15828    pub fn go_to_prev_diagnostic(
15829        &mut self,
15830        action: &GoToPreviousDiagnostic,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        if !self.diagnostics_enabled() {
15835            return;
15836        }
15837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15838        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15839    }
15840
15841    pub fn go_to_diagnostic_impl(
15842        &mut self,
15843        direction: Direction,
15844        severity: GoToDiagnosticSeverityFilter,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        let buffer = self.buffer.read(cx).snapshot(cx);
15849        let selection = self.selections.newest::<usize>(cx);
15850
15851        let mut active_group_id = None;
15852        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15853            && active_group.active_range.start.to_offset(&buffer) == selection.start
15854        {
15855            active_group_id = Some(active_group.group_id);
15856        }
15857
15858        fn filtered(
15859            snapshot: EditorSnapshot,
15860            severity: GoToDiagnosticSeverityFilter,
15861            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15862        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15863            diagnostics
15864                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15865                .filter(|entry| entry.range.start != entry.range.end)
15866                .filter(|entry| !entry.diagnostic.is_unnecessary)
15867                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15868        }
15869
15870        let snapshot = self.snapshot(window, cx);
15871        let before = filtered(
15872            snapshot.clone(),
15873            severity,
15874            buffer
15875                .diagnostics_in_range(0..selection.start)
15876                .filter(|entry| entry.range.start <= selection.start),
15877        );
15878        let after = filtered(
15879            snapshot,
15880            severity,
15881            buffer
15882                .diagnostics_in_range(selection.start..buffer.len())
15883                .filter(|entry| entry.range.start >= selection.start),
15884        );
15885
15886        let mut found: Option<DiagnosticEntry<usize>> = None;
15887        if direction == Direction::Prev {
15888            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15889            {
15890                for diagnostic in prev_diagnostics.into_iter().rev() {
15891                    if diagnostic.range.start != selection.start
15892                        || active_group_id
15893                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15894                    {
15895                        found = Some(diagnostic);
15896                        break 'outer;
15897                    }
15898                }
15899            }
15900        } else {
15901            for diagnostic in after.chain(before) {
15902                if diagnostic.range.start != selection.start
15903                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15904                {
15905                    found = Some(diagnostic);
15906                    break;
15907                }
15908            }
15909        }
15910        let Some(next_diagnostic) = found else {
15911            return;
15912        };
15913
15914        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15915        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15916            return;
15917        };
15918        self.change_selections(Default::default(), window, cx, |s| {
15919            s.select_ranges(vec![
15920                next_diagnostic.range.start..next_diagnostic.range.start,
15921            ])
15922        });
15923        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15924        self.refresh_edit_prediction(false, true, window, cx);
15925    }
15926
15927    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        let snapshot = self.snapshot(window, cx);
15930        let selection = self.selections.newest::<Point>(cx);
15931        self.go_to_hunk_before_or_after_position(
15932            &snapshot,
15933            selection.head(),
15934            Direction::Next,
15935            window,
15936            cx,
15937        );
15938    }
15939
15940    pub fn go_to_hunk_before_or_after_position(
15941        &mut self,
15942        snapshot: &EditorSnapshot,
15943        position: Point,
15944        direction: Direction,
15945        window: &mut Window,
15946        cx: &mut Context<Editor>,
15947    ) {
15948        let row = if direction == Direction::Next {
15949            self.hunk_after_position(snapshot, position)
15950                .map(|hunk| hunk.row_range.start)
15951        } else {
15952            self.hunk_before_position(snapshot, position)
15953        };
15954
15955        if let Some(row) = row {
15956            let destination = Point::new(row.0, 0);
15957            let autoscroll = Autoscroll::center();
15958
15959            self.unfold_ranges(&[destination..destination], false, false, cx);
15960            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15961                s.select_ranges([destination..destination]);
15962            });
15963        }
15964    }
15965
15966    fn hunk_after_position(
15967        &mut self,
15968        snapshot: &EditorSnapshot,
15969        position: Point,
15970    ) -> Option<MultiBufferDiffHunk> {
15971        snapshot
15972            .buffer_snapshot
15973            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15974            .find(|hunk| hunk.row_range.start.0 > position.row)
15975            .or_else(|| {
15976                snapshot
15977                    .buffer_snapshot
15978                    .diff_hunks_in_range(Point::zero()..position)
15979                    .find(|hunk| hunk.row_range.end.0 < position.row)
15980            })
15981    }
15982
15983    fn go_to_prev_hunk(
15984        &mut self,
15985        _: &GoToPreviousHunk,
15986        window: &mut Window,
15987        cx: &mut Context<Self>,
15988    ) {
15989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15990        let snapshot = self.snapshot(window, cx);
15991        let selection = self.selections.newest::<Point>(cx);
15992        self.go_to_hunk_before_or_after_position(
15993            &snapshot,
15994            selection.head(),
15995            Direction::Prev,
15996            window,
15997            cx,
15998        );
15999    }
16000
16001    fn hunk_before_position(
16002        &mut self,
16003        snapshot: &EditorSnapshot,
16004        position: Point,
16005    ) -> Option<MultiBufferRow> {
16006        snapshot
16007            .buffer_snapshot
16008            .diff_hunk_before(position)
16009            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16010    }
16011
16012    fn go_to_next_change(
16013        &mut self,
16014        _: &GoToNextChange,
16015        window: &mut Window,
16016        cx: &mut Context<Self>,
16017    ) {
16018        if let Some(selections) = self
16019            .change_list
16020            .next_change(1, Direction::Next)
16021            .map(|s| s.to_vec())
16022        {
16023            self.change_selections(Default::default(), window, cx, |s| {
16024                let map = s.display_map();
16025                s.select_display_ranges(selections.iter().map(|a| {
16026                    let point = a.to_display_point(&map);
16027                    point..point
16028                }))
16029            })
16030        }
16031    }
16032
16033    fn go_to_previous_change(
16034        &mut self,
16035        _: &GoToPreviousChange,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        if let Some(selections) = self
16040            .change_list
16041            .next_change(1, Direction::Prev)
16042            .map(|s| s.to_vec())
16043        {
16044            self.change_selections(Default::default(), window, cx, |s| {
16045                let map = s.display_map();
16046                s.select_display_ranges(selections.iter().map(|a| {
16047                    let point = a.to_display_point(&map);
16048                    point..point
16049                }))
16050            })
16051        }
16052    }
16053
16054    pub fn go_to_next_document_highlight(
16055        &mut self,
16056        _: &GoToNextDocumentHighlight,
16057        window: &mut Window,
16058        cx: &mut Context<Self>,
16059    ) {
16060        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16061    }
16062
16063    pub fn go_to_prev_document_highlight(
16064        &mut self,
16065        _: &GoToPreviousDocumentHighlight,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) {
16069        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16070    }
16071
16072    pub fn go_to_document_highlight_before_or_after_position(
16073        &mut self,
16074        direction: Direction,
16075        window: &mut Window,
16076        cx: &mut Context<Editor>,
16077    ) {
16078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16079        let snapshot = self.snapshot(window, cx);
16080        let buffer = &snapshot.buffer_snapshot;
16081        let position = self.selections.newest::<Point>(cx).head();
16082        let anchor_position = buffer.anchor_after(position);
16083
16084        // Get all document highlights (both read and write)
16085        let mut all_highlights = Vec::new();
16086
16087        if let Some((_, read_highlights)) = self
16088            .background_highlights
16089            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16090        {
16091            all_highlights.extend(read_highlights.iter());
16092        }
16093
16094        if let Some((_, write_highlights)) = self
16095            .background_highlights
16096            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16097        {
16098            all_highlights.extend(write_highlights.iter());
16099        }
16100
16101        if all_highlights.is_empty() {
16102            return;
16103        }
16104
16105        // Sort highlights by position
16106        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16107
16108        let target_highlight = match direction {
16109            Direction::Next => {
16110                // Find the first highlight after the current position
16111                all_highlights
16112                    .iter()
16113                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16114            }
16115            Direction::Prev => {
16116                // Find the last highlight before the current position
16117                all_highlights
16118                    .iter()
16119                    .rev()
16120                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16121            }
16122        };
16123
16124        if let Some(highlight) = target_highlight {
16125            let destination = highlight.start.to_point(buffer);
16126            let autoscroll = Autoscroll::center();
16127
16128            self.unfold_ranges(&[destination..destination], false, false, cx);
16129            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16130                s.select_ranges([destination..destination]);
16131            });
16132        }
16133    }
16134
16135    fn go_to_line<T: 'static>(
16136        &mut self,
16137        position: Anchor,
16138        highlight_color: Option<Hsla>,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        let snapshot = self.snapshot(window, cx).display_snapshot;
16143        let position = position.to_point(&snapshot.buffer_snapshot);
16144        let start = snapshot
16145            .buffer_snapshot
16146            .clip_point(Point::new(position.row, 0), Bias::Left);
16147        let end = start + Point::new(1, 0);
16148        let start = snapshot.buffer_snapshot.anchor_before(start);
16149        let end = snapshot.buffer_snapshot.anchor_before(end);
16150
16151        self.highlight_rows::<T>(
16152            start..end,
16153            highlight_color
16154                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16155            Default::default(),
16156            cx,
16157        );
16158
16159        if self.buffer.read(cx).is_singleton() {
16160            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16161        }
16162    }
16163
16164    pub fn go_to_definition(
16165        &mut self,
16166        _: &GoToDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        let definition =
16171            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16172        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16173        cx.spawn_in(window, async move |editor, cx| {
16174            if definition.await? == Navigated::Yes {
16175                return Ok(Navigated::Yes);
16176            }
16177            match fallback_strategy {
16178                GoToDefinitionFallback::None => Ok(Navigated::No),
16179                GoToDefinitionFallback::FindAllReferences => {
16180                    match editor.update_in(cx, |editor, window, cx| {
16181                        editor.find_all_references(&FindAllReferences, window, cx)
16182                    })? {
16183                        Some(references) => references.await,
16184                        None => Ok(Navigated::No),
16185                    }
16186                }
16187            }
16188        })
16189    }
16190
16191    pub fn go_to_declaration(
16192        &mut self,
16193        _: &GoToDeclaration,
16194        window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) -> Task<Result<Navigated>> {
16197        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16198    }
16199
16200    pub fn go_to_declaration_split(
16201        &mut self,
16202        _: &GoToDeclaration,
16203        window: &mut Window,
16204        cx: &mut Context<Self>,
16205    ) -> Task<Result<Navigated>> {
16206        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16207    }
16208
16209    pub fn go_to_implementation(
16210        &mut self,
16211        _: &GoToImplementation,
16212        window: &mut Window,
16213        cx: &mut Context<Self>,
16214    ) -> Task<Result<Navigated>> {
16215        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16216    }
16217
16218    pub fn go_to_implementation_split(
16219        &mut self,
16220        _: &GoToImplementationSplit,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) -> Task<Result<Navigated>> {
16224        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16225    }
16226
16227    pub fn go_to_type_definition(
16228        &mut self,
16229        _: &GoToTypeDefinition,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) -> Task<Result<Navigated>> {
16233        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16234    }
16235
16236    pub fn go_to_definition_split(
16237        &mut self,
16238        _: &GoToDefinitionSplit,
16239        window: &mut Window,
16240        cx: &mut Context<Self>,
16241    ) -> Task<Result<Navigated>> {
16242        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16243    }
16244
16245    pub fn go_to_type_definition_split(
16246        &mut self,
16247        _: &GoToTypeDefinitionSplit,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) -> Task<Result<Navigated>> {
16251        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16252    }
16253
16254    fn go_to_definition_of_kind(
16255        &mut self,
16256        kind: GotoDefinitionKind,
16257        split: bool,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Task<Result<Navigated>> {
16261        let Some(provider) = self.semantics_provider.clone() else {
16262            return Task::ready(Ok(Navigated::No));
16263        };
16264        let head = self.selections.newest::<usize>(cx).head();
16265        let buffer = self.buffer.read(cx);
16266        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16267            return Task::ready(Ok(Navigated::No));
16268        };
16269        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16270            return Task::ready(Ok(Navigated::No));
16271        };
16272
16273        cx.spawn_in(window, async move |editor, cx| {
16274            let Some(definitions) = definitions.await? else {
16275                return Ok(Navigated::No);
16276            };
16277            let navigated = editor
16278                .update_in(cx, |editor, window, cx| {
16279                    editor.navigate_to_hover_links(
16280                        Some(kind),
16281                        definitions
16282                            .into_iter()
16283                            .filter(|location| {
16284                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16285                            })
16286                            .map(HoverLink::Text)
16287                            .collect::<Vec<_>>(),
16288                        split,
16289                        window,
16290                        cx,
16291                    )
16292                })?
16293                .await?;
16294            anyhow::Ok(navigated)
16295        })
16296    }
16297
16298    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16299        let selection = self.selections.newest_anchor();
16300        let head = selection.head();
16301        let tail = selection.tail();
16302
16303        let Some((buffer, start_position)) =
16304            self.buffer.read(cx).text_anchor_for_position(head, cx)
16305        else {
16306            return;
16307        };
16308
16309        let end_position = if head != tail {
16310            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16311                return;
16312            };
16313            Some(pos)
16314        } else {
16315            None
16316        };
16317
16318        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16319            let url = if let Some(end_pos) = end_position {
16320                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16321            } else {
16322                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16323            };
16324
16325            if let Some(url) = url {
16326                editor.update(cx, |_, cx| {
16327                    cx.open_url(&url);
16328                })
16329            } else {
16330                Ok(())
16331            }
16332        });
16333
16334        url_finder.detach();
16335    }
16336
16337    pub fn open_selected_filename(
16338        &mut self,
16339        _: &OpenSelectedFilename,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) {
16343        let Some(workspace) = self.workspace() else {
16344            return;
16345        };
16346
16347        let position = self.selections.newest_anchor().head();
16348
16349        let Some((buffer, buffer_position)) =
16350            self.buffer.read(cx).text_anchor_for_position(position, cx)
16351        else {
16352            return;
16353        };
16354
16355        let project = self.project.clone();
16356
16357        cx.spawn_in(window, async move |_, cx| {
16358            let result = find_file(&buffer, project, buffer_position, cx).await;
16359
16360            if let Some((_, path)) = result {
16361                workspace
16362                    .update_in(cx, |workspace, window, cx| {
16363                        workspace.open_resolved_path(path, window, cx)
16364                    })?
16365                    .await?;
16366            }
16367            anyhow::Ok(())
16368        })
16369        .detach();
16370    }
16371
16372    pub(crate) fn navigate_to_hover_links(
16373        &mut self,
16374        kind: Option<GotoDefinitionKind>,
16375        definitions: Vec<HoverLink>,
16376        split: bool,
16377        window: &mut Window,
16378        cx: &mut Context<Editor>,
16379    ) -> Task<Result<Navigated>> {
16380        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16381        let mut first_url_or_file = None;
16382        let definitions: Vec<_> = definitions
16383            .into_iter()
16384            .filter_map(|def| match def {
16385                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16386                HoverLink::InlayHint(lsp_location, server_id) => {
16387                    let computation =
16388                        self.compute_target_location(lsp_location, server_id, window, cx);
16389                    Some(cx.background_spawn(computation))
16390                }
16391                HoverLink::Url(url) => {
16392                    first_url_or_file = Some(Either::Left(url));
16393                    None
16394                }
16395                HoverLink::File(path) => {
16396                    first_url_or_file = Some(Either::Right(path));
16397                    None
16398                }
16399            })
16400            .collect();
16401
16402        let workspace = self.workspace();
16403
16404        cx.spawn_in(window, async move |editor, cx| {
16405            let locations: Vec<Location> = future::join_all(definitions)
16406                .await
16407                .into_iter()
16408                .filter_map(|location| location.transpose())
16409                .collect::<Result<_>>()
16410                .context("location tasks")?;
16411            let mut locations = cx.update(|_, cx| {
16412                locations
16413                    .into_iter()
16414                    .map(|location| {
16415                        let buffer = location.buffer.read(cx);
16416                        (location.buffer, location.range.to_point(buffer))
16417                    })
16418                    .into_group_map()
16419            })?;
16420            let mut num_locations = 0;
16421            for ranges in locations.values_mut() {
16422                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16423                ranges.dedup();
16424                num_locations += ranges.len();
16425            }
16426
16427            if num_locations > 1 {
16428                let Some(workspace) = workspace else {
16429                    return Ok(Navigated::No);
16430                };
16431
16432                let tab_kind = match kind {
16433                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16434                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16435                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16436                    Some(GotoDefinitionKind::Type) => "Types",
16437                };
16438                let title = editor
16439                    .update_in(cx, |_, _, cx| {
16440                        let target = locations
16441                            .iter()
16442                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16443                            .map(|(buffer, location)| {
16444                                buffer
16445                                    .read(cx)
16446                                    .text_for_range(location.clone())
16447                                    .collect::<String>()
16448                            })
16449                            .filter(|text| !text.contains('\n'))
16450                            .unique()
16451                            .take(3)
16452                            .join(", ");
16453                        if target.is_empty() {
16454                            tab_kind.to_owned()
16455                        } else {
16456                            format!("{tab_kind} for {target}")
16457                        }
16458                    })
16459                    .context("buffer title")?;
16460
16461                let opened = workspace
16462                    .update_in(cx, |workspace, window, cx| {
16463                        Self::open_locations_in_multibuffer(
16464                            workspace,
16465                            locations,
16466                            title,
16467                            split,
16468                            MultibufferSelectionMode::First,
16469                            window,
16470                            cx,
16471                        )
16472                    })
16473                    .is_ok();
16474
16475                anyhow::Ok(Navigated::from_bool(opened))
16476            } else if num_locations == 0 {
16477                // If there is one url or file, open it directly
16478                match first_url_or_file {
16479                    Some(Either::Left(url)) => {
16480                        cx.update(|_, cx| cx.open_url(&url))?;
16481                        Ok(Navigated::Yes)
16482                    }
16483                    Some(Either::Right(path)) => {
16484                        let Some(workspace) = workspace else {
16485                            return Ok(Navigated::No);
16486                        };
16487
16488                        workspace
16489                            .update_in(cx, |workspace, window, cx| {
16490                                workspace.open_resolved_path(path, window, cx)
16491                            })?
16492                            .await?;
16493                        Ok(Navigated::Yes)
16494                    }
16495                    None => Ok(Navigated::No),
16496                }
16497            } else {
16498                let Some(workspace) = workspace else {
16499                    return Ok(Navigated::No);
16500                };
16501
16502                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16503                let target_range = target_ranges.first().unwrap().clone();
16504
16505                editor.update_in(cx, |editor, window, cx| {
16506                    let range = target_range.to_point(target_buffer.read(cx));
16507                    let range = editor.range_for_match(&range);
16508                    let range = collapse_multiline_range(range);
16509
16510                    if !split
16511                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16512                    {
16513                        editor.go_to_singleton_buffer_range(range, window, cx);
16514                    } else {
16515                        let pane = workspace.read(cx).active_pane().clone();
16516                        window.defer(cx, move |window, cx| {
16517                            let target_editor: Entity<Self> =
16518                                workspace.update(cx, |workspace, cx| {
16519                                    let pane = if split {
16520                                        workspace.adjacent_pane(window, cx)
16521                                    } else {
16522                                        workspace.active_pane().clone()
16523                                    };
16524
16525                                    workspace.open_project_item(
16526                                        pane,
16527                                        target_buffer.clone(),
16528                                        true,
16529                                        true,
16530                                        window,
16531                                        cx,
16532                                    )
16533                                });
16534                            target_editor.update(cx, |target_editor, cx| {
16535                                // When selecting a definition in a different buffer, disable the nav history
16536                                // to avoid creating a history entry at the previous cursor location.
16537                                pane.update(cx, |pane, _| pane.disable_history());
16538                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16539                                pane.update(cx, |pane, _| pane.enable_history());
16540                            });
16541                        });
16542                    }
16543                    Navigated::Yes
16544                })
16545            }
16546        })
16547    }
16548
16549    fn compute_target_location(
16550        &self,
16551        lsp_location: lsp::Location,
16552        server_id: LanguageServerId,
16553        window: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) -> Task<anyhow::Result<Option<Location>>> {
16556        let Some(project) = self.project.clone() else {
16557            return Task::ready(Ok(None));
16558        };
16559
16560        cx.spawn_in(window, async move |editor, cx| {
16561            let location_task = editor.update(cx, |_, cx| {
16562                project.update(cx, |project, cx| {
16563                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16564                })
16565            })?;
16566            let location = Some({
16567                let target_buffer_handle = location_task.await.context("open local buffer")?;
16568                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16569                    let target_start = target_buffer
16570                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16571                    let target_end = target_buffer
16572                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16573                    target_buffer.anchor_after(target_start)
16574                        ..target_buffer.anchor_before(target_end)
16575                })?;
16576                Location {
16577                    buffer: target_buffer_handle,
16578                    range,
16579                }
16580            });
16581            Ok(location)
16582        })
16583    }
16584
16585    pub fn find_all_references(
16586        &mut self,
16587        _: &FindAllReferences,
16588        window: &mut Window,
16589        cx: &mut Context<Self>,
16590    ) -> Option<Task<Result<Navigated>>> {
16591        let selection = self.selections.newest::<usize>(cx);
16592        let multi_buffer = self.buffer.read(cx);
16593        let head = selection.head();
16594
16595        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16596        let head_anchor = multi_buffer_snapshot.anchor_at(
16597            head,
16598            if head < selection.tail() {
16599                Bias::Right
16600            } else {
16601                Bias::Left
16602            },
16603        );
16604
16605        match self
16606            .find_all_references_task_sources
16607            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16608        {
16609            Ok(_) => {
16610                log::info!(
16611                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16612                );
16613                return None;
16614            }
16615            Err(i) => {
16616                self.find_all_references_task_sources.insert(i, head_anchor);
16617            }
16618        }
16619
16620        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16621        let workspace = self.workspace()?;
16622        let project = workspace.read(cx).project().clone();
16623        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16624        Some(cx.spawn_in(window, async move |editor, cx| {
16625            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16626                if let Ok(i) = editor
16627                    .find_all_references_task_sources
16628                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16629                {
16630                    editor.find_all_references_task_sources.remove(i);
16631                }
16632            });
16633
16634            let Some(locations) = references.await? else {
16635                return anyhow::Ok(Navigated::No);
16636            };
16637            let mut locations = cx.update(|_, cx| {
16638                locations
16639                    .into_iter()
16640                    .map(|location| {
16641                        let buffer = location.buffer.read(cx);
16642                        (location.buffer, location.range.to_point(buffer))
16643                    })
16644                    .into_group_map()
16645            })?;
16646            if locations.is_empty() {
16647                return anyhow::Ok(Navigated::No);
16648            }
16649            for ranges in locations.values_mut() {
16650                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16651                ranges.dedup();
16652            }
16653
16654            workspace.update_in(cx, |workspace, window, cx| {
16655                let target = locations
16656                    .iter()
16657                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16658                    .map(|(buffer, location)| {
16659                        buffer
16660                            .read(cx)
16661                            .text_for_range(location.clone())
16662                            .collect::<String>()
16663                    })
16664                    .filter(|text| !text.contains('\n'))
16665                    .unique()
16666                    .take(3)
16667                    .join(", ");
16668                let title = if target.is_empty() {
16669                    "References".to_owned()
16670                } else {
16671                    format!("References to {target}")
16672                };
16673                Self::open_locations_in_multibuffer(
16674                    workspace,
16675                    locations,
16676                    title,
16677                    false,
16678                    MultibufferSelectionMode::First,
16679                    window,
16680                    cx,
16681                );
16682                Navigated::Yes
16683            })
16684        }))
16685    }
16686
16687    /// Opens a multibuffer with the given project locations in it
16688    pub fn open_locations_in_multibuffer(
16689        workspace: &mut Workspace,
16690        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16691        title: String,
16692        split: bool,
16693        multibuffer_selection_mode: MultibufferSelectionMode,
16694        window: &mut Window,
16695        cx: &mut Context<Workspace>,
16696    ) {
16697        if locations.is_empty() {
16698            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16699            return;
16700        }
16701
16702        let capability = workspace.project().read(cx).capability();
16703        let mut ranges = <Vec<Range<Anchor>>>::new();
16704
16705        // a key to find existing multibuffer editors with the same set of locations
16706        // to prevent us from opening more and more multibuffer tabs for searches and the like
16707        let mut key = (title.clone(), vec![]);
16708        let excerpt_buffer = cx.new(|cx| {
16709            let key = &mut key.1;
16710            let mut multibuffer = MultiBuffer::new(capability);
16711            for (buffer, mut ranges_for_buffer) in locations {
16712                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16713                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16714                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16715                    PathKey::for_buffer(&buffer, cx),
16716                    buffer.clone(),
16717                    ranges_for_buffer,
16718                    multibuffer_context_lines(cx),
16719                    cx,
16720                );
16721                ranges.extend(new_ranges)
16722            }
16723
16724            multibuffer.with_title(title)
16725        });
16726        let existing = workspace.active_pane().update(cx, |pane, cx| {
16727            pane.items()
16728                .filter_map(|item| item.downcast::<Editor>())
16729                .find(|editor| {
16730                    editor
16731                        .read(cx)
16732                        .lookup_key
16733                        .as_ref()
16734                        .and_then(|it| {
16735                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16736                        })
16737                        .is_some_and(|it| *it == key)
16738                })
16739        });
16740        let editor = existing.unwrap_or_else(|| {
16741            cx.new(|cx| {
16742                let mut editor = Editor::for_multibuffer(
16743                    excerpt_buffer,
16744                    Some(workspace.project().clone()),
16745                    window,
16746                    cx,
16747                );
16748                editor.lookup_key = Some(Box::new(key));
16749                editor
16750            })
16751        });
16752        editor.update(cx, |editor, cx| {
16753            match multibuffer_selection_mode {
16754                MultibufferSelectionMode::First => {
16755                    if let Some(first_range) = ranges.first() {
16756                        editor.change_selections(
16757                            SelectionEffects::no_scroll(),
16758                            window,
16759                            cx,
16760                            |selections| {
16761                                selections.clear_disjoint();
16762                                selections
16763                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16764                            },
16765                        );
16766                    }
16767                    editor.highlight_background::<Self>(
16768                        &ranges,
16769                        |theme| theme.colors().editor_highlighted_line_background,
16770                        cx,
16771                    );
16772                }
16773                MultibufferSelectionMode::All => {
16774                    editor.change_selections(
16775                        SelectionEffects::no_scroll(),
16776                        window,
16777                        cx,
16778                        |selections| {
16779                            selections.clear_disjoint();
16780                            selections.select_anchor_ranges(ranges);
16781                        },
16782                    );
16783                }
16784            }
16785            editor.register_buffers_with_language_servers(cx);
16786        });
16787
16788        let item = Box::new(editor);
16789        let item_id = item.item_id();
16790
16791        if split {
16792            workspace.split_item(SplitDirection::Right, item, window, cx);
16793        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16794            let (preview_item_id, preview_item_idx) =
16795                workspace.active_pane().read_with(cx, |pane, _| {
16796                    (pane.preview_item_id(), pane.preview_item_idx())
16797                });
16798
16799            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16800
16801            if let Some(preview_item_id) = preview_item_id {
16802                workspace.active_pane().update(cx, |pane, cx| {
16803                    pane.remove_item(preview_item_id, false, false, window, cx);
16804                });
16805            }
16806        } else {
16807            workspace.add_item_to_active_pane(item, None, true, window, cx);
16808        }
16809        workspace.active_pane().update(cx, |pane, cx| {
16810            pane.set_preview_item_id(Some(item_id), cx);
16811        });
16812    }
16813
16814    pub fn rename(
16815        &mut self,
16816        _: &Rename,
16817        window: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) -> Option<Task<Result<()>>> {
16820        use language::ToOffset as _;
16821
16822        let provider = self.semantics_provider.clone()?;
16823        let selection = self.selections.newest_anchor().clone();
16824        let (cursor_buffer, cursor_buffer_position) = self
16825            .buffer
16826            .read(cx)
16827            .text_anchor_for_position(selection.head(), cx)?;
16828        let (tail_buffer, cursor_buffer_position_end) = self
16829            .buffer
16830            .read(cx)
16831            .text_anchor_for_position(selection.tail(), cx)?;
16832        if tail_buffer != cursor_buffer {
16833            return None;
16834        }
16835
16836        let snapshot = cursor_buffer.read(cx).snapshot();
16837        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16838        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16839        let prepare_rename = provider
16840            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16841            .unwrap_or_else(|| Task::ready(Ok(None)));
16842        drop(snapshot);
16843
16844        Some(cx.spawn_in(window, async move |this, cx| {
16845            let rename_range = if let Some(range) = prepare_rename.await? {
16846                Some(range)
16847            } else {
16848                this.update(cx, |this, cx| {
16849                    let buffer = this.buffer.read(cx).snapshot(cx);
16850                    let mut buffer_highlights = this
16851                        .document_highlights_for_position(selection.head(), &buffer)
16852                        .filter(|highlight| {
16853                            highlight.start.excerpt_id == selection.head().excerpt_id
16854                                && highlight.end.excerpt_id == selection.head().excerpt_id
16855                        });
16856                    buffer_highlights
16857                        .next()
16858                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16859                })?
16860            };
16861            if let Some(rename_range) = rename_range {
16862                this.update_in(cx, |this, window, cx| {
16863                    let snapshot = cursor_buffer.read(cx).snapshot();
16864                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16865                    let cursor_offset_in_rename_range =
16866                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16867                    let cursor_offset_in_rename_range_end =
16868                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16869
16870                    this.take_rename(false, window, cx);
16871                    let buffer = this.buffer.read(cx).read(cx);
16872                    let cursor_offset = selection.head().to_offset(&buffer);
16873                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16874                    let rename_end = rename_start + rename_buffer_range.len();
16875                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16876                    let mut old_highlight_id = None;
16877                    let old_name: Arc<str> = buffer
16878                        .chunks(rename_start..rename_end, true)
16879                        .map(|chunk| {
16880                            if old_highlight_id.is_none() {
16881                                old_highlight_id = chunk.syntax_highlight_id;
16882                            }
16883                            chunk.text
16884                        })
16885                        .collect::<String>()
16886                        .into();
16887
16888                    drop(buffer);
16889
16890                    // Position the selection in the rename editor so that it matches the current selection.
16891                    this.show_local_selections = false;
16892                    let rename_editor = cx.new(|cx| {
16893                        let mut editor = Editor::single_line(window, cx);
16894                        editor.buffer.update(cx, |buffer, cx| {
16895                            buffer.edit([(0..0, old_name.clone())], None, cx)
16896                        });
16897                        let rename_selection_range = match cursor_offset_in_rename_range
16898                            .cmp(&cursor_offset_in_rename_range_end)
16899                        {
16900                            Ordering::Equal => {
16901                                editor.select_all(&SelectAll, window, cx);
16902                                return editor;
16903                            }
16904                            Ordering::Less => {
16905                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16906                            }
16907                            Ordering::Greater => {
16908                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16909                            }
16910                        };
16911                        if rename_selection_range.end > old_name.len() {
16912                            editor.select_all(&SelectAll, window, cx);
16913                        } else {
16914                            editor.change_selections(Default::default(), window, cx, |s| {
16915                                s.select_ranges([rename_selection_range]);
16916                            });
16917                        }
16918                        editor
16919                    });
16920                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16921                        if e == &EditorEvent::Focused {
16922                            cx.emit(EditorEvent::FocusedIn)
16923                        }
16924                    })
16925                    .detach();
16926
16927                    let write_highlights =
16928                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16929                    let read_highlights =
16930                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16931                    let ranges = write_highlights
16932                        .iter()
16933                        .flat_map(|(_, ranges)| ranges.iter())
16934                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16935                        .cloned()
16936                        .collect();
16937
16938                    this.highlight_text::<Rename>(
16939                        ranges,
16940                        HighlightStyle {
16941                            fade_out: Some(0.6),
16942                            ..Default::default()
16943                        },
16944                        cx,
16945                    );
16946                    let rename_focus_handle = rename_editor.focus_handle(cx);
16947                    window.focus(&rename_focus_handle);
16948                    let block_id = this.insert_blocks(
16949                        [BlockProperties {
16950                            style: BlockStyle::Flex,
16951                            placement: BlockPlacement::Below(range.start),
16952                            height: Some(1),
16953                            render: Arc::new({
16954                                let rename_editor = rename_editor.clone();
16955                                move |cx: &mut BlockContext| {
16956                                    let mut text_style = cx.editor_style.text.clone();
16957                                    if let Some(highlight_style) = old_highlight_id
16958                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16959                                    {
16960                                        text_style = text_style.highlight(highlight_style);
16961                                    }
16962                                    div()
16963                                        .block_mouse_except_scroll()
16964                                        .pl(cx.anchor_x)
16965                                        .child(EditorElement::new(
16966                                            &rename_editor,
16967                                            EditorStyle {
16968                                                background: cx.theme().system().transparent,
16969                                                local_player: cx.editor_style.local_player,
16970                                                text: text_style,
16971                                                scrollbar_width: cx.editor_style.scrollbar_width,
16972                                                syntax: cx.editor_style.syntax.clone(),
16973                                                status: cx.editor_style.status.clone(),
16974                                                inlay_hints_style: HighlightStyle {
16975                                                    font_weight: Some(FontWeight::BOLD),
16976                                                    ..make_inlay_hints_style(cx.app)
16977                                                },
16978                                                edit_prediction_styles: make_suggestion_styles(
16979                                                    cx.app,
16980                                                ),
16981                                                ..EditorStyle::default()
16982                                            },
16983                                        ))
16984                                        .into_any_element()
16985                                }
16986                            }),
16987                            priority: 0,
16988                        }],
16989                        Some(Autoscroll::fit()),
16990                        cx,
16991                    )[0];
16992                    this.pending_rename = Some(RenameState {
16993                        range,
16994                        old_name,
16995                        editor: rename_editor,
16996                        block_id,
16997                    });
16998                })?;
16999            }
17000
17001            Ok(())
17002        }))
17003    }
17004
17005    pub fn confirm_rename(
17006        &mut self,
17007        _: &ConfirmRename,
17008        window: &mut Window,
17009        cx: &mut Context<Self>,
17010    ) -> Option<Task<Result<()>>> {
17011        let rename = self.take_rename(false, window, cx)?;
17012        let workspace = self.workspace()?.downgrade();
17013        let (buffer, start) = self
17014            .buffer
17015            .read(cx)
17016            .text_anchor_for_position(rename.range.start, cx)?;
17017        let (end_buffer, _) = self
17018            .buffer
17019            .read(cx)
17020            .text_anchor_for_position(rename.range.end, cx)?;
17021        if buffer != end_buffer {
17022            return None;
17023        }
17024
17025        let old_name = rename.old_name;
17026        let new_name = rename.editor.read(cx).text(cx);
17027
17028        let rename = self.semantics_provider.as_ref()?.perform_rename(
17029            &buffer,
17030            start,
17031            new_name.clone(),
17032            cx,
17033        )?;
17034
17035        Some(cx.spawn_in(window, async move |editor, cx| {
17036            let project_transaction = rename.await?;
17037            Self::open_project_transaction(
17038                &editor,
17039                workspace,
17040                project_transaction,
17041                format!("Rename: {}{}", old_name, new_name),
17042                cx,
17043            )
17044            .await?;
17045
17046            editor.update(cx, |editor, cx| {
17047                editor.refresh_document_highlights(cx);
17048            })?;
17049            Ok(())
17050        }))
17051    }
17052
17053    fn take_rename(
17054        &mut self,
17055        moving_cursor: bool,
17056        window: &mut Window,
17057        cx: &mut Context<Self>,
17058    ) -> Option<RenameState> {
17059        let rename = self.pending_rename.take()?;
17060        if rename.editor.focus_handle(cx).is_focused(window) {
17061            window.focus(&self.focus_handle);
17062        }
17063
17064        self.remove_blocks(
17065            [rename.block_id].into_iter().collect(),
17066            Some(Autoscroll::fit()),
17067            cx,
17068        );
17069        self.clear_highlights::<Rename>(cx);
17070        self.show_local_selections = true;
17071
17072        if moving_cursor {
17073            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17074                editor.selections.newest::<usize>(cx).head()
17075            });
17076
17077            // Update the selection to match the position of the selection inside
17078            // the rename editor.
17079            let snapshot = self.buffer.read(cx).read(cx);
17080            let rename_range = rename.range.to_offset(&snapshot);
17081            let cursor_in_editor = snapshot
17082                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17083                .min(rename_range.end);
17084            drop(snapshot);
17085
17086            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17087                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17088            });
17089        } else {
17090            self.refresh_document_highlights(cx);
17091        }
17092
17093        Some(rename)
17094    }
17095
17096    pub fn pending_rename(&self) -> Option<&RenameState> {
17097        self.pending_rename.as_ref()
17098    }
17099
17100    fn format(
17101        &mut self,
17102        _: &Format,
17103        window: &mut Window,
17104        cx: &mut Context<Self>,
17105    ) -> Option<Task<Result<()>>> {
17106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17107
17108        let project = match &self.project {
17109            Some(project) => project.clone(),
17110            None => return None,
17111        };
17112
17113        Some(self.perform_format(
17114            project,
17115            FormatTrigger::Manual,
17116            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17117            window,
17118            cx,
17119        ))
17120    }
17121
17122    fn format_selections(
17123        &mut self,
17124        _: &FormatSelections,
17125        window: &mut Window,
17126        cx: &mut Context<Self>,
17127    ) -> Option<Task<Result<()>>> {
17128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17129
17130        let project = match &self.project {
17131            Some(project) => project.clone(),
17132            None => return None,
17133        };
17134
17135        let ranges = self
17136            .selections
17137            .all_adjusted(cx)
17138            .into_iter()
17139            .map(|selection| selection.range())
17140            .collect_vec();
17141
17142        Some(self.perform_format(
17143            project,
17144            FormatTrigger::Manual,
17145            FormatTarget::Ranges(ranges),
17146            window,
17147            cx,
17148        ))
17149    }
17150
17151    fn perform_format(
17152        &mut self,
17153        project: Entity<Project>,
17154        trigger: FormatTrigger,
17155        target: FormatTarget,
17156        window: &mut Window,
17157        cx: &mut Context<Self>,
17158    ) -> Task<Result<()>> {
17159        let buffer = self.buffer.clone();
17160        let (buffers, target) = match target {
17161            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17162            FormatTarget::Ranges(selection_ranges) => {
17163                let multi_buffer = buffer.read(cx);
17164                let snapshot = multi_buffer.read(cx);
17165                let mut buffers = HashSet::default();
17166                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17167                    BTreeMap::new();
17168                for selection_range in selection_ranges {
17169                    for (buffer, buffer_range, _) in
17170                        snapshot.range_to_buffer_ranges(selection_range)
17171                    {
17172                        let buffer_id = buffer.remote_id();
17173                        let start = buffer.anchor_before(buffer_range.start);
17174                        let end = buffer.anchor_after(buffer_range.end);
17175                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17176                        buffer_id_to_ranges
17177                            .entry(buffer_id)
17178                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17179                            .or_insert_with(|| vec![start..end]);
17180                    }
17181                }
17182                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17183            }
17184        };
17185
17186        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17187        let selections_prev = transaction_id_prev
17188            .and_then(|transaction_id_prev| {
17189                // default to selections as they were after the last edit, if we have them,
17190                // instead of how they are now.
17191                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17192                // will take you back to where you made the last edit, instead of staying where you scrolled
17193                self.selection_history
17194                    .transaction(transaction_id_prev)
17195                    .map(|t| t.0.clone())
17196            })
17197            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17198
17199        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17200        let format = project.update(cx, |project, cx| {
17201            project.format(buffers, target, true, trigger, cx)
17202        });
17203
17204        cx.spawn_in(window, async move |editor, cx| {
17205            let transaction = futures::select_biased! {
17206                transaction = format.log_err().fuse() => transaction,
17207                () = timeout => {
17208                    log::warn!("timed out waiting for formatting");
17209                    None
17210                }
17211            };
17212
17213            buffer
17214                .update(cx, |buffer, cx| {
17215                    if let Some(transaction) = transaction
17216                        && !buffer.is_singleton()
17217                    {
17218                        buffer.push_transaction(&transaction.0, cx);
17219                    }
17220                    cx.notify();
17221                })
17222                .ok();
17223
17224            if let Some(transaction_id_now) =
17225                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17226            {
17227                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17228                if has_new_transaction {
17229                    _ = editor.update(cx, |editor, _| {
17230                        editor
17231                            .selection_history
17232                            .insert_transaction(transaction_id_now, selections_prev);
17233                    });
17234                }
17235            }
17236
17237            Ok(())
17238        })
17239    }
17240
17241    fn organize_imports(
17242        &mut self,
17243        _: &OrganizeImports,
17244        window: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) -> Option<Task<Result<()>>> {
17247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17248        let project = match &self.project {
17249            Some(project) => project.clone(),
17250            None => return None,
17251        };
17252        Some(self.perform_code_action_kind(
17253            project,
17254            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17255            window,
17256            cx,
17257        ))
17258    }
17259
17260    fn perform_code_action_kind(
17261        &mut self,
17262        project: Entity<Project>,
17263        kind: CodeActionKind,
17264        window: &mut Window,
17265        cx: &mut Context<Self>,
17266    ) -> Task<Result<()>> {
17267        let buffer = self.buffer.clone();
17268        let buffers = buffer.read(cx).all_buffers();
17269        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17270        let apply_action = project.update(cx, |project, cx| {
17271            project.apply_code_action_kind(buffers, kind, true, cx)
17272        });
17273        cx.spawn_in(window, async move |_, cx| {
17274            let transaction = futures::select_biased! {
17275                () = timeout => {
17276                    log::warn!("timed out waiting for executing code action");
17277                    None
17278                }
17279                transaction = apply_action.log_err().fuse() => transaction,
17280            };
17281            buffer
17282                .update(cx, |buffer, cx| {
17283                    // check if we need this
17284                    if let Some(transaction) = transaction
17285                        && !buffer.is_singleton()
17286                    {
17287                        buffer.push_transaction(&transaction.0, cx);
17288                    }
17289                    cx.notify();
17290                })
17291                .ok();
17292            Ok(())
17293        })
17294    }
17295
17296    pub fn restart_language_server(
17297        &mut self,
17298        _: &RestartLanguageServer,
17299        _: &mut Window,
17300        cx: &mut Context<Self>,
17301    ) {
17302        if let Some(project) = self.project.clone() {
17303            self.buffer.update(cx, |multi_buffer, cx| {
17304                project.update(cx, |project, cx| {
17305                    project.restart_language_servers_for_buffers(
17306                        multi_buffer.all_buffers().into_iter().collect(),
17307                        HashSet::default(),
17308                        cx,
17309                    );
17310                });
17311            })
17312        }
17313    }
17314
17315    pub fn stop_language_server(
17316        &mut self,
17317        _: &StopLanguageServer,
17318        _: &mut Window,
17319        cx: &mut Context<Self>,
17320    ) {
17321        if let Some(project) = self.project.clone() {
17322            self.buffer.update(cx, |multi_buffer, cx| {
17323                project.update(cx, |project, cx| {
17324                    project.stop_language_servers_for_buffers(
17325                        multi_buffer.all_buffers().into_iter().collect(),
17326                        HashSet::default(),
17327                        cx,
17328                    );
17329                    cx.emit(project::Event::RefreshInlayHints);
17330                });
17331            });
17332        }
17333    }
17334
17335    fn cancel_language_server_work(
17336        workspace: &mut Workspace,
17337        _: &actions::CancelLanguageServerWork,
17338        _: &mut Window,
17339        cx: &mut Context<Workspace>,
17340    ) {
17341        let project = workspace.project();
17342        let buffers = workspace
17343            .active_item(cx)
17344            .and_then(|item| item.act_as::<Editor>(cx))
17345            .map_or(HashSet::default(), |editor| {
17346                editor.read(cx).buffer.read(cx).all_buffers()
17347            });
17348        project.update(cx, |project, cx| {
17349            project.cancel_language_server_work_for_buffers(buffers, cx);
17350        });
17351    }
17352
17353    fn show_character_palette(
17354        &mut self,
17355        _: &ShowCharacterPalette,
17356        window: &mut Window,
17357        _: &mut Context<Self>,
17358    ) {
17359        window.show_character_palette();
17360    }
17361
17362    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17363        if !self.diagnostics_enabled() {
17364            return;
17365        }
17366
17367        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17368            let buffer = self.buffer.read(cx).snapshot(cx);
17369            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17370            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17371            let is_valid = buffer
17372                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17373                .any(|entry| {
17374                    entry.diagnostic.is_primary
17375                        && !entry.range.is_empty()
17376                        && entry.range.start == primary_range_start
17377                        && entry.diagnostic.message == active_diagnostics.active_message
17378                });
17379
17380            if !is_valid {
17381                self.dismiss_diagnostics(cx);
17382            }
17383        }
17384    }
17385
17386    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17387        match &self.active_diagnostics {
17388            ActiveDiagnostic::Group(group) => Some(group),
17389            _ => None,
17390        }
17391    }
17392
17393    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17394        if !self.diagnostics_enabled() {
17395            return;
17396        }
17397        self.dismiss_diagnostics(cx);
17398        self.active_diagnostics = ActiveDiagnostic::All;
17399    }
17400
17401    fn activate_diagnostics(
17402        &mut self,
17403        buffer_id: BufferId,
17404        diagnostic: DiagnosticEntry<usize>,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17409            return;
17410        }
17411        self.dismiss_diagnostics(cx);
17412        let snapshot = self.snapshot(window, cx);
17413        let buffer = self.buffer.read(cx).snapshot(cx);
17414        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17415            return;
17416        };
17417
17418        let diagnostic_group = buffer
17419            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17420            .collect::<Vec<_>>();
17421
17422        let blocks =
17423            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17424
17425        let blocks = self.display_map.update(cx, |display_map, cx| {
17426            display_map.insert_blocks(blocks, cx).into_iter().collect()
17427        });
17428        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17429            active_range: buffer.anchor_before(diagnostic.range.start)
17430                ..buffer.anchor_after(diagnostic.range.end),
17431            active_message: diagnostic.diagnostic.message.clone(),
17432            group_id: diagnostic.diagnostic.group_id,
17433            blocks,
17434        });
17435        cx.notify();
17436    }
17437
17438    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17439        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17440            return;
17441        };
17442
17443        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17444        if let ActiveDiagnostic::Group(group) = prev {
17445            self.display_map.update(cx, |display_map, cx| {
17446                display_map.remove_blocks(group.blocks, cx);
17447            });
17448            cx.notify();
17449        }
17450    }
17451
17452    /// Disable inline diagnostics rendering for this editor.
17453    pub fn disable_inline_diagnostics(&mut self) {
17454        self.inline_diagnostics_enabled = false;
17455        self.inline_diagnostics_update = Task::ready(());
17456        self.inline_diagnostics.clear();
17457    }
17458
17459    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17460        self.diagnostics_enabled = false;
17461        self.dismiss_diagnostics(cx);
17462        self.inline_diagnostics_update = Task::ready(());
17463        self.inline_diagnostics.clear();
17464    }
17465
17466    pub fn disable_word_completions(&mut self) {
17467        self.word_completions_enabled = false;
17468    }
17469
17470    pub fn diagnostics_enabled(&self) -> bool {
17471        self.diagnostics_enabled && self.mode.is_full()
17472    }
17473
17474    pub fn inline_diagnostics_enabled(&self) -> bool {
17475        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17476    }
17477
17478    pub fn show_inline_diagnostics(&self) -> bool {
17479        self.show_inline_diagnostics
17480    }
17481
17482    pub fn toggle_inline_diagnostics(
17483        &mut self,
17484        _: &ToggleInlineDiagnostics,
17485        window: &mut Window,
17486        cx: &mut Context<Editor>,
17487    ) {
17488        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17489        self.refresh_inline_diagnostics(false, window, cx);
17490    }
17491
17492    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17493        self.diagnostics_max_severity = severity;
17494        self.display_map.update(cx, |display_map, _| {
17495            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17496        });
17497    }
17498
17499    pub fn toggle_diagnostics(
17500        &mut self,
17501        _: &ToggleDiagnostics,
17502        window: &mut Window,
17503        cx: &mut Context<Editor>,
17504    ) {
17505        if !self.diagnostics_enabled() {
17506            return;
17507        }
17508
17509        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17510            EditorSettings::get_global(cx)
17511                .diagnostics_max_severity
17512                .filter(|severity| severity != &DiagnosticSeverity::Off)
17513                .unwrap_or(DiagnosticSeverity::Hint)
17514        } else {
17515            DiagnosticSeverity::Off
17516        };
17517        self.set_max_diagnostics_severity(new_severity, cx);
17518        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17519            self.active_diagnostics = ActiveDiagnostic::None;
17520            self.inline_diagnostics_update = Task::ready(());
17521            self.inline_diagnostics.clear();
17522        } else {
17523            self.refresh_inline_diagnostics(false, window, cx);
17524        }
17525
17526        cx.notify();
17527    }
17528
17529    pub fn toggle_minimap(
17530        &mut self,
17531        _: &ToggleMinimap,
17532        window: &mut Window,
17533        cx: &mut Context<Editor>,
17534    ) {
17535        if self.supports_minimap(cx) {
17536            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17537        }
17538    }
17539
17540    fn refresh_inline_diagnostics(
17541        &mut self,
17542        debounce: bool,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        let max_severity = ProjectSettings::get_global(cx)
17547            .diagnostics
17548            .inline
17549            .max_severity
17550            .unwrap_or(self.diagnostics_max_severity);
17551
17552        if !self.inline_diagnostics_enabled()
17553            || !self.show_inline_diagnostics
17554            || max_severity == DiagnosticSeverity::Off
17555        {
17556            self.inline_diagnostics_update = Task::ready(());
17557            self.inline_diagnostics.clear();
17558            return;
17559        }
17560
17561        let debounce_ms = ProjectSettings::get_global(cx)
17562            .diagnostics
17563            .inline
17564            .update_debounce_ms;
17565        let debounce = if debounce && debounce_ms > 0 {
17566            Some(Duration::from_millis(debounce_ms))
17567        } else {
17568            None
17569        };
17570        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17571            if let Some(debounce) = debounce {
17572                cx.background_executor().timer(debounce).await;
17573            }
17574            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17575                editor
17576                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17577                    .ok()
17578            }) else {
17579                return;
17580            };
17581
17582            let new_inline_diagnostics = cx
17583                .background_spawn(async move {
17584                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17585                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17586                        let message = diagnostic_entry
17587                            .diagnostic
17588                            .message
17589                            .split_once('\n')
17590                            .map(|(line, _)| line)
17591                            .map(SharedString::new)
17592                            .unwrap_or_else(|| {
17593                                SharedString::from(diagnostic_entry.diagnostic.message)
17594                            });
17595                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17596                        let (Ok(i) | Err(i)) = inline_diagnostics
17597                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17598                        inline_diagnostics.insert(
17599                            i,
17600                            (
17601                                start_anchor,
17602                                InlineDiagnostic {
17603                                    message,
17604                                    group_id: diagnostic_entry.diagnostic.group_id,
17605                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17606                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17607                                    severity: diagnostic_entry.diagnostic.severity,
17608                                },
17609                            ),
17610                        );
17611                    }
17612                    inline_diagnostics
17613                })
17614                .await;
17615
17616            editor
17617                .update(cx, |editor, cx| {
17618                    editor.inline_diagnostics = new_inline_diagnostics;
17619                    cx.notify();
17620                })
17621                .ok();
17622        });
17623    }
17624
17625    fn pull_diagnostics(
17626        &mut self,
17627        buffer_id: Option<BufferId>,
17628        window: &Window,
17629        cx: &mut Context<Self>,
17630    ) -> Option<()> {
17631        if !self.mode().is_full() {
17632            return None;
17633        }
17634        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17635            .diagnostics
17636            .lsp_pull_diagnostics;
17637        if !pull_diagnostics_settings.enabled {
17638            return None;
17639        }
17640        let project = self.project()?.downgrade();
17641        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17642        let mut buffers = self.buffer.read(cx).all_buffers();
17643        if let Some(buffer_id) = buffer_id {
17644            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17645        }
17646
17647        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17648            cx.background_executor().timer(debounce).await;
17649
17650            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17651                buffers
17652                    .into_iter()
17653                    .filter_map(|buffer| {
17654                        project
17655                            .update(cx, |project, cx| {
17656                                project.lsp_store().update(cx, |lsp_store, cx| {
17657                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17658                                })
17659                            })
17660                            .ok()
17661                    })
17662                    .collect::<FuturesUnordered<_>>()
17663            }) else {
17664                return;
17665            };
17666
17667            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17668                match pull_task {
17669                    Ok(()) => {
17670                        if editor
17671                            .update_in(cx, |editor, window, cx| {
17672                                editor.update_diagnostics_state(window, cx);
17673                            })
17674                            .is_err()
17675                        {
17676                            return;
17677                        }
17678                    }
17679                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17680                }
17681            }
17682        });
17683
17684        Some(())
17685    }
17686
17687    pub fn set_selections_from_remote(
17688        &mut self,
17689        selections: Vec<Selection<Anchor>>,
17690        pending_selection: Option<Selection<Anchor>>,
17691        window: &mut Window,
17692        cx: &mut Context<Self>,
17693    ) {
17694        let old_cursor_position = self.selections.newest_anchor().head();
17695        self.selections.change_with(cx, |s| {
17696            s.select_anchors(selections);
17697            if let Some(pending_selection) = pending_selection {
17698                s.set_pending(pending_selection, SelectMode::Character);
17699            } else {
17700                s.clear_pending();
17701            }
17702        });
17703        self.selections_did_change(
17704            false,
17705            &old_cursor_position,
17706            SelectionEffects::default(),
17707            window,
17708            cx,
17709        );
17710    }
17711
17712    pub fn transact(
17713        &mut self,
17714        window: &mut Window,
17715        cx: &mut Context<Self>,
17716        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17717    ) -> Option<TransactionId> {
17718        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17719            this.start_transaction_at(Instant::now(), window, cx);
17720            update(this, window, cx);
17721            this.end_transaction_at(Instant::now(), cx)
17722        })
17723    }
17724
17725    pub fn start_transaction_at(
17726        &mut self,
17727        now: Instant,
17728        window: &mut Window,
17729        cx: &mut Context<Self>,
17730    ) -> Option<TransactionId> {
17731        self.end_selection(window, cx);
17732        if let Some(tx_id) = self
17733            .buffer
17734            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17735        {
17736            self.selection_history
17737                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17738            cx.emit(EditorEvent::TransactionBegun {
17739                transaction_id: tx_id,
17740            });
17741            Some(tx_id)
17742        } else {
17743            None
17744        }
17745    }
17746
17747    pub fn end_transaction_at(
17748        &mut self,
17749        now: Instant,
17750        cx: &mut Context<Self>,
17751    ) -> Option<TransactionId> {
17752        if let Some(transaction_id) = self
17753            .buffer
17754            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17755        {
17756            if let Some((_, end_selections)) =
17757                self.selection_history.transaction_mut(transaction_id)
17758            {
17759                *end_selections = Some(self.selections.disjoint_anchors_arc());
17760            } else {
17761                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17762            }
17763
17764            cx.emit(EditorEvent::Edited { transaction_id });
17765            Some(transaction_id)
17766        } else {
17767            None
17768        }
17769    }
17770
17771    pub fn modify_transaction_selection_history(
17772        &mut self,
17773        transaction_id: TransactionId,
17774        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17775    ) -> bool {
17776        self.selection_history
17777            .transaction_mut(transaction_id)
17778            .map(modify)
17779            .is_some()
17780    }
17781
17782    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17783        if self.selection_mark_mode {
17784            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17785                s.move_with(|_, sel| {
17786                    sel.collapse_to(sel.head(), SelectionGoal::None);
17787                });
17788            })
17789        }
17790        self.selection_mark_mode = true;
17791        cx.notify();
17792    }
17793
17794    pub fn swap_selection_ends(
17795        &mut self,
17796        _: &actions::SwapSelectionEnds,
17797        window: &mut Window,
17798        cx: &mut Context<Self>,
17799    ) {
17800        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17801            s.move_with(|_, sel| {
17802                if sel.start != sel.end {
17803                    sel.reversed = !sel.reversed
17804                }
17805            });
17806        });
17807        self.request_autoscroll(Autoscroll::newest(), cx);
17808        cx.notify();
17809    }
17810
17811    pub fn toggle_focus(
17812        workspace: &mut Workspace,
17813        _: &actions::ToggleFocus,
17814        window: &mut Window,
17815        cx: &mut Context<Workspace>,
17816    ) {
17817        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17818            return;
17819        };
17820        workspace.activate_item(&item, true, true, window, cx);
17821    }
17822
17823    pub fn toggle_fold(
17824        &mut self,
17825        _: &actions::ToggleFold,
17826        window: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        if self.is_singleton(cx) {
17830            let selection = self.selections.newest::<Point>(cx);
17831
17832            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17833            let range = if selection.is_empty() {
17834                let point = selection.head().to_display_point(&display_map);
17835                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17836                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17837                    .to_point(&display_map);
17838                start..end
17839            } else {
17840                selection.range()
17841            };
17842            if display_map.folds_in_range(range).next().is_some() {
17843                self.unfold_lines(&Default::default(), window, cx)
17844            } else {
17845                self.fold(&Default::default(), window, cx)
17846            }
17847        } else {
17848            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17849            let buffer_ids: HashSet<_> = self
17850                .selections
17851                .disjoint_anchor_ranges()
17852                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17853                .collect();
17854
17855            let should_unfold = buffer_ids
17856                .iter()
17857                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17858
17859            for buffer_id in buffer_ids {
17860                if should_unfold {
17861                    self.unfold_buffer(buffer_id, cx);
17862                } else {
17863                    self.fold_buffer(buffer_id, cx);
17864                }
17865            }
17866        }
17867    }
17868
17869    pub fn toggle_fold_recursive(
17870        &mut self,
17871        _: &actions::ToggleFoldRecursive,
17872        window: &mut Window,
17873        cx: &mut Context<Self>,
17874    ) {
17875        let selection = self.selections.newest::<Point>(cx);
17876
17877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17878        let range = if selection.is_empty() {
17879            let point = selection.head().to_display_point(&display_map);
17880            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17881            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17882                .to_point(&display_map);
17883            start..end
17884        } else {
17885            selection.range()
17886        };
17887        if display_map.folds_in_range(range).next().is_some() {
17888            self.unfold_recursive(&Default::default(), window, cx)
17889        } else {
17890            self.fold_recursive(&Default::default(), window, cx)
17891        }
17892    }
17893
17894    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17895        if self.is_singleton(cx) {
17896            let mut to_fold = Vec::new();
17897            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17898            let selections = self.selections.all_adjusted(cx);
17899
17900            for selection in selections {
17901                let range = selection.range().sorted();
17902                let buffer_start_row = range.start.row;
17903
17904                if range.start.row != range.end.row {
17905                    let mut found = false;
17906                    let mut row = range.start.row;
17907                    while row <= range.end.row {
17908                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17909                        {
17910                            found = true;
17911                            row = crease.range().end.row + 1;
17912                            to_fold.push(crease);
17913                        } else {
17914                            row += 1
17915                        }
17916                    }
17917                    if found {
17918                        continue;
17919                    }
17920                }
17921
17922                for row in (0..=range.start.row).rev() {
17923                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17924                        && crease.range().end.row >= buffer_start_row
17925                    {
17926                        to_fold.push(crease);
17927                        if row <= range.start.row {
17928                            break;
17929                        }
17930                    }
17931                }
17932            }
17933
17934            self.fold_creases(to_fold, true, window, cx);
17935        } else {
17936            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17937            let buffer_ids = self
17938                .selections
17939                .disjoint_anchor_ranges()
17940                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17941                .collect::<HashSet<_>>();
17942            for buffer_id in buffer_ids {
17943                self.fold_buffer(buffer_id, cx);
17944            }
17945        }
17946    }
17947
17948    pub fn toggle_fold_all(
17949        &mut self,
17950        _: &actions::ToggleFoldAll,
17951        window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        if self.buffer.read(cx).is_singleton() {
17955            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17956            let has_folds = display_map
17957                .folds_in_range(0..display_map.buffer_snapshot.len())
17958                .next()
17959                .is_some();
17960
17961            if has_folds {
17962                self.unfold_all(&actions::UnfoldAll, window, cx);
17963            } else {
17964                self.fold_all(&actions::FoldAll, window, cx);
17965            }
17966        } else {
17967            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17968            let should_unfold = buffer_ids
17969                .iter()
17970                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17971
17972            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17973                editor
17974                    .update_in(cx, |editor, _, cx| {
17975                        for buffer_id in buffer_ids {
17976                            if should_unfold {
17977                                editor.unfold_buffer(buffer_id, cx);
17978                            } else {
17979                                editor.fold_buffer(buffer_id, cx);
17980                            }
17981                        }
17982                    })
17983                    .ok();
17984            });
17985        }
17986    }
17987
17988    fn fold_at_level(
17989        &mut self,
17990        fold_at: &FoldAtLevel,
17991        window: &mut Window,
17992        cx: &mut Context<Self>,
17993    ) {
17994        if !self.buffer.read(cx).is_singleton() {
17995            return;
17996        }
17997
17998        let fold_at_level = fold_at.0;
17999        let snapshot = self.buffer.read(cx).snapshot(cx);
18000        let mut to_fold = Vec::new();
18001        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18002
18003        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18004            while start_row < end_row {
18005                match self
18006                    .snapshot(window, cx)
18007                    .crease_for_buffer_row(MultiBufferRow(start_row))
18008                {
18009                    Some(crease) => {
18010                        let nested_start_row = crease.range().start.row + 1;
18011                        let nested_end_row = crease.range().end.row;
18012
18013                        if current_level < fold_at_level {
18014                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18015                        } else if current_level == fold_at_level {
18016                            to_fold.push(crease);
18017                        }
18018
18019                        start_row = nested_end_row + 1;
18020                    }
18021                    None => start_row += 1,
18022                }
18023            }
18024        }
18025
18026        self.fold_creases(to_fold, true, window, cx);
18027    }
18028
18029    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18030        if self.buffer.read(cx).is_singleton() {
18031            let mut fold_ranges = Vec::new();
18032            let snapshot = self.buffer.read(cx).snapshot(cx);
18033
18034            for row in 0..snapshot.max_row().0 {
18035                if let Some(foldable_range) = self
18036                    .snapshot(window, cx)
18037                    .crease_for_buffer_row(MultiBufferRow(row))
18038                {
18039                    fold_ranges.push(foldable_range);
18040                }
18041            }
18042
18043            self.fold_creases(fold_ranges, true, window, cx);
18044        } else {
18045            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18046                editor
18047                    .update_in(cx, |editor, _, cx| {
18048                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18049                            editor.fold_buffer(buffer_id, cx);
18050                        }
18051                    })
18052                    .ok();
18053            });
18054        }
18055    }
18056
18057    pub fn fold_function_bodies(
18058        &mut self,
18059        _: &actions::FoldFunctionBodies,
18060        window: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) {
18063        let snapshot = self.buffer.read(cx).snapshot(cx);
18064
18065        let ranges = snapshot
18066            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18067            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18068            .collect::<Vec<_>>();
18069
18070        let creases = ranges
18071            .into_iter()
18072            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18073            .collect();
18074
18075        self.fold_creases(creases, true, window, cx);
18076    }
18077
18078    pub fn fold_recursive(
18079        &mut self,
18080        _: &actions::FoldRecursive,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        let mut to_fold = Vec::new();
18085        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18086        let selections = self.selections.all_adjusted(cx);
18087
18088        for selection in selections {
18089            let range = selection.range().sorted();
18090            let buffer_start_row = range.start.row;
18091
18092            if range.start.row != range.end.row {
18093                let mut found = false;
18094                for row in range.start.row..=range.end.row {
18095                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18096                        found = true;
18097                        to_fold.push(crease);
18098                    }
18099                }
18100                if found {
18101                    continue;
18102                }
18103            }
18104
18105            for row in (0..=range.start.row).rev() {
18106                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18107                    if crease.range().end.row >= buffer_start_row {
18108                        to_fold.push(crease);
18109                    } else {
18110                        break;
18111                    }
18112                }
18113            }
18114        }
18115
18116        self.fold_creases(to_fold, true, window, cx);
18117    }
18118
18119    pub fn fold_at(
18120        &mut self,
18121        buffer_row: MultiBufferRow,
18122        window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126
18127        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18128            let autoscroll = self
18129                .selections
18130                .all::<Point>(cx)
18131                .iter()
18132                .any(|selection| crease.range().overlaps(&selection.range()));
18133
18134            self.fold_creases(vec![crease], autoscroll, window, cx);
18135        }
18136    }
18137
18138    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18139        if self.is_singleton(cx) {
18140            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18141            let buffer = &display_map.buffer_snapshot;
18142            let selections = self.selections.all::<Point>(cx);
18143            let ranges = selections
18144                .iter()
18145                .map(|s| {
18146                    let range = s.display_range(&display_map).sorted();
18147                    let mut start = range.start.to_point(&display_map);
18148                    let mut end = range.end.to_point(&display_map);
18149                    start.column = 0;
18150                    end.column = buffer.line_len(MultiBufferRow(end.row));
18151                    start..end
18152                })
18153                .collect::<Vec<_>>();
18154
18155            self.unfold_ranges(&ranges, true, true, cx);
18156        } else {
18157            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18158            let buffer_ids = self
18159                .selections
18160                .disjoint_anchor_ranges()
18161                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18162                .collect::<HashSet<_>>();
18163            for buffer_id in buffer_ids {
18164                self.unfold_buffer(buffer_id, cx);
18165            }
18166        }
18167    }
18168
18169    pub fn unfold_recursive(
18170        &mut self,
18171        _: &UnfoldRecursive,
18172        _window: &mut Window,
18173        cx: &mut Context<Self>,
18174    ) {
18175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18176        let selections = self.selections.all::<Point>(cx);
18177        let ranges = selections
18178            .iter()
18179            .map(|s| {
18180                let mut range = s.display_range(&display_map).sorted();
18181                *range.start.column_mut() = 0;
18182                *range.end.column_mut() = display_map.line_len(range.end.row());
18183                let start = range.start.to_point(&display_map);
18184                let end = range.end.to_point(&display_map);
18185                start..end
18186            })
18187            .collect::<Vec<_>>();
18188
18189        self.unfold_ranges(&ranges, true, true, cx);
18190    }
18191
18192    pub fn unfold_at(
18193        &mut self,
18194        buffer_row: MultiBufferRow,
18195        _window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18199
18200        let intersection_range = Point::new(buffer_row.0, 0)
18201            ..Point::new(
18202                buffer_row.0,
18203                display_map.buffer_snapshot.line_len(buffer_row),
18204            );
18205
18206        let autoscroll = self
18207            .selections
18208            .all::<Point>(cx)
18209            .iter()
18210            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18211
18212        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18213    }
18214
18215    pub fn unfold_all(
18216        &mut self,
18217        _: &actions::UnfoldAll,
18218        _window: &mut Window,
18219        cx: &mut Context<Self>,
18220    ) {
18221        if self.buffer.read(cx).is_singleton() {
18222            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18223            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18224        } else {
18225            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18226                editor
18227                    .update(cx, |editor, cx| {
18228                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18229                            editor.unfold_buffer(buffer_id, cx);
18230                        }
18231                    })
18232                    .ok();
18233            });
18234        }
18235    }
18236
18237    pub fn fold_selected_ranges(
18238        &mut self,
18239        _: &FoldSelectedRanges,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        let selections = self.selections.all_adjusted(cx);
18244        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18245        let ranges = selections
18246            .into_iter()
18247            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18248            .collect::<Vec<_>>();
18249        self.fold_creases(ranges, true, window, cx);
18250    }
18251
18252    pub fn fold_ranges<T: ToOffset + Clone>(
18253        &mut self,
18254        ranges: Vec<Range<T>>,
18255        auto_scroll: bool,
18256        window: &mut Window,
18257        cx: &mut Context<Self>,
18258    ) {
18259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18260        let ranges = ranges
18261            .into_iter()
18262            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18263            .collect::<Vec<_>>();
18264        self.fold_creases(ranges, auto_scroll, window, cx);
18265    }
18266
18267    pub fn fold_creases<T: ToOffset + Clone>(
18268        &mut self,
18269        creases: Vec<Crease<T>>,
18270        auto_scroll: bool,
18271        _window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) {
18274        if creases.is_empty() {
18275            return;
18276        }
18277
18278        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18279
18280        if auto_scroll {
18281            self.request_autoscroll(Autoscroll::fit(), cx);
18282        }
18283
18284        cx.notify();
18285
18286        self.scrollbar_marker_state.dirty = true;
18287        self.folds_did_change(cx);
18288    }
18289
18290    /// Removes any folds whose ranges intersect any of the given ranges.
18291    pub fn unfold_ranges<T: ToOffset + Clone>(
18292        &mut self,
18293        ranges: &[Range<T>],
18294        inclusive: bool,
18295        auto_scroll: bool,
18296        cx: &mut Context<Self>,
18297    ) {
18298        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18299            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18300        });
18301        self.folds_did_change(cx);
18302    }
18303
18304    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18305        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18306            return;
18307        }
18308        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18309        self.display_map.update(cx, |display_map, cx| {
18310            display_map.fold_buffers([buffer_id], cx)
18311        });
18312        cx.emit(EditorEvent::BufferFoldToggled {
18313            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18314            folded: true,
18315        });
18316        cx.notify();
18317    }
18318
18319    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18320        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18321            return;
18322        }
18323        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18324        self.display_map.update(cx, |display_map, cx| {
18325            display_map.unfold_buffers([buffer_id], cx);
18326        });
18327        cx.emit(EditorEvent::BufferFoldToggled {
18328            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18329            folded: false,
18330        });
18331        cx.notify();
18332    }
18333
18334    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18335        self.display_map.read(cx).is_buffer_folded(buffer)
18336    }
18337
18338    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18339        self.display_map.read(cx).folded_buffers()
18340    }
18341
18342    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18343        self.display_map.update(cx, |display_map, cx| {
18344            display_map.disable_header_for_buffer(buffer_id, cx);
18345        });
18346        cx.notify();
18347    }
18348
18349    /// Removes any folds with the given ranges.
18350    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18351        &mut self,
18352        ranges: &[Range<T>],
18353        type_id: TypeId,
18354        auto_scroll: bool,
18355        cx: &mut Context<Self>,
18356    ) {
18357        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18358            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18359        });
18360        self.folds_did_change(cx);
18361    }
18362
18363    fn remove_folds_with<T: ToOffset + Clone>(
18364        &mut self,
18365        ranges: &[Range<T>],
18366        auto_scroll: bool,
18367        cx: &mut Context<Self>,
18368        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18369    ) {
18370        if ranges.is_empty() {
18371            return;
18372        }
18373
18374        let mut buffers_affected = HashSet::default();
18375        let multi_buffer = self.buffer().read(cx);
18376        for range in ranges {
18377            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18378                buffers_affected.insert(buffer.read(cx).remote_id());
18379            };
18380        }
18381
18382        self.display_map.update(cx, update);
18383
18384        if auto_scroll {
18385            self.request_autoscroll(Autoscroll::fit(), cx);
18386        }
18387
18388        cx.notify();
18389        self.scrollbar_marker_state.dirty = true;
18390        self.active_indent_guides_state.dirty = true;
18391    }
18392
18393    pub fn update_renderer_widths(
18394        &mut self,
18395        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18396        cx: &mut Context<Self>,
18397    ) -> bool {
18398        self.display_map
18399            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18400    }
18401
18402    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18403        self.display_map.read(cx).fold_placeholder.clone()
18404    }
18405
18406    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18407        self.buffer.update(cx, |buffer, cx| {
18408            buffer.set_all_diff_hunks_expanded(cx);
18409        });
18410    }
18411
18412    pub fn expand_all_diff_hunks(
18413        &mut self,
18414        _: &ExpandAllDiffHunks,
18415        _window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        self.buffer.update(cx, |buffer, cx| {
18419            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18420        });
18421    }
18422
18423    pub fn toggle_selected_diff_hunks(
18424        &mut self,
18425        _: &ToggleSelectedDiffHunks,
18426        _window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let ranges: Vec<_> = self
18430            .selections
18431            .disjoint_anchors()
18432            .iter()
18433            .map(|s| s.range())
18434            .collect();
18435        self.toggle_diff_hunks_in_ranges(ranges, cx);
18436    }
18437
18438    pub fn diff_hunks_in_ranges<'a>(
18439        &'a self,
18440        ranges: &'a [Range<Anchor>],
18441        buffer: &'a MultiBufferSnapshot,
18442    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18443        ranges.iter().flat_map(move |range| {
18444            let end_excerpt_id = range.end.excerpt_id;
18445            let range = range.to_point(buffer);
18446            let mut peek_end = range.end;
18447            if range.end.row < buffer.max_row().0 {
18448                peek_end = Point::new(range.end.row + 1, 0);
18449            }
18450            buffer
18451                .diff_hunks_in_range(range.start..peek_end)
18452                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18453        })
18454    }
18455
18456    pub fn has_stageable_diff_hunks_in_ranges(
18457        &self,
18458        ranges: &[Range<Anchor>],
18459        snapshot: &MultiBufferSnapshot,
18460    ) -> bool {
18461        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18462        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18463    }
18464
18465    pub fn toggle_staged_selected_diff_hunks(
18466        &mut self,
18467        _: &::git::ToggleStaged,
18468        _: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        let snapshot = self.buffer.read(cx).snapshot(cx);
18472        let ranges: Vec<_> = self
18473            .selections
18474            .disjoint_anchors()
18475            .iter()
18476            .map(|s| s.range())
18477            .collect();
18478        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18479        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18480    }
18481
18482    pub fn set_render_diff_hunk_controls(
18483        &mut self,
18484        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18485        cx: &mut Context<Self>,
18486    ) {
18487        self.render_diff_hunk_controls = render_diff_hunk_controls;
18488        cx.notify();
18489    }
18490
18491    pub fn stage_and_next(
18492        &mut self,
18493        _: &::git::StageAndNext,
18494        window: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) {
18497        self.do_stage_or_unstage_and_next(true, window, cx);
18498    }
18499
18500    pub fn unstage_and_next(
18501        &mut self,
18502        _: &::git::UnstageAndNext,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) {
18506        self.do_stage_or_unstage_and_next(false, window, cx);
18507    }
18508
18509    pub fn stage_or_unstage_diff_hunks(
18510        &mut self,
18511        stage: bool,
18512        ranges: Vec<Range<Anchor>>,
18513        cx: &mut Context<Self>,
18514    ) {
18515        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18516        cx.spawn(async move |this, cx| {
18517            task.await?;
18518            this.update(cx, |this, cx| {
18519                let snapshot = this.buffer.read(cx).snapshot(cx);
18520                let chunk_by = this
18521                    .diff_hunks_in_ranges(&ranges, &snapshot)
18522                    .chunk_by(|hunk| hunk.buffer_id);
18523                for (buffer_id, hunks) in &chunk_by {
18524                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18525                }
18526            })
18527        })
18528        .detach_and_log_err(cx);
18529    }
18530
18531    fn save_buffers_for_ranges_if_needed(
18532        &mut self,
18533        ranges: &[Range<Anchor>],
18534        cx: &mut Context<Editor>,
18535    ) -> Task<Result<()>> {
18536        let multibuffer = self.buffer.read(cx);
18537        let snapshot = multibuffer.read(cx);
18538        let buffer_ids: HashSet<_> = ranges
18539            .iter()
18540            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18541            .collect();
18542        drop(snapshot);
18543
18544        let mut buffers = HashSet::default();
18545        for buffer_id in buffer_ids {
18546            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18547                let buffer = buffer_entity.read(cx);
18548                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18549                {
18550                    buffers.insert(buffer_entity);
18551                }
18552            }
18553        }
18554
18555        if let Some(project) = &self.project {
18556            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18557        } else {
18558            Task::ready(Ok(()))
18559        }
18560    }
18561
18562    fn do_stage_or_unstage_and_next(
18563        &mut self,
18564        stage: bool,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18569
18570        if ranges.iter().any(|range| range.start != range.end) {
18571            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18572            return;
18573        }
18574
18575        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18576        let snapshot = self.snapshot(window, cx);
18577        let position = self.selections.newest::<Point>(cx).head();
18578        let mut row = snapshot
18579            .buffer_snapshot
18580            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18581            .find(|hunk| hunk.row_range.start.0 > position.row)
18582            .map(|hunk| hunk.row_range.start);
18583
18584        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18585        // Outside of the project diff editor, wrap around to the beginning.
18586        if !all_diff_hunks_expanded {
18587            row = row.or_else(|| {
18588                snapshot
18589                    .buffer_snapshot
18590                    .diff_hunks_in_range(Point::zero()..position)
18591                    .find(|hunk| hunk.row_range.end.0 < position.row)
18592                    .map(|hunk| hunk.row_range.start)
18593            });
18594        }
18595
18596        if let Some(row) = row {
18597            let destination = Point::new(row.0, 0);
18598            let autoscroll = Autoscroll::center();
18599
18600            self.unfold_ranges(&[destination..destination], false, false, cx);
18601            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18602                s.select_ranges([destination..destination]);
18603            });
18604        }
18605    }
18606
18607    fn do_stage_or_unstage(
18608        &self,
18609        stage: bool,
18610        buffer_id: BufferId,
18611        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18612        cx: &mut App,
18613    ) -> Option<()> {
18614        let project = self.project()?;
18615        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18616        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18617        let buffer_snapshot = buffer.read(cx).snapshot();
18618        let file_exists = buffer_snapshot
18619            .file()
18620            .is_some_and(|file| file.disk_state().exists());
18621        diff.update(cx, |diff, cx| {
18622            diff.stage_or_unstage_hunks(
18623                stage,
18624                &hunks
18625                    .map(|hunk| buffer_diff::DiffHunk {
18626                        buffer_range: hunk.buffer_range,
18627                        diff_base_byte_range: hunk.diff_base_byte_range,
18628                        secondary_status: hunk.secondary_status,
18629                        range: Point::zero()..Point::zero(), // unused
18630                    })
18631                    .collect::<Vec<_>>(),
18632                &buffer_snapshot,
18633                file_exists,
18634                cx,
18635            )
18636        });
18637        None
18638    }
18639
18640    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18641        let ranges: Vec<_> = self
18642            .selections
18643            .disjoint_anchors()
18644            .iter()
18645            .map(|s| s.range())
18646            .collect();
18647        self.buffer
18648            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18649    }
18650
18651    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18652        self.buffer.update(cx, |buffer, cx| {
18653            let ranges = vec![Anchor::min()..Anchor::max()];
18654            if !buffer.all_diff_hunks_expanded()
18655                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18656            {
18657                buffer.collapse_diff_hunks(ranges, cx);
18658                true
18659            } else {
18660                false
18661            }
18662        })
18663    }
18664
18665    fn toggle_diff_hunks_in_ranges(
18666        &mut self,
18667        ranges: Vec<Range<Anchor>>,
18668        cx: &mut Context<Editor>,
18669    ) {
18670        self.buffer.update(cx, |buffer, cx| {
18671            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18672            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18673        })
18674    }
18675
18676    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18677        self.buffer.update(cx, |buffer, cx| {
18678            let snapshot = buffer.snapshot(cx);
18679            let excerpt_id = range.end.excerpt_id;
18680            let point_range = range.to_point(&snapshot);
18681            let expand = !buffer.single_hunk_is_expanded(range, cx);
18682            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18683        })
18684    }
18685
18686    pub(crate) fn apply_all_diff_hunks(
18687        &mut self,
18688        _: &ApplyAllDiffHunks,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18693
18694        let buffers = self.buffer.read(cx).all_buffers();
18695        for branch_buffer in buffers {
18696            branch_buffer.update(cx, |branch_buffer, cx| {
18697                branch_buffer.merge_into_base(Vec::new(), cx);
18698            });
18699        }
18700
18701        if let Some(project) = self.project.clone() {
18702            self.save(
18703                SaveOptions {
18704                    format: true,
18705                    autosave: false,
18706                },
18707                project,
18708                window,
18709                cx,
18710            )
18711            .detach_and_log_err(cx);
18712        }
18713    }
18714
18715    pub(crate) fn apply_selected_diff_hunks(
18716        &mut self,
18717        _: &ApplyDiffHunk,
18718        window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) {
18721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18722        let snapshot = self.snapshot(window, cx);
18723        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18724        let mut ranges_by_buffer = HashMap::default();
18725        self.transact(window, cx, |editor, _window, cx| {
18726            for hunk in hunks {
18727                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18728                    ranges_by_buffer
18729                        .entry(buffer.clone())
18730                        .or_insert_with(Vec::new)
18731                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18732                }
18733            }
18734
18735            for (buffer, ranges) in ranges_by_buffer {
18736                buffer.update(cx, |buffer, cx| {
18737                    buffer.merge_into_base(ranges, cx);
18738                });
18739            }
18740        });
18741
18742        if let Some(project) = self.project.clone() {
18743            self.save(
18744                SaveOptions {
18745                    format: true,
18746                    autosave: false,
18747                },
18748                project,
18749                window,
18750                cx,
18751            )
18752            .detach_and_log_err(cx);
18753        }
18754    }
18755
18756    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18757        if hovered != self.gutter_hovered {
18758            self.gutter_hovered = hovered;
18759            cx.notify();
18760        }
18761    }
18762
18763    pub fn insert_blocks(
18764        &mut self,
18765        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18766        autoscroll: Option<Autoscroll>,
18767        cx: &mut Context<Self>,
18768    ) -> Vec<CustomBlockId> {
18769        let blocks = self
18770            .display_map
18771            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18772        if let Some(autoscroll) = autoscroll {
18773            self.request_autoscroll(autoscroll, cx);
18774        }
18775        cx.notify();
18776        blocks
18777    }
18778
18779    pub fn resize_blocks(
18780        &mut self,
18781        heights: HashMap<CustomBlockId, u32>,
18782        autoscroll: Option<Autoscroll>,
18783        cx: &mut Context<Self>,
18784    ) {
18785        self.display_map
18786            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18787        if let Some(autoscroll) = autoscroll {
18788            self.request_autoscroll(autoscroll, cx);
18789        }
18790        cx.notify();
18791    }
18792
18793    pub fn replace_blocks(
18794        &mut self,
18795        renderers: HashMap<CustomBlockId, RenderBlock>,
18796        autoscroll: Option<Autoscroll>,
18797        cx: &mut Context<Self>,
18798    ) {
18799        self.display_map
18800            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18801        if let Some(autoscroll) = autoscroll {
18802            self.request_autoscroll(autoscroll, cx);
18803        }
18804        cx.notify();
18805    }
18806
18807    pub fn remove_blocks(
18808        &mut self,
18809        block_ids: HashSet<CustomBlockId>,
18810        autoscroll: Option<Autoscroll>,
18811        cx: &mut Context<Self>,
18812    ) {
18813        self.display_map.update(cx, |display_map, cx| {
18814            display_map.remove_blocks(block_ids, cx)
18815        });
18816        if let Some(autoscroll) = autoscroll {
18817            self.request_autoscroll(autoscroll, cx);
18818        }
18819        cx.notify();
18820    }
18821
18822    pub fn row_for_block(
18823        &self,
18824        block_id: CustomBlockId,
18825        cx: &mut Context<Self>,
18826    ) -> Option<DisplayRow> {
18827        self.display_map
18828            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18829    }
18830
18831    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18832        self.focused_block = Some(focused_block);
18833    }
18834
18835    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18836        self.focused_block.take()
18837    }
18838
18839    pub fn insert_creases(
18840        &mut self,
18841        creases: impl IntoIterator<Item = Crease<Anchor>>,
18842        cx: &mut Context<Self>,
18843    ) -> Vec<CreaseId> {
18844        self.display_map
18845            .update(cx, |map, cx| map.insert_creases(creases, cx))
18846    }
18847
18848    pub fn remove_creases(
18849        &mut self,
18850        ids: impl IntoIterator<Item = CreaseId>,
18851        cx: &mut Context<Self>,
18852    ) -> Vec<(CreaseId, Range<Anchor>)> {
18853        self.display_map
18854            .update(cx, |map, cx| map.remove_creases(ids, cx))
18855    }
18856
18857    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18858        self.display_map
18859            .update(cx, |map, cx| map.snapshot(cx))
18860            .longest_row()
18861    }
18862
18863    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18864        self.display_map
18865            .update(cx, |map, cx| map.snapshot(cx))
18866            .max_point()
18867    }
18868
18869    pub fn text(&self, cx: &App) -> String {
18870        self.buffer.read(cx).read(cx).text()
18871    }
18872
18873    pub fn is_empty(&self, cx: &App) -> bool {
18874        self.buffer.read(cx).read(cx).is_empty()
18875    }
18876
18877    pub fn text_option(&self, cx: &App) -> Option<String> {
18878        let text = self.text(cx);
18879        let text = text.trim();
18880
18881        if text.is_empty() {
18882            return None;
18883        }
18884
18885        Some(text.to_string())
18886    }
18887
18888    pub fn set_text(
18889        &mut self,
18890        text: impl Into<Arc<str>>,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) {
18894        self.transact(window, cx, |this, _, cx| {
18895            this.buffer
18896                .read(cx)
18897                .as_singleton()
18898                .expect("you can only call set_text on editors for singleton buffers")
18899                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18900        });
18901    }
18902
18903    pub fn display_text(&self, cx: &mut App) -> String {
18904        self.display_map
18905            .update(cx, |map, cx| map.snapshot(cx))
18906            .text()
18907    }
18908
18909    fn create_minimap(
18910        &self,
18911        minimap_settings: MinimapSettings,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) -> Option<Entity<Self>> {
18915        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18916            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18917    }
18918
18919    fn initialize_new_minimap(
18920        &self,
18921        minimap_settings: MinimapSettings,
18922        window: &mut Window,
18923        cx: &mut Context<Self>,
18924    ) -> Entity<Self> {
18925        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18926
18927        let mut minimap = Editor::new_internal(
18928            EditorMode::Minimap {
18929                parent: cx.weak_entity(),
18930            },
18931            self.buffer.clone(),
18932            None,
18933            Some(self.display_map.clone()),
18934            window,
18935            cx,
18936        );
18937        minimap.scroll_manager.clone_state(&self.scroll_manager);
18938        minimap.set_text_style_refinement(TextStyleRefinement {
18939            font_size: Some(MINIMAP_FONT_SIZE),
18940            font_weight: Some(MINIMAP_FONT_WEIGHT),
18941            ..Default::default()
18942        });
18943        minimap.update_minimap_configuration(minimap_settings, cx);
18944        cx.new(|_| minimap)
18945    }
18946
18947    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18948        let current_line_highlight = minimap_settings
18949            .current_line_highlight
18950            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18951        self.set_current_line_highlight(Some(current_line_highlight));
18952    }
18953
18954    pub fn minimap(&self) -> Option<&Entity<Self>> {
18955        self.minimap
18956            .as_ref()
18957            .filter(|_| self.minimap_visibility.visible())
18958    }
18959
18960    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18961        let mut wrap_guides = smallvec![];
18962
18963        if self.show_wrap_guides == Some(false) {
18964            return wrap_guides;
18965        }
18966
18967        let settings = self.buffer.read(cx).language_settings(cx);
18968        if settings.show_wrap_guides {
18969            match self.soft_wrap_mode(cx) {
18970                SoftWrap::Column(soft_wrap) => {
18971                    wrap_guides.push((soft_wrap as usize, true));
18972                }
18973                SoftWrap::Bounded(soft_wrap) => {
18974                    wrap_guides.push((soft_wrap as usize, true));
18975                }
18976                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18977            }
18978            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18979        }
18980
18981        wrap_guides
18982    }
18983
18984    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18985        let settings = self.buffer.read(cx).language_settings(cx);
18986        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18987        match mode {
18988            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18989                SoftWrap::None
18990            }
18991            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18992            language_settings::SoftWrap::PreferredLineLength => {
18993                SoftWrap::Column(settings.preferred_line_length)
18994            }
18995            language_settings::SoftWrap::Bounded => {
18996                SoftWrap::Bounded(settings.preferred_line_length)
18997            }
18998        }
18999    }
19000
19001    pub fn set_soft_wrap_mode(
19002        &mut self,
19003        mode: language_settings::SoftWrap,
19004
19005        cx: &mut Context<Self>,
19006    ) {
19007        self.soft_wrap_mode_override = Some(mode);
19008        cx.notify();
19009    }
19010
19011    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19012        self.hard_wrap = hard_wrap;
19013        cx.notify();
19014    }
19015
19016    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19017        self.text_style_refinement = Some(style);
19018    }
19019
19020    /// called by the Element so we know what style we were most recently rendered with.
19021    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19022        // We intentionally do not inform the display map about the minimap style
19023        // so that wrapping is not recalculated and stays consistent for the editor
19024        // and its linked minimap.
19025        if !self.mode.is_minimap() {
19026            let font = style.text.font();
19027            let font_size = style.text.font_size.to_pixels(window.rem_size());
19028            let display_map = self
19029                .placeholder_display_map
19030                .as_ref()
19031                .filter(|_| self.is_empty(cx))
19032                .unwrap_or(&self.display_map);
19033
19034            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19035        }
19036        self.style = Some(style);
19037    }
19038
19039    pub fn style(&self) -> Option<&EditorStyle> {
19040        self.style.as_ref()
19041    }
19042
19043    // Called by the element. This method is not designed to be called outside of the editor
19044    // element's layout code because it does not notify when rewrapping is computed synchronously.
19045    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19046        if self.is_empty(cx) {
19047            self.placeholder_display_map
19048                .as_ref()
19049                .map_or(false, |display_map| {
19050                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19051                })
19052        } else {
19053            self.display_map
19054                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19055        }
19056    }
19057
19058    pub fn set_soft_wrap(&mut self) {
19059        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19060    }
19061
19062    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19063        if self.soft_wrap_mode_override.is_some() {
19064            self.soft_wrap_mode_override.take();
19065        } else {
19066            let soft_wrap = match self.soft_wrap_mode(cx) {
19067                SoftWrap::GitDiff => return,
19068                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19069                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19070                    language_settings::SoftWrap::None
19071                }
19072            };
19073            self.soft_wrap_mode_override = Some(soft_wrap);
19074        }
19075        cx.notify();
19076    }
19077
19078    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19079        let Some(workspace) = self.workspace() else {
19080            return;
19081        };
19082        let fs = workspace.read(cx).app_state().fs.clone();
19083        let current_show = TabBarSettings::get_global(cx).show;
19084        update_settings_file(fs, cx, move |setting, _| {
19085            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19086        });
19087    }
19088
19089    pub fn toggle_indent_guides(
19090        &mut self,
19091        _: &ToggleIndentGuides,
19092        _: &mut Window,
19093        cx: &mut Context<Self>,
19094    ) {
19095        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19096            self.buffer
19097                .read(cx)
19098                .language_settings(cx)
19099                .indent_guides
19100                .enabled
19101        });
19102        self.show_indent_guides = Some(!currently_enabled);
19103        cx.notify();
19104    }
19105
19106    fn should_show_indent_guides(&self) -> Option<bool> {
19107        self.show_indent_guides
19108    }
19109
19110    pub fn toggle_line_numbers(
19111        &mut self,
19112        _: &ToggleLineNumbers,
19113        _: &mut Window,
19114        cx: &mut Context<Self>,
19115    ) {
19116        let mut editor_settings = EditorSettings::get_global(cx).clone();
19117        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19118        EditorSettings::override_global(editor_settings, cx);
19119    }
19120
19121    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19122        if let Some(show_line_numbers) = self.show_line_numbers {
19123            return show_line_numbers;
19124        }
19125        EditorSettings::get_global(cx).gutter.line_numbers
19126    }
19127
19128    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19129        self.use_relative_line_numbers
19130            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19131    }
19132
19133    pub fn toggle_relative_line_numbers(
19134        &mut self,
19135        _: &ToggleRelativeLineNumbers,
19136        _: &mut Window,
19137        cx: &mut Context<Self>,
19138    ) {
19139        let is_relative = self.should_use_relative_line_numbers(cx);
19140        self.set_relative_line_number(Some(!is_relative), cx)
19141    }
19142
19143    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19144        self.use_relative_line_numbers = is_relative;
19145        cx.notify();
19146    }
19147
19148    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19149        self.show_gutter = show_gutter;
19150        cx.notify();
19151    }
19152
19153    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19154        self.show_scrollbars = ScrollbarAxes {
19155            horizontal: show,
19156            vertical: show,
19157        };
19158        cx.notify();
19159    }
19160
19161    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19162        self.show_scrollbars.vertical = show;
19163        cx.notify();
19164    }
19165
19166    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19167        self.show_scrollbars.horizontal = show;
19168        cx.notify();
19169    }
19170
19171    pub fn set_minimap_visibility(
19172        &mut self,
19173        minimap_visibility: MinimapVisibility,
19174        window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        if self.minimap_visibility != minimap_visibility {
19178            if minimap_visibility.visible() && self.minimap.is_none() {
19179                let minimap_settings = EditorSettings::get_global(cx).minimap;
19180                self.minimap =
19181                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19182            }
19183            self.minimap_visibility = minimap_visibility;
19184            cx.notify();
19185        }
19186    }
19187
19188    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19189        self.set_show_scrollbars(false, cx);
19190        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19191    }
19192
19193    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19194        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19195    }
19196
19197    /// Normally the text in full mode and auto height editors is padded on the
19198    /// left side by roughly half a character width for improved hit testing.
19199    ///
19200    /// Use this method to disable this for cases where this is not wanted (e.g.
19201    /// if you want to align the editor text with some other text above or below)
19202    /// or if you want to add this padding to single-line editors.
19203    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19204        self.offset_content = offset_content;
19205        cx.notify();
19206    }
19207
19208    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19209        self.show_line_numbers = Some(show_line_numbers);
19210        cx.notify();
19211    }
19212
19213    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19214        self.disable_expand_excerpt_buttons = true;
19215        cx.notify();
19216    }
19217
19218    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19219        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19220        cx.notify();
19221    }
19222
19223    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19224        self.show_code_actions = Some(show_code_actions);
19225        cx.notify();
19226    }
19227
19228    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19229        self.show_runnables = Some(show_runnables);
19230        cx.notify();
19231    }
19232
19233    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19234        self.show_breakpoints = Some(show_breakpoints);
19235        cx.notify();
19236    }
19237
19238    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19239        if self.display_map.read(cx).masked != masked {
19240            self.display_map.update(cx, |map, _| map.masked = masked);
19241        }
19242        cx.notify()
19243    }
19244
19245    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19246        self.show_wrap_guides = Some(show_wrap_guides);
19247        cx.notify();
19248    }
19249
19250    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19251        self.show_indent_guides = Some(show_indent_guides);
19252        cx.notify();
19253    }
19254
19255    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19256        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19257            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19258                && let Some(dir) = file.abs_path(cx).parent()
19259            {
19260                return Some(dir.to_owned());
19261            }
19262
19263            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19264                return Some(project_path.path.to_path_buf());
19265            }
19266        }
19267
19268        None
19269    }
19270
19271    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19272        self.active_excerpt(cx)?
19273            .1
19274            .read(cx)
19275            .file()
19276            .and_then(|f| f.as_local())
19277    }
19278
19279    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19280        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19281            let buffer = buffer.read(cx);
19282            if let Some(project_path) = buffer.project_path(cx) {
19283                let project = self.project()?.read(cx);
19284                project.absolute_path(&project_path, cx)
19285            } else {
19286                buffer
19287                    .file()
19288                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19289            }
19290        })
19291    }
19292
19293    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19294        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19295            let project_path = buffer.read(cx).project_path(cx)?;
19296            let project = self.project()?.read(cx);
19297            let entry = project.entry_for_path(&project_path, cx)?;
19298            let path = entry.path.to_path_buf();
19299            Some(path)
19300        })
19301    }
19302
19303    pub fn reveal_in_finder(
19304        &mut self,
19305        _: &RevealInFileManager,
19306        _window: &mut Window,
19307        cx: &mut Context<Self>,
19308    ) {
19309        if let Some(target) = self.target_file(cx) {
19310            cx.reveal_path(&target.abs_path(cx));
19311        }
19312    }
19313
19314    pub fn copy_path(
19315        &mut self,
19316        _: &zed_actions::workspace::CopyPath,
19317        _window: &mut Window,
19318        cx: &mut Context<Self>,
19319    ) {
19320        if let Some(path) = self.target_file_abs_path(cx)
19321            && let Some(path) = path.to_str()
19322        {
19323            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19324        } else {
19325            cx.propagate();
19326        }
19327    }
19328
19329    pub fn copy_relative_path(
19330        &mut self,
19331        _: &zed_actions::workspace::CopyRelativePath,
19332        _window: &mut Window,
19333        cx: &mut Context<Self>,
19334    ) {
19335        if let Some(path) = self.target_file_path(cx)
19336            && let Some(path) = path.to_str()
19337        {
19338            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19339        } else {
19340            cx.propagate();
19341        }
19342    }
19343
19344    /// Returns the project path for the editor's buffer, if any buffer is
19345    /// opened in the editor.
19346    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19347        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19348            buffer.read(cx).project_path(cx)
19349        } else {
19350            None
19351        }
19352    }
19353
19354    // Returns true if the editor handled a go-to-line request
19355    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19356        maybe!({
19357            let breakpoint_store = self.breakpoint_store.as_ref()?;
19358
19359            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19360            else {
19361                self.clear_row_highlights::<ActiveDebugLine>();
19362                return None;
19363            };
19364
19365            let position = active_stack_frame.position;
19366            let buffer_id = position.buffer_id?;
19367            let snapshot = self
19368                .project
19369                .as_ref()?
19370                .read(cx)
19371                .buffer_for_id(buffer_id, cx)?
19372                .read(cx)
19373                .snapshot();
19374
19375            let mut handled = false;
19376            for (id, ExcerptRange { context, .. }) in
19377                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19378            {
19379                if context.start.cmp(&position, &snapshot).is_ge()
19380                    || context.end.cmp(&position, &snapshot).is_lt()
19381                {
19382                    continue;
19383                }
19384                let snapshot = self.buffer.read(cx).snapshot(cx);
19385                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19386
19387                handled = true;
19388                self.clear_row_highlights::<ActiveDebugLine>();
19389
19390                self.go_to_line::<ActiveDebugLine>(
19391                    multibuffer_anchor,
19392                    Some(cx.theme().colors().editor_debugger_active_line_background),
19393                    window,
19394                    cx,
19395                );
19396
19397                cx.notify();
19398            }
19399
19400            handled.then_some(())
19401        })
19402        .is_some()
19403    }
19404
19405    pub fn copy_file_name_without_extension(
19406        &mut self,
19407        _: &CopyFileNameWithoutExtension,
19408        _: &mut Window,
19409        cx: &mut Context<Self>,
19410    ) {
19411        if let Some(file) = self.target_file(cx)
19412            && let Some(file_stem) = file.path().file_stem()
19413            && let Some(name) = file_stem.to_str()
19414        {
19415            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19416        }
19417    }
19418
19419    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19420        if let Some(file) = self.target_file(cx)
19421            && let Some(file_name) = file.path().file_name()
19422            && let Some(name) = file_name.to_str()
19423        {
19424            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19425        }
19426    }
19427
19428    pub fn toggle_git_blame(
19429        &mut self,
19430        _: &::git::Blame,
19431        window: &mut Window,
19432        cx: &mut Context<Self>,
19433    ) {
19434        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19435
19436        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19437            self.start_git_blame(true, window, cx);
19438        }
19439
19440        cx.notify();
19441    }
19442
19443    pub fn toggle_git_blame_inline(
19444        &mut self,
19445        _: &ToggleGitBlameInline,
19446        window: &mut Window,
19447        cx: &mut Context<Self>,
19448    ) {
19449        self.toggle_git_blame_inline_internal(true, window, cx);
19450        cx.notify();
19451    }
19452
19453    pub fn open_git_blame_commit(
19454        &mut self,
19455        _: &OpenGitBlameCommit,
19456        window: &mut Window,
19457        cx: &mut Context<Self>,
19458    ) {
19459        self.open_git_blame_commit_internal(window, cx);
19460    }
19461
19462    fn open_git_blame_commit_internal(
19463        &mut self,
19464        window: &mut Window,
19465        cx: &mut Context<Self>,
19466    ) -> Option<()> {
19467        let blame = self.blame.as_ref()?;
19468        let snapshot = self.snapshot(window, cx);
19469        let cursor = self.selections.newest::<Point>(cx).head();
19470        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19471        let (_, blame_entry) = blame
19472            .update(cx, |blame, cx| {
19473                blame
19474                    .blame_for_rows(
19475                        &[RowInfo {
19476                            buffer_id: Some(buffer.remote_id()),
19477                            buffer_row: Some(point.row),
19478                            ..Default::default()
19479                        }],
19480                        cx,
19481                    )
19482                    .next()
19483            })
19484            .flatten()?;
19485        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19486        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19487        let workspace = self.workspace()?.downgrade();
19488        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19489        None
19490    }
19491
19492    pub fn git_blame_inline_enabled(&self) -> bool {
19493        self.git_blame_inline_enabled
19494    }
19495
19496    pub fn toggle_selection_menu(
19497        &mut self,
19498        _: &ToggleSelectionMenu,
19499        _: &mut Window,
19500        cx: &mut Context<Self>,
19501    ) {
19502        self.show_selection_menu = self
19503            .show_selection_menu
19504            .map(|show_selections_menu| !show_selections_menu)
19505            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19506
19507        cx.notify();
19508    }
19509
19510    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19511        self.show_selection_menu
19512            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19513    }
19514
19515    fn start_git_blame(
19516        &mut self,
19517        user_triggered: bool,
19518        window: &mut Window,
19519        cx: &mut Context<Self>,
19520    ) {
19521        if let Some(project) = self.project() {
19522            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19523                && buffer.read(cx).file().is_none()
19524            {
19525                return;
19526            }
19527
19528            let focused = self.focus_handle(cx).contains_focused(window, cx);
19529
19530            let project = project.clone();
19531            let blame = cx
19532                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19533            self.blame_subscription =
19534                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19535            self.blame = Some(blame);
19536        }
19537    }
19538
19539    fn toggle_git_blame_inline_internal(
19540        &mut self,
19541        user_triggered: bool,
19542        window: &mut Window,
19543        cx: &mut Context<Self>,
19544    ) {
19545        if self.git_blame_inline_enabled {
19546            self.git_blame_inline_enabled = false;
19547            self.show_git_blame_inline = false;
19548            self.show_git_blame_inline_delay_task.take();
19549        } else {
19550            self.git_blame_inline_enabled = true;
19551            self.start_git_blame_inline(user_triggered, window, cx);
19552        }
19553
19554        cx.notify();
19555    }
19556
19557    fn start_git_blame_inline(
19558        &mut self,
19559        user_triggered: bool,
19560        window: &mut Window,
19561        cx: &mut Context<Self>,
19562    ) {
19563        self.start_git_blame(user_triggered, window, cx);
19564
19565        if ProjectSettings::get_global(cx)
19566            .git
19567            .inline_blame_delay()
19568            .is_some()
19569        {
19570            self.start_inline_blame_timer(window, cx);
19571        } else {
19572            self.show_git_blame_inline = true
19573        }
19574    }
19575
19576    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19577        self.blame.as_ref()
19578    }
19579
19580    pub fn show_git_blame_gutter(&self) -> bool {
19581        self.show_git_blame_gutter
19582    }
19583
19584    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19585        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19586    }
19587
19588    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19589        self.show_git_blame_inline
19590            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19591            && !self.newest_selection_head_on_empty_line(cx)
19592            && self.has_blame_entries(cx)
19593    }
19594
19595    fn has_blame_entries(&self, cx: &App) -> bool {
19596        self.blame()
19597            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19598    }
19599
19600    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19601        let cursor_anchor = self.selections.newest_anchor().head();
19602
19603        let snapshot = self.buffer.read(cx).snapshot(cx);
19604        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19605
19606        snapshot.line_len(buffer_row) == 0
19607    }
19608
19609    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19610        let buffer_and_selection = maybe!({
19611            let selection = self.selections.newest::<Point>(cx);
19612            let selection_range = selection.range();
19613
19614            let multi_buffer = self.buffer().read(cx);
19615            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19616            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19617
19618            let (buffer, range, _) = if selection.reversed {
19619                buffer_ranges.first()
19620            } else {
19621                buffer_ranges.last()
19622            }?;
19623
19624            let selection = text::ToPoint::to_point(&range.start, buffer).row
19625                ..text::ToPoint::to_point(&range.end, buffer).row;
19626            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19627        });
19628
19629        let Some((buffer, selection)) = buffer_and_selection else {
19630            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19631        };
19632
19633        let Some(project) = self.project() else {
19634            return Task::ready(Err(anyhow!("editor does not have project")));
19635        };
19636
19637        project.update(cx, |project, cx| {
19638            project.get_permalink_to_line(&buffer, selection, cx)
19639        })
19640    }
19641
19642    pub fn copy_permalink_to_line(
19643        &mut self,
19644        _: &CopyPermalinkToLine,
19645        window: &mut Window,
19646        cx: &mut Context<Self>,
19647    ) {
19648        let permalink_task = self.get_permalink_to_line(cx);
19649        let workspace = self.workspace();
19650
19651        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19652            Ok(permalink) => {
19653                cx.update(|_, cx| {
19654                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19655                })
19656                .ok();
19657            }
19658            Err(err) => {
19659                let message = format!("Failed to copy permalink: {err}");
19660
19661                anyhow::Result::<()>::Err(err).log_err();
19662
19663                if let Some(workspace) = workspace {
19664                    workspace
19665                        .update_in(cx, |workspace, _, cx| {
19666                            struct CopyPermalinkToLine;
19667
19668                            workspace.show_toast(
19669                                Toast::new(
19670                                    NotificationId::unique::<CopyPermalinkToLine>(),
19671                                    message,
19672                                ),
19673                                cx,
19674                            )
19675                        })
19676                        .ok();
19677                }
19678            }
19679        })
19680        .detach();
19681    }
19682
19683    pub fn copy_file_location(
19684        &mut self,
19685        _: &CopyFileLocation,
19686        _: &mut Window,
19687        cx: &mut Context<Self>,
19688    ) {
19689        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19690        if let Some(file) = self.target_file(cx)
19691            && let Some(path) = file.path().to_str()
19692        {
19693            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19694        }
19695    }
19696
19697    pub fn open_permalink_to_line(
19698        &mut self,
19699        _: &OpenPermalinkToLine,
19700        window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        let permalink_task = self.get_permalink_to_line(cx);
19704        let workspace = self.workspace();
19705
19706        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19707            Ok(permalink) => {
19708                cx.update(|_, cx| {
19709                    cx.open_url(permalink.as_ref());
19710                })
19711                .ok();
19712            }
19713            Err(err) => {
19714                let message = format!("Failed to open permalink: {err}");
19715
19716                anyhow::Result::<()>::Err(err).log_err();
19717
19718                if let Some(workspace) = workspace {
19719                    workspace
19720                        .update(cx, |workspace, cx| {
19721                            struct OpenPermalinkToLine;
19722
19723                            workspace.show_toast(
19724                                Toast::new(
19725                                    NotificationId::unique::<OpenPermalinkToLine>(),
19726                                    message,
19727                                ),
19728                                cx,
19729                            )
19730                        })
19731                        .ok();
19732                }
19733            }
19734        })
19735        .detach();
19736    }
19737
19738    pub fn insert_uuid_v4(
19739        &mut self,
19740        _: &InsertUuidV4,
19741        window: &mut Window,
19742        cx: &mut Context<Self>,
19743    ) {
19744        self.insert_uuid(UuidVersion::V4, window, cx);
19745    }
19746
19747    pub fn insert_uuid_v7(
19748        &mut self,
19749        _: &InsertUuidV7,
19750        window: &mut Window,
19751        cx: &mut Context<Self>,
19752    ) {
19753        self.insert_uuid(UuidVersion::V7, window, cx);
19754    }
19755
19756    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19758        self.transact(window, cx, |this, window, cx| {
19759            let edits = this
19760                .selections
19761                .all::<Point>(cx)
19762                .into_iter()
19763                .map(|selection| {
19764                    let uuid = match version {
19765                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19766                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19767                    };
19768
19769                    (selection.range(), uuid.to_string())
19770                });
19771            this.edit(edits, cx);
19772            this.refresh_edit_prediction(true, false, window, cx);
19773        });
19774    }
19775
19776    pub fn open_selections_in_multibuffer(
19777        &mut self,
19778        _: &OpenSelectionsInMultibuffer,
19779        window: &mut Window,
19780        cx: &mut Context<Self>,
19781    ) {
19782        let multibuffer = self.buffer.read(cx);
19783
19784        let Some(buffer) = multibuffer.as_singleton() else {
19785            return;
19786        };
19787
19788        let Some(workspace) = self.workspace() else {
19789            return;
19790        };
19791
19792        let title = multibuffer.title(cx).to_string();
19793
19794        let locations = self
19795            .selections
19796            .all_anchors(cx)
19797            .iter()
19798            .map(|selection| {
19799                (
19800                    buffer.clone(),
19801                    (selection.start.text_anchor..selection.end.text_anchor)
19802                        .to_point(buffer.read(cx)),
19803                )
19804            })
19805            .into_group_map();
19806
19807        cx.spawn_in(window, async move |_, cx| {
19808            workspace.update_in(cx, |workspace, window, cx| {
19809                Self::open_locations_in_multibuffer(
19810                    workspace,
19811                    locations,
19812                    format!("Selections for '{title}'"),
19813                    false,
19814                    MultibufferSelectionMode::All,
19815                    window,
19816                    cx,
19817                );
19818            })
19819        })
19820        .detach();
19821    }
19822
19823    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19824    /// last highlight added will be used.
19825    ///
19826    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19827    pub fn highlight_rows<T: 'static>(
19828        &mut self,
19829        range: Range<Anchor>,
19830        color: Hsla,
19831        options: RowHighlightOptions,
19832        cx: &mut Context<Self>,
19833    ) {
19834        let snapshot = self.buffer().read(cx).snapshot(cx);
19835        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19836        let ix = row_highlights.binary_search_by(|highlight| {
19837            Ordering::Equal
19838                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19839                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19840        });
19841
19842        if let Err(mut ix) = ix {
19843            let index = post_inc(&mut self.highlight_order);
19844
19845            // If this range intersects with the preceding highlight, then merge it with
19846            // the preceding highlight. Otherwise insert a new highlight.
19847            let mut merged = false;
19848            if ix > 0 {
19849                let prev_highlight = &mut row_highlights[ix - 1];
19850                if prev_highlight
19851                    .range
19852                    .end
19853                    .cmp(&range.start, &snapshot)
19854                    .is_ge()
19855                {
19856                    ix -= 1;
19857                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19858                        prev_highlight.range.end = range.end;
19859                    }
19860                    merged = true;
19861                    prev_highlight.index = index;
19862                    prev_highlight.color = color;
19863                    prev_highlight.options = options;
19864                }
19865            }
19866
19867            if !merged {
19868                row_highlights.insert(
19869                    ix,
19870                    RowHighlight {
19871                        range,
19872                        index,
19873                        color,
19874                        options,
19875                        type_id: TypeId::of::<T>(),
19876                    },
19877                );
19878            }
19879
19880            // If any of the following highlights intersect with this one, merge them.
19881            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19882                let highlight = &row_highlights[ix];
19883                if next_highlight
19884                    .range
19885                    .start
19886                    .cmp(&highlight.range.end, &snapshot)
19887                    .is_le()
19888                {
19889                    if next_highlight
19890                        .range
19891                        .end
19892                        .cmp(&highlight.range.end, &snapshot)
19893                        .is_gt()
19894                    {
19895                        row_highlights[ix].range.end = next_highlight.range.end;
19896                    }
19897                    row_highlights.remove(ix + 1);
19898                } else {
19899                    break;
19900                }
19901            }
19902        }
19903    }
19904
19905    /// Remove any highlighted row ranges of the given type that intersect the
19906    /// given ranges.
19907    pub fn remove_highlighted_rows<T: 'static>(
19908        &mut self,
19909        ranges_to_remove: Vec<Range<Anchor>>,
19910        cx: &mut Context<Self>,
19911    ) {
19912        let snapshot = self.buffer().read(cx).snapshot(cx);
19913        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19914        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19915        row_highlights.retain(|highlight| {
19916            while let Some(range_to_remove) = ranges_to_remove.peek() {
19917                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19918                    Ordering::Less | Ordering::Equal => {
19919                        ranges_to_remove.next();
19920                    }
19921                    Ordering::Greater => {
19922                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19923                            Ordering::Less | Ordering::Equal => {
19924                                return false;
19925                            }
19926                            Ordering::Greater => break,
19927                        }
19928                    }
19929                }
19930            }
19931
19932            true
19933        })
19934    }
19935
19936    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19937    pub fn clear_row_highlights<T: 'static>(&mut self) {
19938        self.highlighted_rows.remove(&TypeId::of::<T>());
19939    }
19940
19941    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19942    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19943        self.highlighted_rows
19944            .get(&TypeId::of::<T>())
19945            .map_or(&[] as &[_], |vec| vec.as_slice())
19946            .iter()
19947            .map(|highlight| (highlight.range.clone(), highlight.color))
19948    }
19949
19950    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19951    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19952    /// Allows to ignore certain kinds of highlights.
19953    pub fn highlighted_display_rows(
19954        &self,
19955        window: &mut Window,
19956        cx: &mut App,
19957    ) -> BTreeMap<DisplayRow, LineHighlight> {
19958        let snapshot = self.snapshot(window, cx);
19959        let mut used_highlight_orders = HashMap::default();
19960        self.highlighted_rows
19961            .iter()
19962            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19963            .fold(
19964                BTreeMap::<DisplayRow, LineHighlight>::new(),
19965                |mut unique_rows, highlight| {
19966                    let start = highlight.range.start.to_display_point(&snapshot);
19967                    let end = highlight.range.end.to_display_point(&snapshot);
19968                    let start_row = start.row().0;
19969                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19970                        && end.column() == 0
19971                    {
19972                        end.row().0.saturating_sub(1)
19973                    } else {
19974                        end.row().0
19975                    };
19976                    for row in start_row..=end_row {
19977                        let used_index =
19978                            used_highlight_orders.entry(row).or_insert(highlight.index);
19979                        if highlight.index >= *used_index {
19980                            *used_index = highlight.index;
19981                            unique_rows.insert(
19982                                DisplayRow(row),
19983                                LineHighlight {
19984                                    include_gutter: highlight.options.include_gutter,
19985                                    border: None,
19986                                    background: highlight.color.into(),
19987                                    type_id: Some(highlight.type_id),
19988                                },
19989                            );
19990                        }
19991                    }
19992                    unique_rows
19993                },
19994            )
19995    }
19996
19997    pub fn highlighted_display_row_for_autoscroll(
19998        &self,
19999        snapshot: &DisplaySnapshot,
20000    ) -> Option<DisplayRow> {
20001        self.highlighted_rows
20002            .values()
20003            .flat_map(|highlighted_rows| highlighted_rows.iter())
20004            .filter_map(|highlight| {
20005                if highlight.options.autoscroll {
20006                    Some(highlight.range.start.to_display_point(snapshot).row())
20007                } else {
20008                    None
20009                }
20010            })
20011            .min()
20012    }
20013
20014    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20015        self.highlight_background::<SearchWithinRange>(
20016            ranges,
20017            |colors| colors.colors().editor_document_highlight_read_background,
20018            cx,
20019        )
20020    }
20021
20022    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20023        self.breadcrumb_header = Some(new_header);
20024    }
20025
20026    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20027        self.clear_background_highlights::<SearchWithinRange>(cx);
20028    }
20029
20030    pub fn highlight_background<T: 'static>(
20031        &mut self,
20032        ranges: &[Range<Anchor>],
20033        color_fetcher: fn(&Theme) -> Hsla,
20034        cx: &mut Context<Self>,
20035    ) {
20036        self.background_highlights.insert(
20037            HighlightKey::Type(TypeId::of::<T>()),
20038            (color_fetcher, Arc::from(ranges)),
20039        );
20040        self.scrollbar_marker_state.dirty = true;
20041        cx.notify();
20042    }
20043
20044    pub fn highlight_background_key<T: 'static>(
20045        &mut self,
20046        key: usize,
20047        ranges: &[Range<Anchor>],
20048        color_fetcher: fn(&Theme) -> Hsla,
20049        cx: &mut Context<Self>,
20050    ) {
20051        self.background_highlights.insert(
20052            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20053            (color_fetcher, Arc::from(ranges)),
20054        );
20055        self.scrollbar_marker_state.dirty = true;
20056        cx.notify();
20057    }
20058
20059    pub fn clear_background_highlights<T: 'static>(
20060        &mut self,
20061        cx: &mut Context<Self>,
20062    ) -> Option<BackgroundHighlight> {
20063        let text_highlights = self
20064            .background_highlights
20065            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20066        if !text_highlights.1.is_empty() {
20067            self.scrollbar_marker_state.dirty = true;
20068            cx.notify();
20069        }
20070        Some(text_highlights)
20071    }
20072
20073    pub fn highlight_gutter<T: 'static>(
20074        &mut self,
20075        ranges: impl Into<Vec<Range<Anchor>>>,
20076        color_fetcher: fn(&App) -> Hsla,
20077        cx: &mut Context<Self>,
20078    ) {
20079        self.gutter_highlights
20080            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20081        cx.notify();
20082    }
20083
20084    pub fn clear_gutter_highlights<T: 'static>(
20085        &mut self,
20086        cx: &mut Context<Self>,
20087    ) -> Option<GutterHighlight> {
20088        cx.notify();
20089        self.gutter_highlights.remove(&TypeId::of::<T>())
20090    }
20091
20092    pub fn insert_gutter_highlight<T: 'static>(
20093        &mut self,
20094        range: Range<Anchor>,
20095        color_fetcher: fn(&App) -> Hsla,
20096        cx: &mut Context<Self>,
20097    ) {
20098        let snapshot = self.buffer().read(cx).snapshot(cx);
20099        let mut highlights = self
20100            .gutter_highlights
20101            .remove(&TypeId::of::<T>())
20102            .map(|(_, highlights)| highlights)
20103            .unwrap_or_default();
20104        let ix = highlights.binary_search_by(|highlight| {
20105            Ordering::Equal
20106                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20107                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20108        });
20109        if let Err(ix) = ix {
20110            highlights.insert(ix, range);
20111        }
20112        self.gutter_highlights
20113            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20114    }
20115
20116    pub fn remove_gutter_highlights<T: 'static>(
20117        &mut self,
20118        ranges_to_remove: Vec<Range<Anchor>>,
20119        cx: &mut Context<Self>,
20120    ) {
20121        let snapshot = self.buffer().read(cx).snapshot(cx);
20122        let Some((color_fetcher, mut gutter_highlights)) =
20123            self.gutter_highlights.remove(&TypeId::of::<T>())
20124        else {
20125            return;
20126        };
20127        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20128        gutter_highlights.retain(|highlight| {
20129            while let Some(range_to_remove) = ranges_to_remove.peek() {
20130                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20131                    Ordering::Less | Ordering::Equal => {
20132                        ranges_to_remove.next();
20133                    }
20134                    Ordering::Greater => {
20135                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20136                            Ordering::Less | Ordering::Equal => {
20137                                return false;
20138                            }
20139                            Ordering::Greater => break,
20140                        }
20141                    }
20142                }
20143            }
20144
20145            true
20146        });
20147        self.gutter_highlights
20148            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20149    }
20150
20151    #[cfg(feature = "test-support")]
20152    pub fn all_text_highlights(
20153        &self,
20154        window: &mut Window,
20155        cx: &mut Context<Self>,
20156    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20157        let snapshot = self.snapshot(window, cx);
20158        self.display_map.update(cx, |display_map, _| {
20159            display_map
20160                .all_text_highlights()
20161                .map(|highlight| {
20162                    let (style, ranges) = highlight.as_ref();
20163                    (
20164                        *style,
20165                        ranges
20166                            .iter()
20167                            .map(|range| range.clone().to_display_points(&snapshot))
20168                            .collect(),
20169                    )
20170                })
20171                .collect()
20172        })
20173    }
20174
20175    #[cfg(feature = "test-support")]
20176    pub fn all_text_background_highlights(
20177        &self,
20178        window: &mut Window,
20179        cx: &mut Context<Self>,
20180    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20181        let snapshot = self.snapshot(window, cx);
20182        let buffer = &snapshot.buffer_snapshot;
20183        let start = buffer.anchor_before(0);
20184        let end = buffer.anchor_after(buffer.len());
20185        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20186    }
20187
20188    #[cfg(any(test, feature = "test-support"))]
20189    pub fn sorted_background_highlights_in_range(
20190        &self,
20191        search_range: Range<Anchor>,
20192        display_snapshot: &DisplaySnapshot,
20193        theme: &Theme,
20194    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20195        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20196        res.sort_by(|a, b| {
20197            a.0.start
20198                .cmp(&b.0.start)
20199                .then_with(|| a.0.end.cmp(&b.0.end))
20200                .then_with(|| a.1.cmp(&b.1))
20201        });
20202        res
20203    }
20204
20205    #[cfg(feature = "test-support")]
20206    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20207        let snapshot = self.buffer().read(cx).snapshot(cx);
20208
20209        let highlights = self
20210            .background_highlights
20211            .get(&HighlightKey::Type(TypeId::of::<
20212                items::BufferSearchHighlights,
20213            >()));
20214
20215        if let Some((_color, ranges)) = highlights {
20216            ranges
20217                .iter()
20218                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20219                .collect_vec()
20220        } else {
20221            vec![]
20222        }
20223    }
20224
20225    fn document_highlights_for_position<'a>(
20226        &'a self,
20227        position: Anchor,
20228        buffer: &'a MultiBufferSnapshot,
20229    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20230        let read_highlights = self
20231            .background_highlights
20232            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20233            .map(|h| &h.1);
20234        let write_highlights = self
20235            .background_highlights
20236            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20237            .map(|h| &h.1);
20238        let left_position = position.bias_left(buffer);
20239        let right_position = position.bias_right(buffer);
20240        read_highlights
20241            .into_iter()
20242            .chain(write_highlights)
20243            .flat_map(move |ranges| {
20244                let start_ix = match ranges.binary_search_by(|probe| {
20245                    let cmp = probe.end.cmp(&left_position, buffer);
20246                    if cmp.is_ge() {
20247                        Ordering::Greater
20248                    } else {
20249                        Ordering::Less
20250                    }
20251                }) {
20252                    Ok(i) | Err(i) => i,
20253                };
20254
20255                ranges[start_ix..]
20256                    .iter()
20257                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20258            })
20259    }
20260
20261    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20262        self.background_highlights
20263            .get(&HighlightKey::Type(TypeId::of::<T>()))
20264            .is_some_and(|(_, highlights)| !highlights.is_empty())
20265    }
20266
20267    /// Returns all background highlights for a given range.
20268    ///
20269    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20270    pub fn background_highlights_in_range(
20271        &self,
20272        search_range: Range<Anchor>,
20273        display_snapshot: &DisplaySnapshot,
20274        theme: &Theme,
20275    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20276        let mut results = Vec::new();
20277        for (color_fetcher, ranges) in self.background_highlights.values() {
20278            let color = color_fetcher(theme);
20279            let start_ix = match ranges.binary_search_by(|probe| {
20280                let cmp = probe
20281                    .end
20282                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20283                if cmp.is_gt() {
20284                    Ordering::Greater
20285                } else {
20286                    Ordering::Less
20287                }
20288            }) {
20289                Ok(i) | Err(i) => i,
20290            };
20291            for range in &ranges[start_ix..] {
20292                if range
20293                    .start
20294                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20295                    .is_ge()
20296                {
20297                    break;
20298                }
20299
20300                let start = range.start.to_display_point(display_snapshot);
20301                let end = range.end.to_display_point(display_snapshot);
20302                results.push((start..end, color))
20303            }
20304        }
20305        results
20306    }
20307
20308    pub fn gutter_highlights_in_range(
20309        &self,
20310        search_range: Range<Anchor>,
20311        display_snapshot: &DisplaySnapshot,
20312        cx: &App,
20313    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20314        let mut results = Vec::new();
20315        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20316            let color = color_fetcher(cx);
20317            let start_ix = match ranges.binary_search_by(|probe| {
20318                let cmp = probe
20319                    .end
20320                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20321                if cmp.is_gt() {
20322                    Ordering::Greater
20323                } else {
20324                    Ordering::Less
20325                }
20326            }) {
20327                Ok(i) | Err(i) => i,
20328            };
20329            for range in &ranges[start_ix..] {
20330                if range
20331                    .start
20332                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20333                    .is_ge()
20334                {
20335                    break;
20336                }
20337
20338                let start = range.start.to_display_point(display_snapshot);
20339                let end = range.end.to_display_point(display_snapshot);
20340                results.push((start..end, color))
20341            }
20342        }
20343        results
20344    }
20345
20346    /// Get the text ranges corresponding to the redaction query
20347    pub fn redacted_ranges(
20348        &self,
20349        search_range: Range<Anchor>,
20350        display_snapshot: &DisplaySnapshot,
20351        cx: &App,
20352    ) -> Vec<Range<DisplayPoint>> {
20353        display_snapshot
20354            .buffer_snapshot
20355            .redacted_ranges(search_range, |file| {
20356                if let Some(file) = file {
20357                    file.is_private()
20358                        && EditorSettings::get(
20359                            Some(SettingsLocation {
20360                                worktree_id: file.worktree_id(cx),
20361                                path: file.path().as_ref(),
20362                            }),
20363                            cx,
20364                        )
20365                        .redact_private_values
20366                } else {
20367                    false
20368                }
20369            })
20370            .map(|range| {
20371                range.start.to_display_point(display_snapshot)
20372                    ..range.end.to_display_point(display_snapshot)
20373            })
20374            .collect()
20375    }
20376
20377    pub fn highlight_text_key<T: 'static>(
20378        &mut self,
20379        key: usize,
20380        ranges: Vec<Range<Anchor>>,
20381        style: HighlightStyle,
20382        cx: &mut Context<Self>,
20383    ) {
20384        self.display_map.update(cx, |map, _| {
20385            map.highlight_text(
20386                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20387                ranges,
20388                style,
20389            );
20390        });
20391        cx.notify();
20392    }
20393
20394    pub fn highlight_text<T: 'static>(
20395        &mut self,
20396        ranges: Vec<Range<Anchor>>,
20397        style: HighlightStyle,
20398        cx: &mut Context<Self>,
20399    ) {
20400        self.display_map.update(cx, |map, _| {
20401            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20402        });
20403        cx.notify();
20404    }
20405
20406    pub(crate) fn highlight_inlays<T: 'static>(
20407        &mut self,
20408        highlights: Vec<InlayHighlight>,
20409        style: HighlightStyle,
20410        cx: &mut Context<Self>,
20411    ) {
20412        self.display_map.update(cx, |map, _| {
20413            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20414        });
20415        cx.notify();
20416    }
20417
20418    pub fn text_highlights<'a, T: 'static>(
20419        &'a self,
20420        cx: &'a App,
20421    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20422        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20423    }
20424
20425    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20426        let cleared = self
20427            .display_map
20428            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20429        if cleared {
20430            cx.notify();
20431        }
20432    }
20433
20434    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20435        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20436            && self.focus_handle.is_focused(window)
20437    }
20438
20439    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20440        self.show_cursor_when_unfocused = is_enabled;
20441        cx.notify();
20442    }
20443
20444    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20445        cx.notify();
20446    }
20447
20448    fn on_debug_session_event(
20449        &mut self,
20450        _session: Entity<Session>,
20451        event: &SessionEvent,
20452        cx: &mut Context<Self>,
20453    ) {
20454        if let SessionEvent::InvalidateInlineValue = event {
20455            self.refresh_inline_values(cx);
20456        }
20457    }
20458
20459    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20460        let Some(project) = self.project.clone() else {
20461            return;
20462        };
20463
20464        if !self.inline_value_cache.enabled {
20465            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20466            self.splice_inlays(&inlays, Vec::new(), cx);
20467            return;
20468        }
20469
20470        let current_execution_position = self
20471            .highlighted_rows
20472            .get(&TypeId::of::<ActiveDebugLine>())
20473            .and_then(|lines| lines.last().map(|line| line.range.end));
20474
20475        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20476            let inline_values = editor
20477                .update(cx, |editor, cx| {
20478                    let Some(current_execution_position) = current_execution_position else {
20479                        return Some(Task::ready(Ok(Vec::new())));
20480                    };
20481
20482                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20483                        let snapshot = buffer.snapshot(cx);
20484
20485                        let excerpt = snapshot.excerpt_containing(
20486                            current_execution_position..current_execution_position,
20487                        )?;
20488
20489                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20490                    })?;
20491
20492                    let range =
20493                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20494
20495                    project.inline_values(buffer, range, cx)
20496                })
20497                .ok()
20498                .flatten()?
20499                .await
20500                .context("refreshing debugger inlays")
20501                .log_err()?;
20502
20503            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20504
20505            for (buffer_id, inline_value) in inline_values
20506                .into_iter()
20507                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20508            {
20509                buffer_inline_values
20510                    .entry(buffer_id)
20511                    .or_default()
20512                    .push(inline_value);
20513            }
20514
20515            editor
20516                .update(cx, |editor, cx| {
20517                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20518                    let mut new_inlays = Vec::default();
20519
20520                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20521                        let buffer_id = buffer_snapshot.remote_id();
20522                        buffer_inline_values
20523                            .get(&buffer_id)
20524                            .into_iter()
20525                            .flatten()
20526                            .for_each(|hint| {
20527                                let inlay = Inlay::debugger(
20528                                    post_inc(&mut editor.next_inlay_id),
20529                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20530                                    hint.text(),
20531                                );
20532                                if !inlay.text.chars().contains(&'\n') {
20533                                    new_inlays.push(inlay);
20534                                }
20535                            });
20536                    }
20537
20538                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20539                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20540
20541                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20542                })
20543                .ok()?;
20544            Some(())
20545        });
20546    }
20547
20548    fn on_buffer_event(
20549        &mut self,
20550        multibuffer: &Entity<MultiBuffer>,
20551        event: &multi_buffer::Event,
20552        window: &mut Window,
20553        cx: &mut Context<Self>,
20554    ) {
20555        match event {
20556            multi_buffer::Event::Edited {
20557                singleton_buffer_edited,
20558                edited_buffer,
20559            } => {
20560                self.scrollbar_marker_state.dirty = true;
20561                self.active_indent_guides_state.dirty = true;
20562                self.refresh_active_diagnostics(cx);
20563                self.refresh_code_actions(window, cx);
20564                self.refresh_selected_text_highlights(true, window, cx);
20565                self.refresh_single_line_folds(window, cx);
20566                refresh_matching_bracket_highlights(self, window, cx);
20567                if self.has_active_edit_prediction() {
20568                    self.update_visible_edit_prediction(window, cx);
20569                }
20570                if let Some(project) = self.project.as_ref()
20571                    && let Some(edited_buffer) = edited_buffer
20572                {
20573                    project.update(cx, |project, cx| {
20574                        self.registered_buffers
20575                            .entry(edited_buffer.read(cx).remote_id())
20576                            .or_insert_with(|| {
20577                                project.register_buffer_with_language_servers(edited_buffer, cx)
20578                            });
20579                    });
20580                }
20581                cx.emit(EditorEvent::BufferEdited);
20582                cx.emit(SearchEvent::MatchesInvalidated);
20583
20584                if let Some(buffer) = edited_buffer {
20585                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20586                }
20587
20588                if *singleton_buffer_edited {
20589                    if let Some(buffer) = edited_buffer
20590                        && buffer.read(cx).file().is_none()
20591                    {
20592                        cx.emit(EditorEvent::TitleChanged);
20593                    }
20594                    if let Some(project) = &self.project {
20595                        #[allow(clippy::mutable_key_type)]
20596                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20597                            multibuffer
20598                                .all_buffers()
20599                                .into_iter()
20600                                .filter_map(|buffer| {
20601                                    buffer.update(cx, |buffer, cx| {
20602                                        let language = buffer.language()?;
20603                                        let should_discard = project.update(cx, |project, cx| {
20604                                            project.is_local()
20605                                                && !project.has_language_servers_for(buffer, cx)
20606                                        });
20607                                        should_discard.not().then_some(language.clone())
20608                                    })
20609                                })
20610                                .collect::<HashSet<_>>()
20611                        });
20612                        if !languages_affected.is_empty() {
20613                            self.refresh_inlay_hints(
20614                                InlayHintRefreshReason::BufferEdited(languages_affected),
20615                                cx,
20616                            );
20617                        }
20618                    }
20619                }
20620
20621                let Some(project) = &self.project else { return };
20622                let (telemetry, is_via_ssh) = {
20623                    let project = project.read(cx);
20624                    let telemetry = project.client().telemetry().clone();
20625                    let is_via_ssh = project.is_via_remote_server();
20626                    (telemetry, is_via_ssh)
20627                };
20628                refresh_linked_ranges(self, window, cx);
20629                telemetry.log_edit_event("editor", is_via_ssh);
20630            }
20631            multi_buffer::Event::ExcerptsAdded {
20632                buffer,
20633                predecessor,
20634                excerpts,
20635            } => {
20636                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20637                let buffer_id = buffer.read(cx).remote_id();
20638                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20639                    && let Some(project) = &self.project
20640                {
20641                    update_uncommitted_diff_for_buffer(
20642                        cx.entity(),
20643                        project,
20644                        [buffer.clone()],
20645                        self.buffer.clone(),
20646                        cx,
20647                    )
20648                    .detach();
20649                }
20650                if self.active_diagnostics != ActiveDiagnostic::All {
20651                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20652                }
20653                cx.emit(EditorEvent::ExcerptsAdded {
20654                    buffer: buffer.clone(),
20655                    predecessor: *predecessor,
20656                    excerpts: excerpts.clone(),
20657                });
20658                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20659            }
20660            multi_buffer::Event::ExcerptsRemoved {
20661                ids,
20662                removed_buffer_ids,
20663            } => {
20664                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20665                let buffer = self.buffer.read(cx);
20666                self.registered_buffers
20667                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20668                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20669                cx.emit(EditorEvent::ExcerptsRemoved {
20670                    ids: ids.clone(),
20671                    removed_buffer_ids: removed_buffer_ids.clone(),
20672                });
20673            }
20674            multi_buffer::Event::ExcerptsEdited {
20675                excerpt_ids,
20676                buffer_ids,
20677            } => {
20678                self.display_map.update(cx, |map, cx| {
20679                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20680                });
20681                cx.emit(EditorEvent::ExcerptsEdited {
20682                    ids: excerpt_ids.clone(),
20683                });
20684            }
20685            multi_buffer::Event::ExcerptsExpanded { ids } => {
20686                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20687                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20688            }
20689            multi_buffer::Event::Reparsed(buffer_id) => {
20690                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20691                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20692
20693                cx.emit(EditorEvent::Reparsed(*buffer_id));
20694            }
20695            multi_buffer::Event::DiffHunksToggled => {
20696                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20697            }
20698            multi_buffer::Event::LanguageChanged(buffer_id) => {
20699                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20700                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20701                cx.emit(EditorEvent::Reparsed(*buffer_id));
20702                cx.notify();
20703            }
20704            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20705            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20706            multi_buffer::Event::FileHandleChanged
20707            | multi_buffer::Event::Reloaded
20708            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20709            multi_buffer::Event::DiagnosticsUpdated => {
20710                self.update_diagnostics_state(window, cx);
20711            }
20712            _ => {}
20713        };
20714    }
20715
20716    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20717        if !self.diagnostics_enabled() {
20718            return;
20719        }
20720        self.refresh_active_diagnostics(cx);
20721        self.refresh_inline_diagnostics(true, window, cx);
20722        self.scrollbar_marker_state.dirty = true;
20723        cx.notify();
20724    }
20725
20726    pub fn start_temporary_diff_override(&mut self) {
20727        self.load_diff_task.take();
20728        self.temporary_diff_override = true;
20729    }
20730
20731    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20732        self.temporary_diff_override = false;
20733        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20734        self.buffer.update(cx, |buffer, cx| {
20735            buffer.set_all_diff_hunks_collapsed(cx);
20736        });
20737
20738        if let Some(project) = self.project.clone() {
20739            self.load_diff_task = Some(
20740                update_uncommitted_diff_for_buffer(
20741                    cx.entity(),
20742                    &project,
20743                    self.buffer.read(cx).all_buffers(),
20744                    self.buffer.clone(),
20745                    cx,
20746                )
20747                .shared(),
20748            );
20749        }
20750    }
20751
20752    fn on_display_map_changed(
20753        &mut self,
20754        _: Entity<DisplayMap>,
20755        _: &mut Window,
20756        cx: &mut Context<Self>,
20757    ) {
20758        cx.notify();
20759    }
20760
20761    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20762        if self.diagnostics_enabled() {
20763            let new_severity = EditorSettings::get_global(cx)
20764                .diagnostics_max_severity
20765                .unwrap_or(DiagnosticSeverity::Hint);
20766            self.set_max_diagnostics_severity(new_severity, cx);
20767        }
20768        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20769        self.update_edit_prediction_settings(cx);
20770        self.refresh_edit_prediction(true, false, window, cx);
20771        self.refresh_inline_values(cx);
20772        self.refresh_inlay_hints(
20773            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20774                self.selections.newest_anchor().head(),
20775                &self.buffer.read(cx).snapshot(cx),
20776                cx,
20777            )),
20778            cx,
20779        );
20780
20781        let old_cursor_shape = self.cursor_shape;
20782        let old_show_breadcrumbs = self.show_breadcrumbs;
20783
20784        {
20785            let editor_settings = EditorSettings::get_global(cx);
20786            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20787            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20788            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20789            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20790        }
20791
20792        if old_cursor_shape != self.cursor_shape {
20793            cx.emit(EditorEvent::CursorShapeChanged);
20794        }
20795
20796        if old_show_breadcrumbs != self.show_breadcrumbs {
20797            cx.emit(EditorEvent::BreadcrumbsChanged);
20798        }
20799
20800        let project_settings = ProjectSettings::get_global(cx);
20801        self.serialize_dirty_buffers =
20802            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20803
20804        if self.mode.is_full() {
20805            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20806            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20807            if self.show_inline_diagnostics != show_inline_diagnostics {
20808                self.show_inline_diagnostics = show_inline_diagnostics;
20809                self.refresh_inline_diagnostics(false, window, cx);
20810            }
20811
20812            if self.git_blame_inline_enabled != inline_blame_enabled {
20813                self.toggle_git_blame_inline_internal(false, window, cx);
20814            }
20815
20816            let minimap_settings = EditorSettings::get_global(cx).minimap;
20817            if self.minimap_visibility != MinimapVisibility::Disabled {
20818                if self.minimap_visibility.settings_visibility()
20819                    != minimap_settings.minimap_enabled()
20820                {
20821                    self.set_minimap_visibility(
20822                        MinimapVisibility::for_mode(self.mode(), cx),
20823                        window,
20824                        cx,
20825                    );
20826                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20827                    minimap_entity.update(cx, |minimap_editor, cx| {
20828                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20829                    })
20830                }
20831            }
20832        }
20833
20834        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20835            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20836        }) {
20837            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20838                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20839            }
20840            self.refresh_colors(false, None, window, cx);
20841        }
20842
20843        cx.notify();
20844    }
20845
20846    pub fn set_searchable(&mut self, searchable: bool) {
20847        self.searchable = searchable;
20848    }
20849
20850    pub fn searchable(&self) -> bool {
20851        self.searchable
20852    }
20853
20854    fn open_proposed_changes_editor(
20855        &mut self,
20856        _: &OpenProposedChangesEditor,
20857        window: &mut Window,
20858        cx: &mut Context<Self>,
20859    ) {
20860        let Some(workspace) = self.workspace() else {
20861            cx.propagate();
20862            return;
20863        };
20864
20865        let selections = self.selections.all::<usize>(cx);
20866        let multi_buffer = self.buffer.read(cx);
20867        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20868        let mut new_selections_by_buffer = HashMap::default();
20869        for selection in selections {
20870            for (buffer, range, _) in
20871                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20872            {
20873                let mut range = range.to_point(buffer);
20874                range.start.column = 0;
20875                range.end.column = buffer.line_len(range.end.row);
20876                new_selections_by_buffer
20877                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20878                    .or_insert(Vec::new())
20879                    .push(range)
20880            }
20881        }
20882
20883        let proposed_changes_buffers = new_selections_by_buffer
20884            .into_iter()
20885            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20886            .collect::<Vec<_>>();
20887        let proposed_changes_editor = cx.new(|cx| {
20888            ProposedChangesEditor::new(
20889                "Proposed changes",
20890                proposed_changes_buffers,
20891                self.project.clone(),
20892                window,
20893                cx,
20894            )
20895        });
20896
20897        window.defer(cx, move |window, cx| {
20898            workspace.update(cx, |workspace, cx| {
20899                workspace.active_pane().update(cx, |pane, cx| {
20900                    pane.add_item(
20901                        Box::new(proposed_changes_editor),
20902                        true,
20903                        true,
20904                        None,
20905                        window,
20906                        cx,
20907                    );
20908                });
20909            });
20910        });
20911    }
20912
20913    pub fn open_excerpts_in_split(
20914        &mut self,
20915        _: &OpenExcerptsSplit,
20916        window: &mut Window,
20917        cx: &mut Context<Self>,
20918    ) {
20919        self.open_excerpts_common(None, true, window, cx)
20920    }
20921
20922    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20923        self.open_excerpts_common(None, false, window, cx)
20924    }
20925
20926    fn open_excerpts_common(
20927        &mut self,
20928        jump_data: Option<JumpData>,
20929        split: bool,
20930        window: &mut Window,
20931        cx: &mut Context<Self>,
20932    ) {
20933        let Some(workspace) = self.workspace() else {
20934            cx.propagate();
20935            return;
20936        };
20937
20938        if self.buffer.read(cx).is_singleton() {
20939            cx.propagate();
20940            return;
20941        }
20942
20943        let mut new_selections_by_buffer = HashMap::default();
20944        match &jump_data {
20945            Some(JumpData::MultiBufferPoint {
20946                excerpt_id,
20947                position,
20948                anchor,
20949                line_offset_from_top,
20950            }) => {
20951                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20952                if let Some(buffer) = multi_buffer_snapshot
20953                    .buffer_id_for_excerpt(*excerpt_id)
20954                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20955                {
20956                    let buffer_snapshot = buffer.read(cx).snapshot();
20957                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20958                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20959                    } else {
20960                        buffer_snapshot.clip_point(*position, Bias::Left)
20961                    };
20962                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20963                    new_selections_by_buffer.insert(
20964                        buffer,
20965                        (
20966                            vec![jump_to_offset..jump_to_offset],
20967                            Some(*line_offset_from_top),
20968                        ),
20969                    );
20970                }
20971            }
20972            Some(JumpData::MultiBufferRow {
20973                row,
20974                line_offset_from_top,
20975            }) => {
20976                let point = MultiBufferPoint::new(row.0, 0);
20977                if let Some((buffer, buffer_point, _)) =
20978                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20979                {
20980                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20981                    new_selections_by_buffer
20982                        .entry(buffer)
20983                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20984                        .0
20985                        .push(buffer_offset..buffer_offset)
20986                }
20987            }
20988            None => {
20989                let selections = self.selections.all::<usize>(cx);
20990                let multi_buffer = self.buffer.read(cx);
20991                for selection in selections {
20992                    for (snapshot, range, _, anchor) in multi_buffer
20993                        .snapshot(cx)
20994                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20995                    {
20996                        if let Some(anchor) = anchor {
20997                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20998                            else {
20999                                continue;
21000                            };
21001                            let offset = text::ToOffset::to_offset(
21002                                &anchor.text_anchor,
21003                                &buffer_handle.read(cx).snapshot(),
21004                            );
21005                            let range = offset..offset;
21006                            new_selections_by_buffer
21007                                .entry(buffer_handle)
21008                                .or_insert((Vec::new(), None))
21009                                .0
21010                                .push(range)
21011                        } else {
21012                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21013                            else {
21014                                continue;
21015                            };
21016                            new_selections_by_buffer
21017                                .entry(buffer_handle)
21018                                .or_insert((Vec::new(), None))
21019                                .0
21020                                .push(range)
21021                        }
21022                    }
21023                }
21024            }
21025        }
21026
21027        new_selections_by_buffer
21028            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21029
21030        if new_selections_by_buffer.is_empty() {
21031            return;
21032        }
21033
21034        // We defer the pane interaction because we ourselves are a workspace item
21035        // and activating a new item causes the pane to call a method on us reentrantly,
21036        // which panics if we're on the stack.
21037        window.defer(cx, move |window, cx| {
21038            workspace.update(cx, |workspace, cx| {
21039                let pane = if split {
21040                    workspace.adjacent_pane(window, cx)
21041                } else {
21042                    workspace.active_pane().clone()
21043                };
21044
21045                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21046                    let editor = buffer
21047                        .read(cx)
21048                        .file()
21049                        .is_none()
21050                        .then(|| {
21051                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21052                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21053                            // Instead, we try to activate the existing editor in the pane first.
21054                            let (editor, pane_item_index) =
21055                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21056                                    let editor = item.downcast::<Editor>()?;
21057                                    let singleton_buffer =
21058                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21059                                    if singleton_buffer == buffer {
21060                                        Some((editor, i))
21061                                    } else {
21062                                        None
21063                                    }
21064                                })?;
21065                            pane.update(cx, |pane, cx| {
21066                                pane.activate_item(pane_item_index, true, true, window, cx)
21067                            });
21068                            Some(editor)
21069                        })
21070                        .flatten()
21071                        .unwrap_or_else(|| {
21072                            workspace.open_project_item::<Self>(
21073                                pane.clone(),
21074                                buffer,
21075                                true,
21076                                true,
21077                                window,
21078                                cx,
21079                            )
21080                        });
21081
21082                    editor.update(cx, |editor, cx| {
21083                        let autoscroll = match scroll_offset {
21084                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21085                            None => Autoscroll::newest(),
21086                        };
21087                        let nav_history = editor.nav_history.take();
21088                        editor.change_selections(
21089                            SelectionEffects::scroll(autoscroll),
21090                            window,
21091                            cx,
21092                            |s| {
21093                                s.select_ranges(ranges);
21094                            },
21095                        );
21096                        editor.nav_history = nav_history;
21097                    });
21098                }
21099            })
21100        });
21101    }
21102
21103    // For now, don't allow opening excerpts in buffers that aren't backed by
21104    // regular project files.
21105    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21106        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21107    }
21108
21109    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21110        let snapshot = self.buffer.read(cx).read(cx);
21111        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21112        Some(
21113            ranges
21114                .iter()
21115                .map(move |range| {
21116                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21117                })
21118                .collect(),
21119        )
21120    }
21121
21122    fn selection_replacement_ranges(
21123        &self,
21124        range: Range<OffsetUtf16>,
21125        cx: &mut App,
21126    ) -> Vec<Range<OffsetUtf16>> {
21127        let selections = self.selections.all::<OffsetUtf16>(cx);
21128        let newest_selection = selections
21129            .iter()
21130            .max_by_key(|selection| selection.id)
21131            .unwrap();
21132        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21133        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21134        let snapshot = self.buffer.read(cx).read(cx);
21135        selections
21136            .into_iter()
21137            .map(|mut selection| {
21138                selection.start.0 =
21139                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21140                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21141                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21142                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21143            })
21144            .collect()
21145    }
21146
21147    fn report_editor_event(
21148        &self,
21149        reported_event: ReportEditorEvent,
21150        file_extension: Option<String>,
21151        cx: &App,
21152    ) {
21153        if cfg!(any(test, feature = "test-support")) {
21154            return;
21155        }
21156
21157        let Some(project) = &self.project else { return };
21158
21159        // If None, we are in a file without an extension
21160        let file = self
21161            .buffer
21162            .read(cx)
21163            .as_singleton()
21164            .and_then(|b| b.read(cx).file());
21165        let file_extension = file_extension.or(file
21166            .as_ref()
21167            .and_then(|file| Path::new(file.file_name(cx)).extension())
21168            .and_then(|e| e.to_str())
21169            .map(|a| a.to_string()));
21170
21171        let vim_mode = vim_enabled(cx);
21172
21173        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21174        let copilot_enabled = edit_predictions_provider
21175            == language::language_settings::EditPredictionProvider::Copilot;
21176        let copilot_enabled_for_language = self
21177            .buffer
21178            .read(cx)
21179            .language_settings(cx)
21180            .show_edit_predictions;
21181
21182        let project = project.read(cx);
21183        let event_type = reported_event.event_type();
21184
21185        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21186            telemetry::event!(
21187                event_type,
21188                type = if auto_saved {"autosave"} else {"manual"},
21189                file_extension,
21190                vim_mode,
21191                copilot_enabled,
21192                copilot_enabled_for_language,
21193                edit_predictions_provider,
21194                is_via_ssh = project.is_via_remote_server(),
21195            );
21196        } else {
21197            telemetry::event!(
21198                event_type,
21199                file_extension,
21200                vim_mode,
21201                copilot_enabled,
21202                copilot_enabled_for_language,
21203                edit_predictions_provider,
21204                is_via_ssh = project.is_via_remote_server(),
21205            );
21206        };
21207    }
21208
21209    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21210    /// with each line being an array of {text, highlight} objects.
21211    fn copy_highlight_json(
21212        &mut self,
21213        _: &CopyHighlightJson,
21214        window: &mut Window,
21215        cx: &mut Context<Self>,
21216    ) {
21217        #[derive(Serialize)]
21218        struct Chunk<'a> {
21219            text: String,
21220            highlight: Option<&'a str>,
21221        }
21222
21223        let snapshot = self.buffer.read(cx).snapshot(cx);
21224        let range = self
21225            .selected_text_range(false, window, cx)
21226            .and_then(|selection| {
21227                if selection.range.is_empty() {
21228                    None
21229                } else {
21230                    Some(selection.range)
21231                }
21232            })
21233            .unwrap_or_else(|| 0..snapshot.len());
21234
21235        let chunks = snapshot.chunks(range, true);
21236        let mut lines = Vec::new();
21237        let mut line: VecDeque<Chunk> = VecDeque::new();
21238
21239        let Some(style) = self.style.as_ref() else {
21240            return;
21241        };
21242
21243        for chunk in chunks {
21244            let highlight = chunk
21245                .syntax_highlight_id
21246                .and_then(|id| id.name(&style.syntax));
21247            let mut chunk_lines = chunk.text.split('\n').peekable();
21248            while let Some(text) = chunk_lines.next() {
21249                let mut merged_with_last_token = false;
21250                if let Some(last_token) = line.back_mut()
21251                    && last_token.highlight == highlight
21252                {
21253                    last_token.text.push_str(text);
21254                    merged_with_last_token = true;
21255                }
21256
21257                if !merged_with_last_token {
21258                    line.push_back(Chunk {
21259                        text: text.into(),
21260                        highlight,
21261                    });
21262                }
21263
21264                if chunk_lines.peek().is_some() {
21265                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21266                        line.pop_front();
21267                    }
21268                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21269                        line.pop_back();
21270                    }
21271
21272                    lines.push(mem::take(&mut line));
21273                }
21274            }
21275        }
21276
21277        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21278            return;
21279        };
21280        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21281    }
21282
21283    pub fn open_context_menu(
21284        &mut self,
21285        _: &OpenContextMenu,
21286        window: &mut Window,
21287        cx: &mut Context<Self>,
21288    ) {
21289        self.request_autoscroll(Autoscroll::newest(), cx);
21290        let position = self.selections.newest_display(cx).start;
21291        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21292    }
21293
21294    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21295        &self.inlay_hint_cache
21296    }
21297
21298    pub fn replay_insert_event(
21299        &mut self,
21300        text: &str,
21301        relative_utf16_range: Option<Range<isize>>,
21302        window: &mut Window,
21303        cx: &mut Context<Self>,
21304    ) {
21305        if !self.input_enabled {
21306            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21307            return;
21308        }
21309        if let Some(relative_utf16_range) = relative_utf16_range {
21310            let selections = self.selections.all::<OffsetUtf16>(cx);
21311            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21312                let new_ranges = selections.into_iter().map(|range| {
21313                    let start = OffsetUtf16(
21314                        range
21315                            .head()
21316                            .0
21317                            .saturating_add_signed(relative_utf16_range.start),
21318                    );
21319                    let end = OffsetUtf16(
21320                        range
21321                            .head()
21322                            .0
21323                            .saturating_add_signed(relative_utf16_range.end),
21324                    );
21325                    start..end
21326                });
21327                s.select_ranges(new_ranges);
21328            });
21329        }
21330
21331        self.handle_input(text, window, cx);
21332    }
21333
21334    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21335        let Some(provider) = self.semantics_provider.as_ref() else {
21336            return false;
21337        };
21338
21339        let mut supports = false;
21340        self.buffer().update(cx, |this, cx| {
21341            this.for_each_buffer(|buffer| {
21342                supports |= provider.supports_inlay_hints(buffer, cx);
21343            });
21344        });
21345
21346        supports
21347    }
21348
21349    pub fn is_focused(&self, window: &Window) -> bool {
21350        self.focus_handle.is_focused(window)
21351    }
21352
21353    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21354        cx.emit(EditorEvent::Focused);
21355
21356        if let Some(descendant) = self
21357            .last_focused_descendant
21358            .take()
21359            .and_then(|descendant| descendant.upgrade())
21360        {
21361            window.focus(&descendant);
21362        } else {
21363            if let Some(blame) = self.blame.as_ref() {
21364                blame.update(cx, GitBlame::focus)
21365            }
21366
21367            self.blink_manager.update(cx, BlinkManager::enable);
21368            self.show_cursor_names(window, cx);
21369            self.buffer.update(cx, |buffer, cx| {
21370                buffer.finalize_last_transaction(cx);
21371                if self.leader_id.is_none() {
21372                    buffer.set_active_selections(
21373                        &self.selections.disjoint_anchors_arc(),
21374                        self.selections.line_mode,
21375                        self.cursor_shape,
21376                        cx,
21377                    );
21378                }
21379            });
21380        }
21381    }
21382
21383    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21384        cx.emit(EditorEvent::FocusedIn)
21385    }
21386
21387    fn handle_focus_out(
21388        &mut self,
21389        event: FocusOutEvent,
21390        _window: &mut Window,
21391        cx: &mut Context<Self>,
21392    ) {
21393        if event.blurred != self.focus_handle {
21394            self.last_focused_descendant = Some(event.blurred);
21395        }
21396        self.selection_drag_state = SelectionDragState::None;
21397        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21398    }
21399
21400    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21401        self.blink_manager.update(cx, BlinkManager::disable);
21402        self.buffer
21403            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21404
21405        if let Some(blame) = self.blame.as_ref() {
21406            blame.update(cx, GitBlame::blur)
21407        }
21408        if !self.hover_state.focused(window, cx) {
21409            hide_hover(self, cx);
21410        }
21411        if !self
21412            .context_menu
21413            .borrow()
21414            .as_ref()
21415            .is_some_and(|context_menu| context_menu.focused(window, cx))
21416        {
21417            self.hide_context_menu(window, cx);
21418        }
21419        self.discard_edit_prediction(false, cx);
21420        cx.emit(EditorEvent::Blurred);
21421        cx.notify();
21422    }
21423
21424    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21425        let mut pending: String = window
21426            .pending_input_keystrokes()
21427            .into_iter()
21428            .flatten()
21429            .filter_map(|keystroke| {
21430                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21431                    keystroke.key_char.clone()
21432                } else {
21433                    None
21434                }
21435            })
21436            .collect();
21437
21438        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21439            pending = "".to_string();
21440        }
21441
21442        let existing_pending = self
21443            .text_highlights::<PendingInput>(cx)
21444            .map(|(_, ranges)| ranges.to_vec());
21445        if existing_pending.is_none() && pending.is_empty() {
21446            return;
21447        }
21448        let transaction =
21449            self.transact(window, cx, |this, window, cx| {
21450                let selections = this.selections.all::<usize>(cx);
21451                let edits = selections
21452                    .iter()
21453                    .map(|selection| (selection.end..selection.end, pending.clone()));
21454                this.edit(edits, cx);
21455                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21456                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21457                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21458                    }));
21459                });
21460                if let Some(existing_ranges) = existing_pending {
21461                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21462                    this.edit(edits, cx);
21463                }
21464            });
21465
21466        let snapshot = self.snapshot(window, cx);
21467        let ranges = self
21468            .selections
21469            .all::<usize>(cx)
21470            .into_iter()
21471            .map(|selection| {
21472                snapshot.buffer_snapshot.anchor_after(selection.end)
21473                    ..snapshot
21474                        .buffer_snapshot
21475                        .anchor_before(selection.end + pending.len())
21476            })
21477            .collect();
21478
21479        if pending.is_empty() {
21480            self.clear_highlights::<PendingInput>(cx);
21481        } else {
21482            self.highlight_text::<PendingInput>(
21483                ranges,
21484                HighlightStyle {
21485                    underline: Some(UnderlineStyle {
21486                        thickness: px(1.),
21487                        color: None,
21488                        wavy: false,
21489                    }),
21490                    ..Default::default()
21491                },
21492                cx,
21493            );
21494        }
21495
21496        self.ime_transaction = self.ime_transaction.or(transaction);
21497        if let Some(transaction) = self.ime_transaction {
21498            self.buffer.update(cx, |buffer, cx| {
21499                buffer.group_until_transaction(transaction, cx);
21500            });
21501        }
21502
21503        if self.text_highlights::<PendingInput>(cx).is_none() {
21504            self.ime_transaction.take();
21505        }
21506    }
21507
21508    pub fn register_action_renderer(
21509        &mut self,
21510        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21511    ) -> Subscription {
21512        let id = self.next_editor_action_id.post_inc();
21513        self.editor_actions
21514            .borrow_mut()
21515            .insert(id, Box::new(listener));
21516
21517        let editor_actions = self.editor_actions.clone();
21518        Subscription::new(move || {
21519            editor_actions.borrow_mut().remove(&id);
21520        })
21521    }
21522
21523    pub fn register_action<A: Action>(
21524        &mut self,
21525        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21526    ) -> Subscription {
21527        let id = self.next_editor_action_id.post_inc();
21528        let listener = Arc::new(listener);
21529        self.editor_actions.borrow_mut().insert(
21530            id,
21531            Box::new(move |_, window, _| {
21532                let listener = listener.clone();
21533                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21534                    let action = action.downcast_ref().unwrap();
21535                    if phase == DispatchPhase::Bubble {
21536                        listener(action, window, cx)
21537                    }
21538                })
21539            }),
21540        );
21541
21542        let editor_actions = self.editor_actions.clone();
21543        Subscription::new(move || {
21544            editor_actions.borrow_mut().remove(&id);
21545        })
21546    }
21547
21548    pub fn file_header_size(&self) -> u32 {
21549        FILE_HEADER_HEIGHT
21550    }
21551
21552    pub fn restore(
21553        &mut self,
21554        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21555        window: &mut Window,
21556        cx: &mut Context<Self>,
21557    ) {
21558        let workspace = self.workspace();
21559        let project = self.project();
21560        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21561            let mut tasks = Vec::new();
21562            for (buffer_id, changes) in revert_changes {
21563                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21564                    buffer.update(cx, |buffer, cx| {
21565                        buffer.edit(
21566                            changes
21567                                .into_iter()
21568                                .map(|(range, text)| (range, text.to_string())),
21569                            None,
21570                            cx,
21571                        );
21572                    });
21573
21574                    if let Some(project) =
21575                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21576                    {
21577                        project.update(cx, |project, cx| {
21578                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21579                        })
21580                    }
21581                }
21582            }
21583            tasks
21584        });
21585        cx.spawn_in(window, async move |_, cx| {
21586            for (buffer, task) in save_tasks {
21587                let result = task.await;
21588                if result.is_err() {
21589                    let Some(path) = buffer
21590                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21591                        .ok()
21592                    else {
21593                        continue;
21594                    };
21595                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21596                        let Some(task) = cx
21597                            .update_window_entity(workspace, |workspace, window, cx| {
21598                                workspace
21599                                    .open_path_preview(path, None, false, false, false, window, cx)
21600                            })
21601                            .ok()
21602                        else {
21603                            continue;
21604                        };
21605                        task.await.log_err();
21606                    }
21607                }
21608            }
21609        })
21610        .detach();
21611        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21612            selections.refresh()
21613        });
21614    }
21615
21616    pub fn to_pixel_point(
21617        &self,
21618        source: multi_buffer::Anchor,
21619        editor_snapshot: &EditorSnapshot,
21620        window: &mut Window,
21621    ) -> Option<gpui::Point<Pixels>> {
21622        let source_point = source.to_display_point(editor_snapshot);
21623        self.display_to_pixel_point(source_point, editor_snapshot, window)
21624    }
21625
21626    pub fn display_to_pixel_point(
21627        &self,
21628        source: DisplayPoint,
21629        editor_snapshot: &EditorSnapshot,
21630        window: &mut Window,
21631    ) -> Option<gpui::Point<Pixels>> {
21632        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21633        let text_layout_details = self.text_layout_details(window);
21634        let scroll_top = text_layout_details
21635            .scroll_anchor
21636            .scroll_position(editor_snapshot)
21637            .y;
21638
21639        if source.row().as_f32() < scroll_top.floor() {
21640            return None;
21641        }
21642        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21643        let source_y = line_height * (source.row().as_f32() - scroll_top);
21644        Some(gpui::Point::new(source_x, source_y))
21645    }
21646
21647    pub fn has_visible_completions_menu(&self) -> bool {
21648        !self.edit_prediction_preview_is_active()
21649            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21650                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21651            })
21652    }
21653
21654    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21655        if self.mode.is_minimap() {
21656            return;
21657        }
21658        self.addons
21659            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21660    }
21661
21662    pub fn unregister_addon<T: Addon>(&mut self) {
21663        self.addons.remove(&std::any::TypeId::of::<T>());
21664    }
21665
21666    pub fn addon<T: Addon>(&self) -> Option<&T> {
21667        let type_id = std::any::TypeId::of::<T>();
21668        self.addons
21669            .get(&type_id)
21670            .and_then(|item| item.to_any().downcast_ref::<T>())
21671    }
21672
21673    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21674        let type_id = std::any::TypeId::of::<T>();
21675        self.addons
21676            .get_mut(&type_id)
21677            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21678    }
21679
21680    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21681        let text_layout_details = self.text_layout_details(window);
21682        let style = &text_layout_details.editor_style;
21683        let font_id = window.text_system().resolve_font(&style.text.font());
21684        let font_size = style.text.font_size.to_pixels(window.rem_size());
21685        let line_height = style.text.line_height_in_pixels(window.rem_size());
21686        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21687        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21688
21689        CharacterDimensions {
21690            em_width,
21691            em_advance,
21692            line_height,
21693        }
21694    }
21695
21696    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21697        self.load_diff_task.clone()
21698    }
21699
21700    fn read_metadata_from_db(
21701        &mut self,
21702        item_id: u64,
21703        workspace_id: WorkspaceId,
21704        window: &mut Window,
21705        cx: &mut Context<Editor>,
21706    ) {
21707        if self.is_singleton(cx)
21708            && !self.mode.is_minimap()
21709            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21710        {
21711            let buffer_snapshot = OnceCell::new();
21712
21713            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21714                && !folds.is_empty()
21715            {
21716                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21717                self.fold_ranges(
21718                    folds
21719                        .into_iter()
21720                        .map(|(start, end)| {
21721                            snapshot.clip_offset(start, Bias::Left)
21722                                ..snapshot.clip_offset(end, Bias::Right)
21723                        })
21724                        .collect(),
21725                    false,
21726                    window,
21727                    cx,
21728                );
21729            }
21730
21731            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21732                && !selections.is_empty()
21733            {
21734                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21735                // skip adding the initial selection to selection history
21736                self.selection_history.mode = SelectionHistoryMode::Skipping;
21737                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21738                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21739                        snapshot.clip_offset(start, Bias::Left)
21740                            ..snapshot.clip_offset(end, Bias::Right)
21741                    }));
21742                });
21743                self.selection_history.mode = SelectionHistoryMode::Normal;
21744            };
21745        }
21746
21747        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21748    }
21749
21750    fn update_lsp_data(
21751        &mut self,
21752        ignore_cache: bool,
21753        for_buffer: Option<BufferId>,
21754        window: &mut Window,
21755        cx: &mut Context<'_, Self>,
21756    ) {
21757        self.pull_diagnostics(for_buffer, window, cx);
21758        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21759    }
21760}
21761
21762fn edit_for_markdown_paste<'a>(
21763    buffer: &MultiBufferSnapshot,
21764    range: Range<usize>,
21765    to_insert: &'a str,
21766    url: Option<url::Url>,
21767) -> (Range<usize>, Cow<'a, str>) {
21768    if url.is_none() {
21769        return (range, Cow::Borrowed(to_insert));
21770    };
21771
21772    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21773
21774    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21775        Cow::Borrowed(to_insert)
21776    } else {
21777        Cow::Owned(format!("[{old_text}]({to_insert})"))
21778    };
21779    (range, new_text)
21780}
21781
21782fn vim_enabled(cx: &App) -> bool {
21783    vim_mode_setting::VimModeSetting::try_get(cx)
21784        .map(|vim_mode| vim_mode.0)
21785        .unwrap_or(false)
21786}
21787
21788fn process_completion_for_edit(
21789    completion: &Completion,
21790    intent: CompletionIntent,
21791    buffer: &Entity<Buffer>,
21792    cursor_position: &text::Anchor,
21793    cx: &mut Context<Editor>,
21794) -> CompletionEdit {
21795    let buffer = buffer.read(cx);
21796    let buffer_snapshot = buffer.snapshot();
21797    let (snippet, new_text) = if completion.is_snippet() {
21798        // Workaround for typescript language server issues so that methods don't expand within
21799        // strings and functions with type expressions. The previous point is used because the query
21800        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21801        let mut snippet_source = completion.new_text.clone();
21802        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21803        previous_point.column = previous_point.column.saturating_sub(1);
21804        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21805            && scope.prefers_label_for_snippet_in_completion()
21806            && let Some(label) = completion.label()
21807            && matches!(
21808                completion.kind(),
21809                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21810            )
21811        {
21812            snippet_source = label;
21813        }
21814        match Snippet::parse(&snippet_source).log_err() {
21815            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21816            None => (None, completion.new_text.clone()),
21817        }
21818    } else {
21819        (None, completion.new_text.clone())
21820    };
21821
21822    let mut range_to_replace = {
21823        let replace_range = &completion.replace_range;
21824        if let CompletionSource::Lsp {
21825            insert_range: Some(insert_range),
21826            ..
21827        } = &completion.source
21828        {
21829            debug_assert_eq!(
21830                insert_range.start, replace_range.start,
21831                "insert_range and replace_range should start at the same position"
21832            );
21833            debug_assert!(
21834                insert_range
21835                    .start
21836                    .cmp(cursor_position, &buffer_snapshot)
21837                    .is_le(),
21838                "insert_range should start before or at cursor position"
21839            );
21840            debug_assert!(
21841                replace_range
21842                    .start
21843                    .cmp(cursor_position, &buffer_snapshot)
21844                    .is_le(),
21845                "replace_range should start before or at cursor position"
21846            );
21847
21848            let should_replace = match intent {
21849                CompletionIntent::CompleteWithInsert => false,
21850                CompletionIntent::CompleteWithReplace => true,
21851                CompletionIntent::Complete | CompletionIntent::Compose => {
21852                    let insert_mode =
21853                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21854                            .completions
21855                            .lsp_insert_mode;
21856                    match insert_mode {
21857                        LspInsertMode::Insert => false,
21858                        LspInsertMode::Replace => true,
21859                        LspInsertMode::ReplaceSubsequence => {
21860                            let mut text_to_replace = buffer.chars_for_range(
21861                                buffer.anchor_before(replace_range.start)
21862                                    ..buffer.anchor_after(replace_range.end),
21863                            );
21864                            let mut current_needle = text_to_replace.next();
21865                            for haystack_ch in completion.label.text.chars() {
21866                                if let Some(needle_ch) = current_needle
21867                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21868                                {
21869                                    current_needle = text_to_replace.next();
21870                                }
21871                            }
21872                            current_needle.is_none()
21873                        }
21874                        LspInsertMode::ReplaceSuffix => {
21875                            if replace_range
21876                                .end
21877                                .cmp(cursor_position, &buffer_snapshot)
21878                                .is_gt()
21879                            {
21880                                let range_after_cursor = *cursor_position..replace_range.end;
21881                                let text_after_cursor = buffer
21882                                    .text_for_range(
21883                                        buffer.anchor_before(range_after_cursor.start)
21884                                            ..buffer.anchor_after(range_after_cursor.end),
21885                                    )
21886                                    .collect::<String>()
21887                                    .to_ascii_lowercase();
21888                                completion
21889                                    .label
21890                                    .text
21891                                    .to_ascii_lowercase()
21892                                    .ends_with(&text_after_cursor)
21893                            } else {
21894                                true
21895                            }
21896                        }
21897                    }
21898                }
21899            };
21900
21901            if should_replace {
21902                replace_range.clone()
21903            } else {
21904                insert_range.clone()
21905            }
21906        } else {
21907            replace_range.clone()
21908        }
21909    };
21910
21911    if range_to_replace
21912        .end
21913        .cmp(cursor_position, &buffer_snapshot)
21914        .is_lt()
21915    {
21916        range_to_replace.end = *cursor_position;
21917    }
21918
21919    CompletionEdit {
21920        new_text,
21921        replace_range: range_to_replace.to_offset(buffer),
21922        snippet,
21923    }
21924}
21925
21926struct CompletionEdit {
21927    new_text: String,
21928    replace_range: Range<usize>,
21929    snippet: Option<Snippet>,
21930}
21931
21932fn insert_extra_newline_brackets(
21933    buffer: &MultiBufferSnapshot,
21934    range: Range<usize>,
21935    language: &language::LanguageScope,
21936) -> bool {
21937    let leading_whitespace_len = buffer
21938        .reversed_chars_at(range.start)
21939        .take_while(|c| c.is_whitespace() && *c != '\n')
21940        .map(|c| c.len_utf8())
21941        .sum::<usize>();
21942    let trailing_whitespace_len = buffer
21943        .chars_at(range.end)
21944        .take_while(|c| c.is_whitespace() && *c != '\n')
21945        .map(|c| c.len_utf8())
21946        .sum::<usize>();
21947    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21948
21949    language.brackets().any(|(pair, enabled)| {
21950        let pair_start = pair.start.trim_end();
21951        let pair_end = pair.end.trim_start();
21952
21953        enabled
21954            && pair.newline
21955            && buffer.contains_str_at(range.end, pair_end)
21956            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21957    })
21958}
21959
21960fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21961    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21962        [(buffer, range, _)] => (*buffer, range.clone()),
21963        _ => return false,
21964    };
21965    let pair = {
21966        let mut result: Option<BracketMatch> = None;
21967
21968        for pair in buffer
21969            .all_bracket_ranges(range.clone())
21970            .filter(move |pair| {
21971                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21972            })
21973        {
21974            let len = pair.close_range.end - pair.open_range.start;
21975
21976            if let Some(existing) = &result {
21977                let existing_len = existing.close_range.end - existing.open_range.start;
21978                if len > existing_len {
21979                    continue;
21980                }
21981            }
21982
21983            result = Some(pair);
21984        }
21985
21986        result
21987    };
21988    let Some(pair) = pair else {
21989        return false;
21990    };
21991    pair.newline_only
21992        && buffer
21993            .chars_for_range(pair.open_range.end..range.start)
21994            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21995            .all(|c| c.is_whitespace() && c != '\n')
21996}
21997
21998fn update_uncommitted_diff_for_buffer(
21999    editor: Entity<Editor>,
22000    project: &Entity<Project>,
22001    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22002    buffer: Entity<MultiBuffer>,
22003    cx: &mut App,
22004) -> Task<()> {
22005    let mut tasks = Vec::new();
22006    project.update(cx, |project, cx| {
22007        for buffer in buffers {
22008            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22009                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22010            }
22011        }
22012    });
22013    cx.spawn(async move |cx| {
22014        let diffs = future::join_all(tasks).await;
22015        if editor
22016            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22017            .unwrap_or(false)
22018        {
22019            return;
22020        }
22021
22022        buffer
22023            .update(cx, |buffer, cx| {
22024                for diff in diffs.into_iter().flatten() {
22025                    buffer.add_diff(diff, cx);
22026                }
22027            })
22028            .ok();
22029    })
22030}
22031
22032fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22033    let tab_size = tab_size.get() as usize;
22034    let mut width = offset;
22035
22036    for ch in text.chars() {
22037        width += if ch == '\t' {
22038            tab_size - (width % tab_size)
22039        } else {
22040            1
22041        };
22042    }
22043
22044    width - offset
22045}
22046
22047#[cfg(test)]
22048mod tests {
22049    use super::*;
22050
22051    #[test]
22052    fn test_string_size_with_expanded_tabs() {
22053        let nz = |val| NonZeroU32::new(val).unwrap();
22054        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22055        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22056        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22057        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22058        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22059        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22060        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22061        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22062    }
22063}
22064
22065/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22066struct WordBreakingTokenizer<'a> {
22067    input: &'a str,
22068}
22069
22070impl<'a> WordBreakingTokenizer<'a> {
22071    fn new(input: &'a str) -> Self {
22072        Self { input }
22073    }
22074}
22075
22076fn is_char_ideographic(ch: char) -> bool {
22077    use unicode_script::Script::*;
22078    use unicode_script::UnicodeScript;
22079    matches!(ch.script(), Han | Tangut | Yi)
22080}
22081
22082fn is_grapheme_ideographic(text: &str) -> bool {
22083    text.chars().any(is_char_ideographic)
22084}
22085
22086fn is_grapheme_whitespace(text: &str) -> bool {
22087    text.chars().any(|x| x.is_whitespace())
22088}
22089
22090fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22091    text.chars()
22092        .next()
22093        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22094}
22095
22096#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22097enum WordBreakToken<'a> {
22098    Word { token: &'a str, grapheme_len: usize },
22099    InlineWhitespace { token: &'a str, grapheme_len: usize },
22100    Newline,
22101}
22102
22103impl<'a> Iterator for WordBreakingTokenizer<'a> {
22104    /// Yields a span, the count of graphemes in the token, and whether it was
22105    /// whitespace. Note that it also breaks at word boundaries.
22106    type Item = WordBreakToken<'a>;
22107
22108    fn next(&mut self) -> Option<Self::Item> {
22109        use unicode_segmentation::UnicodeSegmentation;
22110        if self.input.is_empty() {
22111            return None;
22112        }
22113
22114        let mut iter = self.input.graphemes(true).peekable();
22115        let mut offset = 0;
22116        let mut grapheme_len = 0;
22117        if let Some(first_grapheme) = iter.next() {
22118            let is_newline = first_grapheme == "\n";
22119            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22120            offset += first_grapheme.len();
22121            grapheme_len += 1;
22122            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22123                if let Some(grapheme) = iter.peek().copied()
22124                    && should_stay_with_preceding_ideograph(grapheme)
22125                {
22126                    offset += grapheme.len();
22127                    grapheme_len += 1;
22128                }
22129            } else {
22130                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22131                let mut next_word_bound = words.peek().copied();
22132                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22133                    next_word_bound = words.next();
22134                }
22135                while let Some(grapheme) = iter.peek().copied() {
22136                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22137                        break;
22138                    };
22139                    if is_grapheme_whitespace(grapheme) != is_whitespace
22140                        || (grapheme == "\n") != is_newline
22141                    {
22142                        break;
22143                    };
22144                    offset += grapheme.len();
22145                    grapheme_len += 1;
22146                    iter.next();
22147                }
22148            }
22149            let token = &self.input[..offset];
22150            self.input = &self.input[offset..];
22151            if token == "\n" {
22152                Some(WordBreakToken::Newline)
22153            } else if is_whitespace {
22154                Some(WordBreakToken::InlineWhitespace {
22155                    token,
22156                    grapheme_len,
22157                })
22158            } else {
22159                Some(WordBreakToken::Word {
22160                    token,
22161                    grapheme_len,
22162                })
22163            }
22164        } else {
22165            None
22166        }
22167    }
22168}
22169
22170#[test]
22171fn test_word_breaking_tokenizer() {
22172    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22173        ("", &[]),
22174        ("  ", &[whitespace("  ", 2)]),
22175        ("Ʒ", &[word("Ʒ", 1)]),
22176        ("Ǽ", &[word("Ǽ", 1)]),
22177        ("", &[word("", 1)]),
22178        ("⋑⋑", &[word("⋑⋑", 2)]),
22179        (
22180            "原理,进而",
22181            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22182        ),
22183        (
22184            "hello world",
22185            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22186        ),
22187        (
22188            "hello, world",
22189            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22190        ),
22191        (
22192            "  hello world",
22193            &[
22194                whitespace("  ", 2),
22195                word("hello", 5),
22196                whitespace(" ", 1),
22197                word("world", 5),
22198            ],
22199        ),
22200        (
22201            "这是什么 \n 钢笔",
22202            &[
22203                word("", 1),
22204                word("", 1),
22205                word("", 1),
22206                word("", 1),
22207                whitespace(" ", 1),
22208                newline(),
22209                whitespace(" ", 1),
22210                word("", 1),
22211                word("", 1),
22212            ],
22213        ),
22214        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22215    ];
22216
22217    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22218        WordBreakToken::Word {
22219            token,
22220            grapheme_len,
22221        }
22222    }
22223
22224    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22225        WordBreakToken::InlineWhitespace {
22226            token,
22227            grapheme_len,
22228        }
22229    }
22230
22231    fn newline() -> WordBreakToken<'static> {
22232        WordBreakToken::Newline
22233    }
22234
22235    for (input, result) in tests {
22236        assert_eq!(
22237            WordBreakingTokenizer::new(input)
22238                .collect::<Vec<_>>()
22239                .as_slice(),
22240            *result,
22241        );
22242    }
22243}
22244
22245fn wrap_with_prefix(
22246    first_line_prefix: String,
22247    subsequent_lines_prefix: String,
22248    unwrapped_text: String,
22249    wrap_column: usize,
22250    tab_size: NonZeroU32,
22251    preserve_existing_whitespace: bool,
22252) -> String {
22253    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22254    let subsequent_lines_prefix_len =
22255        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22256    let mut wrapped_text = String::new();
22257    let mut current_line = first_line_prefix;
22258    let mut is_first_line = true;
22259
22260    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22261    let mut current_line_len = first_line_prefix_len;
22262    let mut in_whitespace = false;
22263    for token in tokenizer {
22264        let have_preceding_whitespace = in_whitespace;
22265        match token {
22266            WordBreakToken::Word {
22267                token,
22268                grapheme_len,
22269            } => {
22270                in_whitespace = false;
22271                let current_prefix_len = if is_first_line {
22272                    first_line_prefix_len
22273                } else {
22274                    subsequent_lines_prefix_len
22275                };
22276                if current_line_len + grapheme_len > wrap_column
22277                    && current_line_len != current_prefix_len
22278                {
22279                    wrapped_text.push_str(current_line.trim_end());
22280                    wrapped_text.push('\n');
22281                    is_first_line = false;
22282                    current_line = subsequent_lines_prefix.clone();
22283                    current_line_len = subsequent_lines_prefix_len;
22284                }
22285                current_line.push_str(token);
22286                current_line_len += grapheme_len;
22287            }
22288            WordBreakToken::InlineWhitespace {
22289                mut token,
22290                mut grapheme_len,
22291            } => {
22292                in_whitespace = true;
22293                if have_preceding_whitespace && !preserve_existing_whitespace {
22294                    continue;
22295                }
22296                if !preserve_existing_whitespace {
22297                    token = " ";
22298                    grapheme_len = 1;
22299                }
22300                let current_prefix_len = if is_first_line {
22301                    first_line_prefix_len
22302                } else {
22303                    subsequent_lines_prefix_len
22304                };
22305                if current_line_len + grapheme_len > wrap_column {
22306                    wrapped_text.push_str(current_line.trim_end());
22307                    wrapped_text.push('\n');
22308                    is_first_line = false;
22309                    current_line = subsequent_lines_prefix.clone();
22310                    current_line_len = subsequent_lines_prefix_len;
22311                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22312                    current_line.push_str(token);
22313                    current_line_len += grapheme_len;
22314                }
22315            }
22316            WordBreakToken::Newline => {
22317                in_whitespace = true;
22318                let current_prefix_len = if is_first_line {
22319                    first_line_prefix_len
22320                } else {
22321                    subsequent_lines_prefix_len
22322                };
22323                if preserve_existing_whitespace {
22324                    wrapped_text.push_str(current_line.trim_end());
22325                    wrapped_text.push('\n');
22326                    is_first_line = false;
22327                    current_line = subsequent_lines_prefix.clone();
22328                    current_line_len = subsequent_lines_prefix_len;
22329                } else if have_preceding_whitespace {
22330                    continue;
22331                } else if current_line_len + 1 > wrap_column
22332                    && current_line_len != current_prefix_len
22333                {
22334                    wrapped_text.push_str(current_line.trim_end());
22335                    wrapped_text.push('\n');
22336                    is_first_line = false;
22337                    current_line = subsequent_lines_prefix.clone();
22338                    current_line_len = subsequent_lines_prefix_len;
22339                } else if current_line_len != current_prefix_len {
22340                    current_line.push(' ');
22341                    current_line_len += 1;
22342                }
22343            }
22344        }
22345    }
22346
22347    if !current_line.is_empty() {
22348        wrapped_text.push_str(&current_line);
22349    }
22350    wrapped_text
22351}
22352
22353#[test]
22354fn test_wrap_with_prefix() {
22355    assert_eq!(
22356        wrap_with_prefix(
22357            "# ".to_string(),
22358            "# ".to_string(),
22359            "abcdefg".to_string(),
22360            4,
22361            NonZeroU32::new(4).unwrap(),
22362            false,
22363        ),
22364        "# abcdefg"
22365    );
22366    assert_eq!(
22367        wrap_with_prefix(
22368            "".to_string(),
22369            "".to_string(),
22370            "\thello world".to_string(),
22371            8,
22372            NonZeroU32::new(4).unwrap(),
22373            false,
22374        ),
22375        "hello\nworld"
22376    );
22377    assert_eq!(
22378        wrap_with_prefix(
22379            "// ".to_string(),
22380            "// ".to_string(),
22381            "xx \nyy zz aa bb cc".to_string(),
22382            12,
22383            NonZeroU32::new(4).unwrap(),
22384            false,
22385        ),
22386        "// xx yy zz\n// aa bb cc"
22387    );
22388    assert_eq!(
22389        wrap_with_prefix(
22390            String::new(),
22391            String::new(),
22392            "这是什么 \n 钢笔".to_string(),
22393            3,
22394            NonZeroU32::new(4).unwrap(),
22395            false,
22396        ),
22397        "这是什\n么 钢\n"
22398    );
22399}
22400
22401pub trait CollaborationHub {
22402    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22403    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22404    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22405}
22406
22407impl CollaborationHub for Entity<Project> {
22408    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22409        self.read(cx).collaborators()
22410    }
22411
22412    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22413        self.read(cx).user_store().read(cx).participant_indices()
22414    }
22415
22416    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22417        let this = self.read(cx);
22418        let user_ids = this.collaborators().values().map(|c| c.user_id);
22419        this.user_store().read(cx).participant_names(user_ids, cx)
22420    }
22421}
22422
22423pub trait SemanticsProvider {
22424    fn hover(
22425        &self,
22426        buffer: &Entity<Buffer>,
22427        position: text::Anchor,
22428        cx: &mut App,
22429    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22430
22431    fn inline_values(
22432        &self,
22433        buffer_handle: Entity<Buffer>,
22434        range: Range<text::Anchor>,
22435        cx: &mut App,
22436    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22437
22438    fn inlay_hints(
22439        &self,
22440        buffer_handle: Entity<Buffer>,
22441        range: Range<text::Anchor>,
22442        cx: &mut App,
22443    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22444
22445    fn resolve_inlay_hint(
22446        &self,
22447        hint: InlayHint,
22448        buffer_handle: Entity<Buffer>,
22449        server_id: LanguageServerId,
22450        cx: &mut App,
22451    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22452
22453    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22454
22455    fn document_highlights(
22456        &self,
22457        buffer: &Entity<Buffer>,
22458        position: text::Anchor,
22459        cx: &mut App,
22460    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22461
22462    fn definitions(
22463        &self,
22464        buffer: &Entity<Buffer>,
22465        position: text::Anchor,
22466        kind: GotoDefinitionKind,
22467        cx: &mut App,
22468    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22469
22470    fn range_for_rename(
22471        &self,
22472        buffer: &Entity<Buffer>,
22473        position: text::Anchor,
22474        cx: &mut App,
22475    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22476
22477    fn perform_rename(
22478        &self,
22479        buffer: &Entity<Buffer>,
22480        position: text::Anchor,
22481        new_name: String,
22482        cx: &mut App,
22483    ) -> Option<Task<Result<ProjectTransaction>>>;
22484}
22485
22486pub trait CompletionProvider {
22487    fn completions(
22488        &self,
22489        excerpt_id: ExcerptId,
22490        buffer: &Entity<Buffer>,
22491        buffer_position: text::Anchor,
22492        trigger: CompletionContext,
22493        window: &mut Window,
22494        cx: &mut Context<Editor>,
22495    ) -> Task<Result<Vec<CompletionResponse>>>;
22496
22497    fn resolve_completions(
22498        &self,
22499        _buffer: Entity<Buffer>,
22500        _completion_indices: Vec<usize>,
22501        _completions: Rc<RefCell<Box<[Completion]>>>,
22502        _cx: &mut Context<Editor>,
22503    ) -> Task<Result<bool>> {
22504        Task::ready(Ok(false))
22505    }
22506
22507    fn apply_additional_edits_for_completion(
22508        &self,
22509        _buffer: Entity<Buffer>,
22510        _completions: Rc<RefCell<Box<[Completion]>>>,
22511        _completion_index: usize,
22512        _push_to_history: bool,
22513        _cx: &mut Context<Editor>,
22514    ) -> Task<Result<Option<language::Transaction>>> {
22515        Task::ready(Ok(None))
22516    }
22517
22518    fn is_completion_trigger(
22519        &self,
22520        buffer: &Entity<Buffer>,
22521        position: language::Anchor,
22522        text: &str,
22523        trigger_in_words: bool,
22524        menu_is_open: bool,
22525        cx: &mut Context<Editor>,
22526    ) -> bool;
22527
22528    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22529
22530    fn sort_completions(&self) -> bool {
22531        true
22532    }
22533
22534    fn filter_completions(&self) -> bool {
22535        true
22536    }
22537}
22538
22539pub trait CodeActionProvider {
22540    fn id(&self) -> Arc<str>;
22541
22542    fn code_actions(
22543        &self,
22544        buffer: &Entity<Buffer>,
22545        range: Range<text::Anchor>,
22546        window: &mut Window,
22547        cx: &mut App,
22548    ) -> Task<Result<Vec<CodeAction>>>;
22549
22550    fn apply_code_action(
22551        &self,
22552        buffer_handle: Entity<Buffer>,
22553        action: CodeAction,
22554        excerpt_id: ExcerptId,
22555        push_to_history: bool,
22556        window: &mut Window,
22557        cx: &mut App,
22558    ) -> Task<Result<ProjectTransaction>>;
22559}
22560
22561impl CodeActionProvider for Entity<Project> {
22562    fn id(&self) -> Arc<str> {
22563        "project".into()
22564    }
22565
22566    fn code_actions(
22567        &self,
22568        buffer: &Entity<Buffer>,
22569        range: Range<text::Anchor>,
22570        _window: &mut Window,
22571        cx: &mut App,
22572    ) -> Task<Result<Vec<CodeAction>>> {
22573        self.update(cx, |project, cx| {
22574            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22575            let code_actions = project.code_actions(buffer, range, None, cx);
22576            cx.background_spawn(async move {
22577                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22578                Ok(code_lens_actions
22579                    .context("code lens fetch")?
22580                    .into_iter()
22581                    .flatten()
22582                    .chain(
22583                        code_actions
22584                            .context("code action fetch")?
22585                            .into_iter()
22586                            .flatten(),
22587                    )
22588                    .collect())
22589            })
22590        })
22591    }
22592
22593    fn apply_code_action(
22594        &self,
22595        buffer_handle: Entity<Buffer>,
22596        action: CodeAction,
22597        _excerpt_id: ExcerptId,
22598        push_to_history: bool,
22599        _window: &mut Window,
22600        cx: &mut App,
22601    ) -> Task<Result<ProjectTransaction>> {
22602        self.update(cx, |project, cx| {
22603            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22604        })
22605    }
22606}
22607
22608fn snippet_completions(
22609    project: &Project,
22610    buffer: &Entity<Buffer>,
22611    buffer_position: text::Anchor,
22612    cx: &mut App,
22613) -> Task<Result<CompletionResponse>> {
22614    let languages = buffer.read(cx).languages_at(buffer_position);
22615    let snippet_store = project.snippets().read(cx);
22616
22617    let scopes: Vec<_> = languages
22618        .iter()
22619        .filter_map(|language| {
22620            let language_name = language.lsp_id();
22621            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22622
22623            if snippets.is_empty() {
22624                None
22625            } else {
22626                Some((language.default_scope(), snippets))
22627            }
22628        })
22629        .collect();
22630
22631    if scopes.is_empty() {
22632        return Task::ready(Ok(CompletionResponse {
22633            completions: vec![],
22634            display_options: CompletionDisplayOptions::default(),
22635            is_incomplete: false,
22636        }));
22637    }
22638
22639    let snapshot = buffer.read(cx).text_snapshot();
22640    let chars: String = snapshot
22641        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22642        .collect();
22643    let executor = cx.background_executor().clone();
22644
22645    cx.background_spawn(async move {
22646        let mut is_incomplete = false;
22647        let mut completions: Vec<Completion> = Vec::new();
22648        for (scope, snippets) in scopes.into_iter() {
22649            let classifier =
22650                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22651            let mut last_word = chars
22652                .chars()
22653                .take_while(|c| classifier.is_word(*c))
22654                .collect::<String>();
22655            last_word = last_word.chars().rev().collect();
22656
22657            if last_word.is_empty() {
22658                return Ok(CompletionResponse {
22659                    completions: vec![],
22660                    display_options: CompletionDisplayOptions::default(),
22661                    is_incomplete: true,
22662                });
22663            }
22664
22665            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22666            let to_lsp = |point: &text::Anchor| {
22667                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22668                point_to_lsp(end)
22669            };
22670            let lsp_end = to_lsp(&buffer_position);
22671
22672            let candidates = snippets
22673                .iter()
22674                .enumerate()
22675                .flat_map(|(ix, snippet)| {
22676                    snippet
22677                        .prefix
22678                        .iter()
22679                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22680                })
22681                .collect::<Vec<StringMatchCandidate>>();
22682
22683            const MAX_RESULTS: usize = 100;
22684            let mut matches = fuzzy::match_strings(
22685                &candidates,
22686                &last_word,
22687                last_word.chars().any(|c| c.is_uppercase()),
22688                true,
22689                MAX_RESULTS,
22690                &Default::default(),
22691                executor.clone(),
22692            )
22693            .await;
22694
22695            if matches.len() >= MAX_RESULTS {
22696                is_incomplete = true;
22697            }
22698
22699            // Remove all candidates where the query's start does not match the start of any word in the candidate
22700            if let Some(query_start) = last_word.chars().next() {
22701                matches.retain(|string_match| {
22702                    split_words(&string_match.string).any(|word| {
22703                        // Check that the first codepoint of the word as lowercase matches the first
22704                        // codepoint of the query as lowercase
22705                        word.chars()
22706                            .flat_map(|codepoint| codepoint.to_lowercase())
22707                            .zip(query_start.to_lowercase())
22708                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22709                    })
22710                });
22711            }
22712
22713            let matched_strings = matches
22714                .into_iter()
22715                .map(|m| m.string)
22716                .collect::<HashSet<_>>();
22717
22718            completions.extend(snippets.iter().filter_map(|snippet| {
22719                let matching_prefix = snippet
22720                    .prefix
22721                    .iter()
22722                    .find(|prefix| matched_strings.contains(*prefix))?;
22723                let start = as_offset - last_word.len();
22724                let start = snapshot.anchor_before(start);
22725                let range = start..buffer_position;
22726                let lsp_start = to_lsp(&start);
22727                let lsp_range = lsp::Range {
22728                    start: lsp_start,
22729                    end: lsp_end,
22730                };
22731                Some(Completion {
22732                    replace_range: range,
22733                    new_text: snippet.body.clone(),
22734                    source: CompletionSource::Lsp {
22735                        insert_range: None,
22736                        server_id: LanguageServerId(usize::MAX),
22737                        resolved: true,
22738                        lsp_completion: Box::new(lsp::CompletionItem {
22739                            label: snippet.prefix.first().unwrap().clone(),
22740                            kind: Some(CompletionItemKind::SNIPPET),
22741                            label_details: snippet.description.as_ref().map(|description| {
22742                                lsp::CompletionItemLabelDetails {
22743                                    detail: Some(description.clone()),
22744                                    description: None,
22745                                }
22746                            }),
22747                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22748                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22749                                lsp::InsertReplaceEdit {
22750                                    new_text: snippet.body.clone(),
22751                                    insert: lsp_range,
22752                                    replace: lsp_range,
22753                                },
22754                            )),
22755                            filter_text: Some(snippet.body.clone()),
22756                            sort_text: Some(char::MAX.to_string()),
22757                            ..lsp::CompletionItem::default()
22758                        }),
22759                        lsp_defaults: None,
22760                    },
22761                    label: CodeLabel {
22762                        text: matching_prefix.clone(),
22763                        runs: Vec::new(),
22764                        filter_range: 0..matching_prefix.len(),
22765                    },
22766                    icon_path: None,
22767                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22768                        single_line: snippet.name.clone().into(),
22769                        plain_text: snippet
22770                            .description
22771                            .clone()
22772                            .map(|description| description.into()),
22773                    }),
22774                    insert_text_mode: None,
22775                    confirm: None,
22776                })
22777            }))
22778        }
22779
22780        Ok(CompletionResponse {
22781            completions,
22782            display_options: CompletionDisplayOptions::default(),
22783            is_incomplete,
22784        })
22785    })
22786}
22787
22788impl CompletionProvider for Entity<Project> {
22789    fn completions(
22790        &self,
22791        _excerpt_id: ExcerptId,
22792        buffer: &Entity<Buffer>,
22793        buffer_position: text::Anchor,
22794        options: CompletionContext,
22795        _window: &mut Window,
22796        cx: &mut Context<Editor>,
22797    ) -> Task<Result<Vec<CompletionResponse>>> {
22798        self.update(cx, |project, cx| {
22799            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22800            let project_completions = project.completions(buffer, buffer_position, options, cx);
22801            cx.background_spawn(async move {
22802                let mut responses = project_completions.await?;
22803                let snippets = snippets.await?;
22804                if !snippets.completions.is_empty() {
22805                    responses.push(snippets);
22806                }
22807                Ok(responses)
22808            })
22809        })
22810    }
22811
22812    fn resolve_completions(
22813        &self,
22814        buffer: Entity<Buffer>,
22815        completion_indices: Vec<usize>,
22816        completions: Rc<RefCell<Box<[Completion]>>>,
22817        cx: &mut Context<Editor>,
22818    ) -> Task<Result<bool>> {
22819        self.update(cx, |project, cx| {
22820            project.lsp_store().update(cx, |lsp_store, cx| {
22821                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22822            })
22823        })
22824    }
22825
22826    fn apply_additional_edits_for_completion(
22827        &self,
22828        buffer: Entity<Buffer>,
22829        completions: Rc<RefCell<Box<[Completion]>>>,
22830        completion_index: usize,
22831        push_to_history: bool,
22832        cx: &mut Context<Editor>,
22833    ) -> Task<Result<Option<language::Transaction>>> {
22834        self.update(cx, |project, cx| {
22835            project.lsp_store().update(cx, |lsp_store, cx| {
22836                lsp_store.apply_additional_edits_for_completion(
22837                    buffer,
22838                    completions,
22839                    completion_index,
22840                    push_to_history,
22841                    cx,
22842                )
22843            })
22844        })
22845    }
22846
22847    fn is_completion_trigger(
22848        &self,
22849        buffer: &Entity<Buffer>,
22850        position: language::Anchor,
22851        text: &str,
22852        trigger_in_words: bool,
22853        menu_is_open: bool,
22854        cx: &mut Context<Editor>,
22855    ) -> bool {
22856        let mut chars = text.chars();
22857        let char = if let Some(char) = chars.next() {
22858            char
22859        } else {
22860            return false;
22861        };
22862        if chars.next().is_some() {
22863            return false;
22864        }
22865
22866        let buffer = buffer.read(cx);
22867        let snapshot = buffer.snapshot();
22868        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22869            return false;
22870        }
22871        let classifier = snapshot
22872            .char_classifier_at(position)
22873            .scope_context(Some(CharScopeContext::Completion));
22874        if trigger_in_words && classifier.is_word(char) {
22875            return true;
22876        }
22877
22878        buffer.completion_triggers().contains(text)
22879    }
22880}
22881
22882impl SemanticsProvider for Entity<Project> {
22883    fn hover(
22884        &self,
22885        buffer: &Entity<Buffer>,
22886        position: text::Anchor,
22887        cx: &mut App,
22888    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22889        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22890    }
22891
22892    fn document_highlights(
22893        &self,
22894        buffer: &Entity<Buffer>,
22895        position: text::Anchor,
22896        cx: &mut App,
22897    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22898        Some(self.update(cx, |project, cx| {
22899            project.document_highlights(buffer, position, cx)
22900        }))
22901    }
22902
22903    fn definitions(
22904        &self,
22905        buffer: &Entity<Buffer>,
22906        position: text::Anchor,
22907        kind: GotoDefinitionKind,
22908        cx: &mut App,
22909    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22910        Some(self.update(cx, |project, cx| match kind {
22911            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22912            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22913            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22914            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22915        }))
22916    }
22917
22918    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22919        self.update(cx, |project, cx| {
22920            if project
22921                .active_debug_session(cx)
22922                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22923            {
22924                return true;
22925            }
22926
22927            buffer.update(cx, |buffer, cx| {
22928                project.any_language_server_supports_inlay_hints(buffer, cx)
22929            })
22930        })
22931    }
22932
22933    fn inline_values(
22934        &self,
22935        buffer_handle: Entity<Buffer>,
22936        range: Range<text::Anchor>,
22937        cx: &mut App,
22938    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22939        self.update(cx, |project, cx| {
22940            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22941
22942            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22943        })
22944    }
22945
22946    fn inlay_hints(
22947        &self,
22948        buffer_handle: Entity<Buffer>,
22949        range: Range<text::Anchor>,
22950        cx: &mut App,
22951    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22952        Some(self.update(cx, |project, cx| {
22953            project.inlay_hints(buffer_handle, range, cx)
22954        }))
22955    }
22956
22957    fn resolve_inlay_hint(
22958        &self,
22959        hint: InlayHint,
22960        buffer_handle: Entity<Buffer>,
22961        server_id: LanguageServerId,
22962        cx: &mut App,
22963    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22964        Some(self.update(cx, |project, cx| {
22965            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22966        }))
22967    }
22968
22969    fn range_for_rename(
22970        &self,
22971        buffer: &Entity<Buffer>,
22972        position: text::Anchor,
22973        cx: &mut App,
22974    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22975        Some(self.update(cx, |project, cx| {
22976            let buffer = buffer.clone();
22977            let task = project.prepare_rename(buffer.clone(), position, cx);
22978            cx.spawn(async move |_, cx| {
22979                Ok(match task.await? {
22980                    PrepareRenameResponse::Success(range) => Some(range),
22981                    PrepareRenameResponse::InvalidPosition => None,
22982                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22983                        // Fallback on using TreeSitter info to determine identifier range
22984                        buffer.read_with(cx, |buffer, _| {
22985                            let snapshot = buffer.snapshot();
22986                            let (range, kind) = snapshot.surrounding_word(position, None);
22987                            if kind != Some(CharKind::Word) {
22988                                return None;
22989                            }
22990                            Some(
22991                                snapshot.anchor_before(range.start)
22992                                    ..snapshot.anchor_after(range.end),
22993                            )
22994                        })?
22995                    }
22996                })
22997            })
22998        }))
22999    }
23000
23001    fn perform_rename(
23002        &self,
23003        buffer: &Entity<Buffer>,
23004        position: text::Anchor,
23005        new_name: String,
23006        cx: &mut App,
23007    ) -> Option<Task<Result<ProjectTransaction>>> {
23008        Some(self.update(cx, |project, cx| {
23009            project.perform_rename(buffer.clone(), position, new_name, cx)
23010        }))
23011    }
23012}
23013
23014fn inlay_hint_settings(
23015    location: Anchor,
23016    snapshot: &MultiBufferSnapshot,
23017    cx: &mut Context<Editor>,
23018) -> InlayHintSettings {
23019    let file = snapshot.file_at(location);
23020    let language = snapshot.language_at(location).map(|l| l.name());
23021    language_settings(language, file, cx).inlay_hints
23022}
23023
23024fn consume_contiguous_rows(
23025    contiguous_row_selections: &mut Vec<Selection<Point>>,
23026    selection: &Selection<Point>,
23027    display_map: &DisplaySnapshot,
23028    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23029) -> (MultiBufferRow, MultiBufferRow) {
23030    contiguous_row_selections.push(selection.clone());
23031    let start_row = starting_row(selection, display_map);
23032    let mut end_row = ending_row(selection, display_map);
23033
23034    while let Some(next_selection) = selections.peek() {
23035        if next_selection.start.row <= end_row.0 {
23036            end_row = ending_row(next_selection, display_map);
23037            contiguous_row_selections.push(selections.next().unwrap().clone());
23038        } else {
23039            break;
23040        }
23041    }
23042    (start_row, end_row)
23043}
23044
23045fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23046    if selection.start.column > 0 {
23047        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23048    } else {
23049        MultiBufferRow(selection.start.row)
23050    }
23051}
23052
23053fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23054    if next_selection.end.column > 0 || next_selection.is_empty() {
23055        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23056    } else {
23057        MultiBufferRow(next_selection.end.row)
23058    }
23059}
23060
23061impl EditorSnapshot {
23062    pub fn remote_selections_in_range<'a>(
23063        &'a self,
23064        range: &'a Range<Anchor>,
23065        collaboration_hub: &dyn CollaborationHub,
23066        cx: &'a App,
23067    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23068        let participant_names = collaboration_hub.user_names(cx);
23069        let participant_indices = collaboration_hub.user_participant_indices(cx);
23070        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23071        let collaborators_by_replica_id = collaborators_by_peer_id
23072            .values()
23073            .map(|collaborator| (collaborator.replica_id, collaborator))
23074            .collect::<HashMap<_, _>>();
23075        self.buffer_snapshot
23076            .selections_in_range(range, false)
23077            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23078                if replica_id == AGENT_REPLICA_ID {
23079                    Some(RemoteSelection {
23080                        replica_id,
23081                        selection,
23082                        cursor_shape,
23083                        line_mode,
23084                        collaborator_id: CollaboratorId::Agent,
23085                        user_name: Some("Agent".into()),
23086                        color: cx.theme().players().agent(),
23087                    })
23088                } else {
23089                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23090                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23091                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23092                    Some(RemoteSelection {
23093                        replica_id,
23094                        selection,
23095                        cursor_shape,
23096                        line_mode,
23097                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23098                        user_name,
23099                        color: if let Some(index) = participant_index {
23100                            cx.theme().players().color_for_participant(index.0)
23101                        } else {
23102                            cx.theme().players().absent()
23103                        },
23104                    })
23105                }
23106            })
23107    }
23108
23109    pub fn hunks_for_ranges(
23110        &self,
23111        ranges: impl IntoIterator<Item = Range<Point>>,
23112    ) -> Vec<MultiBufferDiffHunk> {
23113        let mut hunks = Vec::new();
23114        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23115            HashMap::default();
23116        for query_range in ranges {
23117            let query_rows =
23118                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23119            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23120                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23121            ) {
23122                // Include deleted hunks that are adjacent to the query range, because
23123                // otherwise they would be missed.
23124                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23125                if hunk.status().is_deleted() {
23126                    intersects_range |= hunk.row_range.start == query_rows.end;
23127                    intersects_range |= hunk.row_range.end == query_rows.start;
23128                }
23129                if intersects_range {
23130                    if !processed_buffer_rows
23131                        .entry(hunk.buffer_id)
23132                        .or_default()
23133                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23134                    {
23135                        continue;
23136                    }
23137                    hunks.push(hunk);
23138                }
23139            }
23140        }
23141
23142        hunks
23143    }
23144
23145    fn display_diff_hunks_for_rows<'a>(
23146        &'a self,
23147        display_rows: Range<DisplayRow>,
23148        folded_buffers: &'a HashSet<BufferId>,
23149    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23150        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23151        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23152
23153        self.buffer_snapshot
23154            .diff_hunks_in_range(buffer_start..buffer_end)
23155            .filter_map(|hunk| {
23156                if folded_buffers.contains(&hunk.buffer_id) {
23157                    return None;
23158                }
23159
23160                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23161                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23162
23163                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23164                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23165
23166                let display_hunk = if hunk_display_start.column() != 0 {
23167                    DisplayDiffHunk::Folded {
23168                        display_row: hunk_display_start.row(),
23169                    }
23170                } else {
23171                    let mut end_row = hunk_display_end.row();
23172                    if hunk_display_end.column() > 0 {
23173                        end_row.0 += 1;
23174                    }
23175                    let is_created_file = hunk.is_created_file();
23176                    DisplayDiffHunk::Unfolded {
23177                        status: hunk.status(),
23178                        diff_base_byte_range: hunk.diff_base_byte_range,
23179                        display_row_range: hunk_display_start.row()..end_row,
23180                        multi_buffer_range: Anchor::range_in_buffer(
23181                            hunk.excerpt_id,
23182                            hunk.buffer_id,
23183                            hunk.buffer_range,
23184                        ),
23185                        is_created_file,
23186                    }
23187                };
23188
23189                Some(display_hunk)
23190            })
23191    }
23192
23193    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23194        self.display_snapshot.buffer_snapshot.language_at(position)
23195    }
23196
23197    pub fn is_focused(&self) -> bool {
23198        self.is_focused
23199    }
23200
23201    pub fn placeholder_text(&self) -> Option<String> {
23202        self.placeholder_display_snapshot
23203            .as_ref()
23204            .map(|display_map| display_map.text())
23205    }
23206
23207    pub fn scroll_position(&self) -> gpui::Point<f32> {
23208        self.scroll_anchor.scroll_position(&self.display_snapshot)
23209    }
23210
23211    fn gutter_dimensions(
23212        &self,
23213        font_id: FontId,
23214        font_size: Pixels,
23215        max_line_number_width: Pixels,
23216        cx: &App,
23217    ) -> Option<GutterDimensions> {
23218        if !self.show_gutter {
23219            return None;
23220        }
23221
23222        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23223        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23224
23225        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23226            matches!(
23227                ProjectSettings::get_global(cx).git.git_gutter,
23228                GitGutterSetting::TrackedFiles
23229            )
23230        });
23231        let gutter_settings = EditorSettings::get_global(cx).gutter;
23232        let show_line_numbers = self
23233            .show_line_numbers
23234            .unwrap_or(gutter_settings.line_numbers);
23235        let line_gutter_width = if show_line_numbers {
23236            // Avoid flicker-like gutter resizes when the line number gains another digit by
23237            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23238            let min_width_for_number_on_gutter =
23239                ch_advance * gutter_settings.min_line_number_digits as f32;
23240            max_line_number_width.max(min_width_for_number_on_gutter)
23241        } else {
23242            0.0.into()
23243        };
23244
23245        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23246        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23247
23248        let git_blame_entries_width =
23249            self.git_blame_gutter_max_author_length
23250                .map(|max_author_length| {
23251                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23252                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23253
23254                    /// The number of characters to dedicate to gaps and margins.
23255                    const SPACING_WIDTH: usize = 4;
23256
23257                    let max_char_count = max_author_length.min(renderer.max_author_length())
23258                        + ::git::SHORT_SHA_LENGTH
23259                        + MAX_RELATIVE_TIMESTAMP.len()
23260                        + SPACING_WIDTH;
23261
23262                    ch_advance * max_char_count
23263                });
23264
23265        let is_singleton = self.buffer_snapshot.is_singleton();
23266
23267        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23268        left_padding += if !is_singleton {
23269            ch_width * 4.0
23270        } else if show_runnables || show_breakpoints {
23271            ch_width * 3.0
23272        } else if show_git_gutter && show_line_numbers {
23273            ch_width * 2.0
23274        } else if show_git_gutter || show_line_numbers {
23275            ch_width
23276        } else {
23277            px(0.)
23278        };
23279
23280        let shows_folds = is_singleton && gutter_settings.folds;
23281
23282        let right_padding = if shows_folds && show_line_numbers {
23283            ch_width * 4.0
23284        } else if shows_folds || (!is_singleton && show_line_numbers) {
23285            ch_width * 3.0
23286        } else if show_line_numbers {
23287            ch_width
23288        } else {
23289            px(0.)
23290        };
23291
23292        Some(GutterDimensions {
23293            left_padding,
23294            right_padding,
23295            width: line_gutter_width + left_padding + right_padding,
23296            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23297            git_blame_entries_width,
23298        })
23299    }
23300
23301    pub fn render_crease_toggle(
23302        &self,
23303        buffer_row: MultiBufferRow,
23304        row_contains_cursor: bool,
23305        editor: Entity<Editor>,
23306        window: &mut Window,
23307        cx: &mut App,
23308    ) -> Option<AnyElement> {
23309        let folded = self.is_line_folded(buffer_row);
23310        let mut is_foldable = false;
23311
23312        if let Some(crease) = self
23313            .crease_snapshot
23314            .query_row(buffer_row, &self.buffer_snapshot)
23315        {
23316            is_foldable = true;
23317            match crease {
23318                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23319                    if let Some(render_toggle) = render_toggle {
23320                        let toggle_callback =
23321                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23322                                if folded {
23323                                    editor.update(cx, |editor, cx| {
23324                                        editor.fold_at(buffer_row, window, cx)
23325                                    });
23326                                } else {
23327                                    editor.update(cx, |editor, cx| {
23328                                        editor.unfold_at(buffer_row, window, cx)
23329                                    });
23330                                }
23331                            });
23332                        return Some((render_toggle)(
23333                            buffer_row,
23334                            folded,
23335                            toggle_callback,
23336                            window,
23337                            cx,
23338                        ));
23339                    }
23340                }
23341            }
23342        }
23343
23344        is_foldable |= self.starts_indent(buffer_row);
23345
23346        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23347            Some(
23348                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23349                    .toggle_state(folded)
23350                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23351                        if folded {
23352                            this.unfold_at(buffer_row, window, cx);
23353                        } else {
23354                            this.fold_at(buffer_row, window, cx);
23355                        }
23356                    }))
23357                    .into_any_element(),
23358            )
23359        } else {
23360            None
23361        }
23362    }
23363
23364    pub fn render_crease_trailer(
23365        &self,
23366        buffer_row: MultiBufferRow,
23367        window: &mut Window,
23368        cx: &mut App,
23369    ) -> Option<AnyElement> {
23370        let folded = self.is_line_folded(buffer_row);
23371        if let Crease::Inline { render_trailer, .. } = self
23372            .crease_snapshot
23373            .query_row(buffer_row, &self.buffer_snapshot)?
23374        {
23375            let render_trailer = render_trailer.as_ref()?;
23376            Some(render_trailer(buffer_row, folded, window, cx))
23377        } else {
23378            None
23379        }
23380    }
23381}
23382
23383impl Deref for EditorSnapshot {
23384    type Target = DisplaySnapshot;
23385
23386    fn deref(&self) -> &Self::Target {
23387        &self.display_snapshot
23388    }
23389}
23390
23391#[derive(Clone, Debug, PartialEq, Eq)]
23392pub enum EditorEvent {
23393    InputIgnored {
23394        text: Arc<str>,
23395    },
23396    InputHandled {
23397        utf16_range_to_replace: Option<Range<isize>>,
23398        text: Arc<str>,
23399    },
23400    ExcerptsAdded {
23401        buffer: Entity<Buffer>,
23402        predecessor: ExcerptId,
23403        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23404    },
23405    ExcerptsRemoved {
23406        ids: Vec<ExcerptId>,
23407        removed_buffer_ids: Vec<BufferId>,
23408    },
23409    BufferFoldToggled {
23410        ids: Vec<ExcerptId>,
23411        folded: bool,
23412    },
23413    ExcerptsEdited {
23414        ids: Vec<ExcerptId>,
23415    },
23416    ExcerptsExpanded {
23417        ids: Vec<ExcerptId>,
23418    },
23419    BufferEdited,
23420    Edited {
23421        transaction_id: clock::Lamport,
23422    },
23423    Reparsed(BufferId),
23424    Focused,
23425    FocusedIn,
23426    Blurred,
23427    DirtyChanged,
23428    Saved,
23429    TitleChanged,
23430    SelectionsChanged {
23431        local: bool,
23432    },
23433    ScrollPositionChanged {
23434        local: bool,
23435        autoscroll: bool,
23436    },
23437    TransactionUndone {
23438        transaction_id: clock::Lamport,
23439    },
23440    TransactionBegun {
23441        transaction_id: clock::Lamport,
23442    },
23443    CursorShapeChanged,
23444    BreadcrumbsChanged,
23445    PushedToNavHistory {
23446        anchor: Anchor,
23447        is_deactivate: bool,
23448    },
23449}
23450
23451impl EventEmitter<EditorEvent> for Editor {}
23452
23453impl Focusable for Editor {
23454    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23455        self.focus_handle.clone()
23456    }
23457}
23458
23459impl Render for Editor {
23460    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23461        let settings = ThemeSettings::get_global(cx);
23462
23463        let mut text_style = match self.mode {
23464            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23465                color: cx.theme().colors().editor_foreground,
23466                font_family: settings.ui_font.family.clone(),
23467                font_features: settings.ui_font.features.clone(),
23468                font_fallbacks: settings.ui_font.fallbacks.clone(),
23469                font_size: rems(0.875).into(),
23470                font_weight: settings.ui_font.weight,
23471                line_height: relative(settings.buffer_line_height.value()),
23472                ..Default::default()
23473            },
23474            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23475                color: cx.theme().colors().editor_foreground,
23476                font_family: settings.buffer_font.family.clone(),
23477                font_features: settings.buffer_font.features.clone(),
23478                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23479                font_size: settings.buffer_font_size(cx).into(),
23480                font_weight: settings.buffer_font.weight,
23481                line_height: relative(settings.buffer_line_height.value()),
23482                ..Default::default()
23483            },
23484        };
23485        if let Some(text_style_refinement) = &self.text_style_refinement {
23486            text_style.refine(text_style_refinement)
23487        }
23488
23489        let background = match self.mode {
23490            EditorMode::SingleLine => cx.theme().system().transparent,
23491            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23492            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23493            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23494        };
23495
23496        EditorElement::new(
23497            &cx.entity(),
23498            EditorStyle {
23499                background,
23500                border: cx.theme().colors().border,
23501                local_player: cx.theme().players().local(),
23502                text: text_style,
23503                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23504                syntax: cx.theme().syntax().clone(),
23505                status: cx.theme().status().clone(),
23506                inlay_hints_style: make_inlay_hints_style(cx),
23507                edit_prediction_styles: make_suggestion_styles(cx),
23508                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23509                show_underlines: self.diagnostics_enabled(),
23510            },
23511        )
23512    }
23513}
23514
23515impl EntityInputHandler for Editor {
23516    fn text_for_range(
23517        &mut self,
23518        range_utf16: Range<usize>,
23519        adjusted_range: &mut Option<Range<usize>>,
23520        _: &mut Window,
23521        cx: &mut Context<Self>,
23522    ) -> Option<String> {
23523        let snapshot = self.buffer.read(cx).read(cx);
23524        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23525        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23526        if (start.0..end.0) != range_utf16 {
23527            adjusted_range.replace(start.0..end.0);
23528        }
23529        Some(snapshot.text_for_range(start..end).collect())
23530    }
23531
23532    fn selected_text_range(
23533        &mut self,
23534        ignore_disabled_input: bool,
23535        _: &mut Window,
23536        cx: &mut Context<Self>,
23537    ) -> Option<UTF16Selection> {
23538        // Prevent the IME menu from appearing when holding down an alphabetic key
23539        // while input is disabled.
23540        if !ignore_disabled_input && !self.input_enabled {
23541            return None;
23542        }
23543
23544        let selection = self.selections.newest::<OffsetUtf16>(cx);
23545        let range = selection.range();
23546
23547        Some(UTF16Selection {
23548            range: range.start.0..range.end.0,
23549            reversed: selection.reversed,
23550        })
23551    }
23552
23553    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23554        let snapshot = self.buffer.read(cx).read(cx);
23555        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23556        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23557    }
23558
23559    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23560        self.clear_highlights::<InputComposition>(cx);
23561        self.ime_transaction.take();
23562    }
23563
23564    fn replace_text_in_range(
23565        &mut self,
23566        range_utf16: Option<Range<usize>>,
23567        text: &str,
23568        window: &mut Window,
23569        cx: &mut Context<Self>,
23570    ) {
23571        if !self.input_enabled {
23572            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23573            return;
23574        }
23575
23576        self.transact(window, cx, |this, window, cx| {
23577            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23578                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23579                Some(this.selection_replacement_ranges(range_utf16, cx))
23580            } else {
23581                this.marked_text_ranges(cx)
23582            };
23583
23584            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23585                let newest_selection_id = this.selections.newest_anchor().id;
23586                this.selections
23587                    .all::<OffsetUtf16>(cx)
23588                    .iter()
23589                    .zip(ranges_to_replace.iter())
23590                    .find_map(|(selection, range)| {
23591                        if selection.id == newest_selection_id {
23592                            Some(
23593                                (range.start.0 as isize - selection.head().0 as isize)
23594                                    ..(range.end.0 as isize - selection.head().0 as isize),
23595                            )
23596                        } else {
23597                            None
23598                        }
23599                    })
23600            });
23601
23602            cx.emit(EditorEvent::InputHandled {
23603                utf16_range_to_replace: range_to_replace,
23604                text: text.into(),
23605            });
23606
23607            if let Some(new_selected_ranges) = new_selected_ranges {
23608                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23609                    selections.select_ranges(new_selected_ranges)
23610                });
23611                this.backspace(&Default::default(), window, cx);
23612            }
23613
23614            this.handle_input(text, window, cx);
23615        });
23616
23617        if let Some(transaction) = self.ime_transaction {
23618            self.buffer.update(cx, |buffer, cx| {
23619                buffer.group_until_transaction(transaction, cx);
23620            });
23621        }
23622
23623        self.unmark_text(window, cx);
23624    }
23625
23626    fn replace_and_mark_text_in_range(
23627        &mut self,
23628        range_utf16: Option<Range<usize>>,
23629        text: &str,
23630        new_selected_range_utf16: Option<Range<usize>>,
23631        window: &mut Window,
23632        cx: &mut Context<Self>,
23633    ) {
23634        if !self.input_enabled {
23635            return;
23636        }
23637
23638        let transaction = self.transact(window, cx, |this, window, cx| {
23639            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23640                let snapshot = this.buffer.read(cx).read(cx);
23641                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23642                    for marked_range in &mut marked_ranges {
23643                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23644                        marked_range.start.0 += relative_range_utf16.start;
23645                        marked_range.start =
23646                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23647                        marked_range.end =
23648                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23649                    }
23650                }
23651                Some(marked_ranges)
23652            } else if let Some(range_utf16) = range_utf16 {
23653                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23654                Some(this.selection_replacement_ranges(range_utf16, cx))
23655            } else {
23656                None
23657            };
23658
23659            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23660                let newest_selection_id = this.selections.newest_anchor().id;
23661                this.selections
23662                    .all::<OffsetUtf16>(cx)
23663                    .iter()
23664                    .zip(ranges_to_replace.iter())
23665                    .find_map(|(selection, range)| {
23666                        if selection.id == newest_selection_id {
23667                            Some(
23668                                (range.start.0 as isize - selection.head().0 as isize)
23669                                    ..(range.end.0 as isize - selection.head().0 as isize),
23670                            )
23671                        } else {
23672                            None
23673                        }
23674                    })
23675            });
23676
23677            cx.emit(EditorEvent::InputHandled {
23678                utf16_range_to_replace: range_to_replace,
23679                text: text.into(),
23680            });
23681
23682            if let Some(ranges) = ranges_to_replace {
23683                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23684                    s.select_ranges(ranges)
23685                });
23686            }
23687
23688            let marked_ranges = {
23689                let snapshot = this.buffer.read(cx).read(cx);
23690                this.selections
23691                    .disjoint_anchors_arc()
23692                    .iter()
23693                    .map(|selection| {
23694                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23695                    })
23696                    .collect::<Vec<_>>()
23697            };
23698
23699            if text.is_empty() {
23700                this.unmark_text(window, cx);
23701            } else {
23702                this.highlight_text::<InputComposition>(
23703                    marked_ranges.clone(),
23704                    HighlightStyle {
23705                        underline: Some(UnderlineStyle {
23706                            thickness: px(1.),
23707                            color: None,
23708                            wavy: false,
23709                        }),
23710                        ..Default::default()
23711                    },
23712                    cx,
23713                );
23714            }
23715
23716            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23717            let use_autoclose = this.use_autoclose;
23718            let use_auto_surround = this.use_auto_surround;
23719            this.set_use_autoclose(false);
23720            this.set_use_auto_surround(false);
23721            this.handle_input(text, window, cx);
23722            this.set_use_autoclose(use_autoclose);
23723            this.set_use_auto_surround(use_auto_surround);
23724
23725            if let Some(new_selected_range) = new_selected_range_utf16 {
23726                let snapshot = this.buffer.read(cx).read(cx);
23727                let new_selected_ranges = marked_ranges
23728                    .into_iter()
23729                    .map(|marked_range| {
23730                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23731                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23732                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23733                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23734                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23735                    })
23736                    .collect::<Vec<_>>();
23737
23738                drop(snapshot);
23739                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23740                    selections.select_ranges(new_selected_ranges)
23741                });
23742            }
23743        });
23744
23745        self.ime_transaction = self.ime_transaction.or(transaction);
23746        if let Some(transaction) = self.ime_transaction {
23747            self.buffer.update(cx, |buffer, cx| {
23748                buffer.group_until_transaction(transaction, cx);
23749            });
23750        }
23751
23752        if self.text_highlights::<InputComposition>(cx).is_none() {
23753            self.ime_transaction.take();
23754        }
23755    }
23756
23757    fn bounds_for_range(
23758        &mut self,
23759        range_utf16: Range<usize>,
23760        element_bounds: gpui::Bounds<Pixels>,
23761        window: &mut Window,
23762        cx: &mut Context<Self>,
23763    ) -> Option<gpui::Bounds<Pixels>> {
23764        let text_layout_details = self.text_layout_details(window);
23765        let CharacterDimensions {
23766            em_width,
23767            em_advance,
23768            line_height,
23769        } = self.character_dimensions(window);
23770
23771        let snapshot = self.snapshot(window, cx);
23772        let scroll_position = snapshot.scroll_position();
23773        let scroll_left = scroll_position.x * em_advance;
23774
23775        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23776        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23777            + self.gutter_dimensions.full_width();
23778        let y = line_height * (start.row().as_f32() - scroll_position.y);
23779
23780        Some(Bounds {
23781            origin: element_bounds.origin + point(x, y),
23782            size: size(em_width, line_height),
23783        })
23784    }
23785
23786    fn character_index_for_point(
23787        &mut self,
23788        point: gpui::Point<Pixels>,
23789        _window: &mut Window,
23790        _cx: &mut Context<Self>,
23791    ) -> Option<usize> {
23792        let position_map = self.last_position_map.as_ref()?;
23793        if !position_map.text_hitbox.contains(&point) {
23794            return None;
23795        }
23796        let display_point = position_map.point_for_position(point).previous_valid;
23797        let anchor = position_map
23798            .snapshot
23799            .display_point_to_anchor(display_point, Bias::Left);
23800        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23801        Some(utf16_offset.0)
23802    }
23803}
23804
23805trait SelectionExt {
23806    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23807    fn spanned_rows(
23808        &self,
23809        include_end_if_at_line_start: bool,
23810        map: &DisplaySnapshot,
23811    ) -> Range<MultiBufferRow>;
23812}
23813
23814impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23815    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23816        let start = self
23817            .start
23818            .to_point(&map.buffer_snapshot)
23819            .to_display_point(map);
23820        let end = self
23821            .end
23822            .to_point(&map.buffer_snapshot)
23823            .to_display_point(map);
23824        if self.reversed {
23825            end..start
23826        } else {
23827            start..end
23828        }
23829    }
23830
23831    fn spanned_rows(
23832        &self,
23833        include_end_if_at_line_start: bool,
23834        map: &DisplaySnapshot,
23835    ) -> Range<MultiBufferRow> {
23836        let start = self.start.to_point(&map.buffer_snapshot);
23837        let mut end = self.end.to_point(&map.buffer_snapshot);
23838        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23839            end.row -= 1;
23840        }
23841
23842        let buffer_start = map.prev_line_boundary(start).0;
23843        let buffer_end = map.next_line_boundary(end).0;
23844        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23845    }
23846}
23847
23848impl<T: InvalidationRegion> InvalidationStack<T> {
23849    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23850    where
23851        S: Clone + ToOffset,
23852    {
23853        while let Some(region) = self.last() {
23854            let all_selections_inside_invalidation_ranges =
23855                if selections.len() == region.ranges().len() {
23856                    selections
23857                        .iter()
23858                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23859                        .all(|(selection, invalidation_range)| {
23860                            let head = selection.head().to_offset(buffer);
23861                            invalidation_range.start <= head && invalidation_range.end >= head
23862                        })
23863                } else {
23864                    false
23865                };
23866
23867            if all_selections_inside_invalidation_ranges {
23868                break;
23869            } else {
23870                self.pop();
23871            }
23872        }
23873    }
23874}
23875
23876impl<T> Default for InvalidationStack<T> {
23877    fn default() -> Self {
23878        Self(Default::default())
23879    }
23880}
23881
23882impl<T> Deref for InvalidationStack<T> {
23883    type Target = Vec<T>;
23884
23885    fn deref(&self) -> &Self::Target {
23886        &self.0
23887    }
23888}
23889
23890impl<T> DerefMut for InvalidationStack<T> {
23891    fn deref_mut(&mut self) -> &mut Self::Target {
23892        &mut self.0
23893    }
23894}
23895
23896impl InvalidationRegion for SnippetState {
23897    fn ranges(&self) -> &[Range<Anchor>] {
23898        &self.ranges[self.active_index]
23899    }
23900}
23901
23902fn edit_prediction_edit_text(
23903    current_snapshot: &BufferSnapshot,
23904    edits: &[(Range<Anchor>, String)],
23905    edit_preview: &EditPreview,
23906    include_deletions: bool,
23907    cx: &App,
23908) -> HighlightedText {
23909    let edits = edits
23910        .iter()
23911        .map(|(anchor, text)| {
23912            (
23913                anchor.start.text_anchor..anchor.end.text_anchor,
23914                text.clone(),
23915            )
23916        })
23917        .collect::<Vec<_>>();
23918
23919    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23920}
23921
23922fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23923    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23924    // Just show the raw edit text with basic styling
23925    let mut text = String::new();
23926    let mut highlights = Vec::new();
23927
23928    let insertion_highlight_style = HighlightStyle {
23929        color: Some(cx.theme().colors().text),
23930        ..Default::default()
23931    };
23932
23933    for (_, edit_text) in edits {
23934        let start_offset = text.len();
23935        text.push_str(edit_text);
23936        let end_offset = text.len();
23937
23938        if start_offset < end_offset {
23939            highlights.push((start_offset..end_offset, insertion_highlight_style));
23940        }
23941    }
23942
23943    HighlightedText {
23944        text: text.into(),
23945        highlights,
23946    }
23947}
23948
23949pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23950    match severity {
23951        lsp::DiagnosticSeverity::ERROR => colors.error,
23952        lsp::DiagnosticSeverity::WARNING => colors.warning,
23953        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23954        lsp::DiagnosticSeverity::HINT => colors.info,
23955        _ => colors.ignored,
23956    }
23957}
23958
23959pub fn styled_runs_for_code_label<'a>(
23960    label: &'a CodeLabel,
23961    syntax_theme: &'a theme::SyntaxTheme,
23962) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23963    let fade_out = HighlightStyle {
23964        fade_out: Some(0.35),
23965        ..Default::default()
23966    };
23967
23968    let mut prev_end = label.filter_range.end;
23969    label
23970        .runs
23971        .iter()
23972        .enumerate()
23973        .flat_map(move |(ix, (range, highlight_id))| {
23974            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23975                style
23976            } else {
23977                return Default::default();
23978            };
23979            let muted_style = style.highlight(fade_out);
23980
23981            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23982            if range.start >= label.filter_range.end {
23983                if range.start > prev_end {
23984                    runs.push((prev_end..range.start, fade_out));
23985                }
23986                runs.push((range.clone(), muted_style));
23987            } else if range.end <= label.filter_range.end {
23988                runs.push((range.clone(), style));
23989            } else {
23990                runs.push((range.start..label.filter_range.end, style));
23991                runs.push((label.filter_range.end..range.end, muted_style));
23992            }
23993            prev_end = cmp::max(prev_end, range.end);
23994
23995            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23996                runs.push((prev_end..label.text.len(), fade_out));
23997            }
23998
23999            runs
24000        })
24001}
24002
24003pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24004    let mut prev_index = 0;
24005    let mut prev_codepoint: Option<char> = None;
24006    text.char_indices()
24007        .chain([(text.len(), '\0')])
24008        .filter_map(move |(index, codepoint)| {
24009            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24010            let is_boundary = index == text.len()
24011                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24012                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24013            if is_boundary {
24014                let chunk = &text[prev_index..index];
24015                prev_index = index;
24016                Some(chunk)
24017            } else {
24018                None
24019            }
24020        })
24021}
24022
24023pub trait RangeToAnchorExt: Sized {
24024    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24025
24026    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24027        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24028        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24029    }
24030}
24031
24032impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24033    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24034        let start_offset = self.start.to_offset(snapshot);
24035        let end_offset = self.end.to_offset(snapshot);
24036        if start_offset == end_offset {
24037            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24038        } else {
24039            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24040        }
24041    }
24042}
24043
24044pub trait RowExt {
24045    fn as_f32(&self) -> f32;
24046
24047    fn next_row(&self) -> Self;
24048
24049    fn previous_row(&self) -> Self;
24050
24051    fn minus(&self, other: Self) -> u32;
24052}
24053
24054impl RowExt for DisplayRow {
24055    fn as_f32(&self) -> f32 {
24056        self.0 as f32
24057    }
24058
24059    fn next_row(&self) -> Self {
24060        Self(self.0 + 1)
24061    }
24062
24063    fn previous_row(&self) -> Self {
24064        Self(self.0.saturating_sub(1))
24065    }
24066
24067    fn minus(&self, other: Self) -> u32 {
24068        self.0 - other.0
24069    }
24070}
24071
24072impl RowExt for MultiBufferRow {
24073    fn as_f32(&self) -> f32 {
24074        self.0 as f32
24075    }
24076
24077    fn next_row(&self) -> Self {
24078        Self(self.0 + 1)
24079    }
24080
24081    fn previous_row(&self) -> Self {
24082        Self(self.0.saturating_sub(1))
24083    }
24084
24085    fn minus(&self, other: Self) -> u32 {
24086        self.0 - other.0
24087    }
24088}
24089
24090trait RowRangeExt {
24091    type Row;
24092
24093    fn len(&self) -> usize;
24094
24095    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24096}
24097
24098impl RowRangeExt for Range<MultiBufferRow> {
24099    type Row = MultiBufferRow;
24100
24101    fn len(&self) -> usize {
24102        (self.end.0 - self.start.0) as usize
24103    }
24104
24105    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24106        (self.start.0..self.end.0).map(MultiBufferRow)
24107    }
24108}
24109
24110impl RowRangeExt for Range<DisplayRow> {
24111    type Row = DisplayRow;
24112
24113    fn len(&self) -> usize {
24114        (self.end.0 - self.start.0) as usize
24115    }
24116
24117    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24118        (self.start.0..self.end.0).map(DisplayRow)
24119    }
24120}
24121
24122/// If select range has more than one line, we
24123/// just point the cursor to range.start.
24124fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24125    if range.start.row == range.end.row {
24126        range
24127    } else {
24128        range.start..range.start
24129    }
24130}
24131pub struct KillRing(ClipboardItem);
24132impl Global for KillRing {}
24133
24134const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24135
24136enum BreakpointPromptEditAction {
24137    Log,
24138    Condition,
24139    HitCondition,
24140}
24141
24142struct BreakpointPromptEditor {
24143    pub(crate) prompt: Entity<Editor>,
24144    editor: WeakEntity<Editor>,
24145    breakpoint_anchor: Anchor,
24146    breakpoint: Breakpoint,
24147    edit_action: BreakpointPromptEditAction,
24148    block_ids: HashSet<CustomBlockId>,
24149    editor_margins: Arc<Mutex<EditorMargins>>,
24150    _subscriptions: Vec<Subscription>,
24151}
24152
24153impl BreakpointPromptEditor {
24154    const MAX_LINES: u8 = 4;
24155
24156    fn new(
24157        editor: WeakEntity<Editor>,
24158        breakpoint_anchor: Anchor,
24159        breakpoint: Breakpoint,
24160        edit_action: BreakpointPromptEditAction,
24161        window: &mut Window,
24162        cx: &mut Context<Self>,
24163    ) -> Self {
24164        let base_text = match edit_action {
24165            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24166            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24167            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24168        }
24169        .map(|msg| msg.to_string())
24170        .unwrap_or_default();
24171
24172        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24173        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24174
24175        let prompt = cx.new(|cx| {
24176            let mut prompt = Editor::new(
24177                EditorMode::AutoHeight {
24178                    min_lines: 1,
24179                    max_lines: Some(Self::MAX_LINES as usize),
24180                },
24181                buffer,
24182                None,
24183                window,
24184                cx,
24185            );
24186            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24187            prompt.set_show_cursor_when_unfocused(false, cx);
24188            prompt.set_placeholder_text(
24189                match edit_action {
24190                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24191                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24192                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24193                },
24194                window,
24195                cx,
24196            );
24197
24198            prompt
24199        });
24200
24201        Self {
24202            prompt,
24203            editor,
24204            breakpoint_anchor,
24205            breakpoint,
24206            edit_action,
24207            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24208            block_ids: Default::default(),
24209            _subscriptions: vec![],
24210        }
24211    }
24212
24213    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24214        self.block_ids.extend(block_ids)
24215    }
24216
24217    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24218        if let Some(editor) = self.editor.upgrade() {
24219            let message = self
24220                .prompt
24221                .read(cx)
24222                .buffer
24223                .read(cx)
24224                .as_singleton()
24225                .expect("A multi buffer in breakpoint prompt isn't possible")
24226                .read(cx)
24227                .as_rope()
24228                .to_string();
24229
24230            editor.update(cx, |editor, cx| {
24231                editor.edit_breakpoint_at_anchor(
24232                    self.breakpoint_anchor,
24233                    self.breakpoint.clone(),
24234                    match self.edit_action {
24235                        BreakpointPromptEditAction::Log => {
24236                            BreakpointEditAction::EditLogMessage(message.into())
24237                        }
24238                        BreakpointPromptEditAction::Condition => {
24239                            BreakpointEditAction::EditCondition(message.into())
24240                        }
24241                        BreakpointPromptEditAction::HitCondition => {
24242                            BreakpointEditAction::EditHitCondition(message.into())
24243                        }
24244                    },
24245                    cx,
24246                );
24247
24248                editor.remove_blocks(self.block_ids.clone(), None, cx);
24249                cx.focus_self(window);
24250            });
24251        }
24252    }
24253
24254    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24255        self.editor
24256            .update(cx, |editor, cx| {
24257                editor.remove_blocks(self.block_ids.clone(), None, cx);
24258                window.focus(&editor.focus_handle);
24259            })
24260            .log_err();
24261    }
24262
24263    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24264        let settings = ThemeSettings::get_global(cx);
24265        let text_style = TextStyle {
24266            color: if self.prompt.read(cx).read_only(cx) {
24267                cx.theme().colors().text_disabled
24268            } else {
24269                cx.theme().colors().text
24270            },
24271            font_family: settings.buffer_font.family.clone(),
24272            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24273            font_size: settings.buffer_font_size(cx).into(),
24274            font_weight: settings.buffer_font.weight,
24275            line_height: relative(settings.buffer_line_height.value()),
24276            ..Default::default()
24277        };
24278        EditorElement::new(
24279            &self.prompt,
24280            EditorStyle {
24281                background: cx.theme().colors().editor_background,
24282                local_player: cx.theme().players().local(),
24283                text: text_style,
24284                ..Default::default()
24285            },
24286        )
24287    }
24288}
24289
24290impl Render for BreakpointPromptEditor {
24291    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24292        let editor_margins = *self.editor_margins.lock();
24293        let gutter_dimensions = editor_margins.gutter;
24294        h_flex()
24295            .key_context("Editor")
24296            .bg(cx.theme().colors().editor_background)
24297            .border_y_1()
24298            .border_color(cx.theme().status().info_border)
24299            .size_full()
24300            .py(window.line_height() / 2.5)
24301            .on_action(cx.listener(Self::confirm))
24302            .on_action(cx.listener(Self::cancel))
24303            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24304            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24305    }
24306}
24307
24308impl Focusable for BreakpointPromptEditor {
24309    fn focus_handle(&self, cx: &App) -> FocusHandle {
24310        self.prompt.focus_handle(cx)
24311    }
24312}
24313
24314fn all_edits_insertions_or_deletions(
24315    edits: &Vec<(Range<Anchor>, String)>,
24316    snapshot: &MultiBufferSnapshot,
24317) -> bool {
24318    let mut all_insertions = true;
24319    let mut all_deletions = true;
24320
24321    for (range, new_text) in edits.iter() {
24322        let range_is_empty = range.to_offset(snapshot).is_empty();
24323        let text_is_empty = new_text.is_empty();
24324
24325        if range_is_empty != text_is_empty {
24326            if range_is_empty {
24327                all_deletions = false;
24328            } else {
24329                all_insertions = false;
24330            }
24331        } else {
24332            return false;
24333        }
24334
24335        if !all_insertions && !all_deletions {
24336            return false;
24337        }
24338    }
24339    all_insertions || all_deletions
24340}
24341
24342struct MissingEditPredictionKeybindingTooltip;
24343
24344impl Render for MissingEditPredictionKeybindingTooltip {
24345    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24346        ui::tooltip_container(window, cx, |container, _, cx| {
24347            container
24348                .flex_shrink_0()
24349                .max_w_80()
24350                .min_h(rems_from_px(124.))
24351                .justify_between()
24352                .child(
24353                    v_flex()
24354                        .flex_1()
24355                        .text_ui_sm(cx)
24356                        .child(Label::new("Conflict with Accept Keybinding"))
24357                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24358                )
24359                .child(
24360                    h_flex()
24361                        .pb_1()
24362                        .gap_1()
24363                        .items_end()
24364                        .w_full()
24365                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24366                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24367                        }))
24368                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24369                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24370                        })),
24371                )
24372        })
24373    }
24374}
24375
24376#[derive(Debug, Clone, Copy, PartialEq)]
24377pub struct LineHighlight {
24378    pub background: Background,
24379    pub border: Option<gpui::Hsla>,
24380    pub include_gutter: bool,
24381    pub type_id: Option<TypeId>,
24382}
24383
24384struct LineManipulationResult {
24385    pub new_text: String,
24386    pub line_count_before: usize,
24387    pub line_count_after: usize,
24388}
24389
24390fn render_diff_hunk_controls(
24391    row: u32,
24392    status: &DiffHunkStatus,
24393    hunk_range: Range<Anchor>,
24394    is_created_file: bool,
24395    line_height: Pixels,
24396    editor: &Entity<Editor>,
24397    _window: &mut Window,
24398    cx: &mut App,
24399) -> AnyElement {
24400    h_flex()
24401        .h(line_height)
24402        .mr_1()
24403        .gap_1()
24404        .px_0p5()
24405        .pb_1()
24406        .border_x_1()
24407        .border_b_1()
24408        .border_color(cx.theme().colors().border_variant)
24409        .rounded_b_lg()
24410        .bg(cx.theme().colors().editor_background)
24411        .gap_1()
24412        .block_mouse_except_scroll()
24413        .shadow_md()
24414        .child(if status.has_secondary_hunk() {
24415            Button::new(("stage", row as u64), "Stage")
24416                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24417                .tooltip({
24418                    let focus_handle = editor.focus_handle(cx);
24419                    move |window, cx| {
24420                        Tooltip::for_action_in(
24421                            "Stage Hunk",
24422                            &::git::ToggleStaged,
24423                            &focus_handle,
24424                            window,
24425                            cx,
24426                        )
24427                    }
24428                })
24429                .on_click({
24430                    let editor = editor.clone();
24431                    move |_event, _window, cx| {
24432                        editor.update(cx, |editor, cx| {
24433                            editor.stage_or_unstage_diff_hunks(
24434                                true,
24435                                vec![hunk_range.start..hunk_range.start],
24436                                cx,
24437                            );
24438                        });
24439                    }
24440                })
24441        } else {
24442            Button::new(("unstage", row as u64), "Unstage")
24443                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24444                .tooltip({
24445                    let focus_handle = editor.focus_handle(cx);
24446                    move |window, cx| {
24447                        Tooltip::for_action_in(
24448                            "Unstage Hunk",
24449                            &::git::ToggleStaged,
24450                            &focus_handle,
24451                            window,
24452                            cx,
24453                        )
24454                    }
24455                })
24456                .on_click({
24457                    let editor = editor.clone();
24458                    move |_event, _window, cx| {
24459                        editor.update(cx, |editor, cx| {
24460                            editor.stage_or_unstage_diff_hunks(
24461                                false,
24462                                vec![hunk_range.start..hunk_range.start],
24463                                cx,
24464                            );
24465                        });
24466                    }
24467                })
24468        })
24469        .child(
24470            Button::new(("restore", row as u64), "Restore")
24471                .tooltip({
24472                    let focus_handle = editor.focus_handle(cx);
24473                    move |window, cx| {
24474                        Tooltip::for_action_in(
24475                            "Restore Hunk",
24476                            &::git::Restore,
24477                            &focus_handle,
24478                            window,
24479                            cx,
24480                        )
24481                    }
24482                })
24483                .on_click({
24484                    let editor = editor.clone();
24485                    move |_event, window, cx| {
24486                        editor.update(cx, |editor, cx| {
24487                            let snapshot = editor.snapshot(window, cx);
24488                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24489                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24490                        });
24491                    }
24492                })
24493                .disabled(is_created_file),
24494        )
24495        .when(
24496            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24497            |el| {
24498                el.child(
24499                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24500                        .shape(IconButtonShape::Square)
24501                        .icon_size(IconSize::Small)
24502                        // .disabled(!has_multiple_hunks)
24503                        .tooltip({
24504                            let focus_handle = editor.focus_handle(cx);
24505                            move |window, cx| {
24506                                Tooltip::for_action_in(
24507                                    "Next Hunk",
24508                                    &GoToHunk,
24509                                    &focus_handle,
24510                                    window,
24511                                    cx,
24512                                )
24513                            }
24514                        })
24515                        .on_click({
24516                            let editor = editor.clone();
24517                            move |_event, window, cx| {
24518                                editor.update(cx, |editor, cx| {
24519                                    let snapshot = editor.snapshot(window, cx);
24520                                    let position =
24521                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24522                                    editor.go_to_hunk_before_or_after_position(
24523                                        &snapshot,
24524                                        position,
24525                                        Direction::Next,
24526                                        window,
24527                                        cx,
24528                                    );
24529                                    editor.expand_selected_diff_hunks(cx);
24530                                });
24531                            }
24532                        }),
24533                )
24534                .child(
24535                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24536                        .shape(IconButtonShape::Square)
24537                        .icon_size(IconSize::Small)
24538                        // .disabled(!has_multiple_hunks)
24539                        .tooltip({
24540                            let focus_handle = editor.focus_handle(cx);
24541                            move |window, cx| {
24542                                Tooltip::for_action_in(
24543                                    "Previous Hunk",
24544                                    &GoToPreviousHunk,
24545                                    &focus_handle,
24546                                    window,
24547                                    cx,
24548                                )
24549                            }
24550                        })
24551                        .on_click({
24552                            let editor = editor.clone();
24553                            move |_event, window, cx| {
24554                                editor.update(cx, |editor, cx| {
24555                                    let snapshot = editor.snapshot(window, cx);
24556                                    let point =
24557                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24558                                    editor.go_to_hunk_before_or_after_position(
24559                                        &snapshot,
24560                                        point,
24561                                        Direction::Prev,
24562                                        window,
24563                                        cx,
24564                                    );
24565                                    editor.expand_selected_diff_hunks(cx);
24566                                });
24567                            }
24568                        }),
24569                )
24570            },
24571        )
24572        .into_any_element()
24573}
24574
24575pub fn multibuffer_context_lines(cx: &App) -> u32 {
24576    EditorSettings::try_get(cx)
24577        .map(|settings| settings.excerpt_context_lines)
24578        .unwrap_or(2)
24579        .min(32)
24580}