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    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, range)) = buffer.syntax_ancestor(new_range.clone()) {
15054                    new_range = range;
15055                    if !node.is_named() {
15056                        continue;
15057                    }
15058                    if !display_map.intersects_fold(new_range.start)
15059                        && !display_map.intersects_fold(new_range.end)
15060                    {
15061                        break;
15062                    }
15063                }
15064
15065                selected_larger_node |= new_range != old_range;
15066                Selection {
15067                    id: selection.id,
15068                    start: new_range.start,
15069                    end: new_range.end,
15070                    goal: SelectionGoal::None,
15071                    reversed: selection.reversed,
15072                }
15073            })
15074            .collect::<Vec<_>>();
15075
15076        if !selected_larger_node {
15077            return; // don't put this call in the history
15078        }
15079
15080        // scroll based on transformation done to the last selection created by the user
15081        let (last_old, last_new) = old_selections
15082            .last()
15083            .zip(new_selections.last().cloned())
15084            .expect("old_selections isn't empty");
15085
15086        // revert selection
15087        let is_selection_reversed = {
15088            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15089            new_selections.last_mut().expect("checked above").reversed =
15090                should_newest_selection_be_reversed;
15091            should_newest_selection_be_reversed
15092        };
15093
15094        if selected_larger_node {
15095            self.select_syntax_node_history.disable_clearing = true;
15096            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15097                s.select(new_selections.clone());
15098            });
15099            self.select_syntax_node_history.disable_clearing = false;
15100        }
15101
15102        let start_row = last_new.start.to_display_point(&display_map).row().0;
15103        let end_row = last_new.end.to_display_point(&display_map).row().0;
15104        let selection_height = end_row - start_row + 1;
15105        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15106
15107        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15108        let scroll_behavior = if fits_on_the_screen {
15109            self.request_autoscroll(Autoscroll::fit(), cx);
15110            SelectSyntaxNodeScrollBehavior::FitSelection
15111        } else if is_selection_reversed {
15112            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15113            SelectSyntaxNodeScrollBehavior::CursorTop
15114        } else {
15115            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15116            SelectSyntaxNodeScrollBehavior::CursorBottom
15117        };
15118
15119        self.select_syntax_node_history.push((
15120            old_selections,
15121            scroll_behavior,
15122            is_selection_reversed,
15123        ));
15124    }
15125
15126    pub fn select_smaller_syntax_node(
15127        &mut self,
15128        _: &SelectSmallerSyntaxNode,
15129        window: &mut Window,
15130        cx: &mut Context<Self>,
15131    ) {
15132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15133
15134        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15135            self.select_syntax_node_history.pop()
15136        {
15137            if let Some(selection) = selections.last_mut() {
15138                selection.reversed = is_selection_reversed;
15139            }
15140
15141            self.select_syntax_node_history.disable_clearing = true;
15142            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15143                s.select(selections.to_vec());
15144            });
15145            self.select_syntax_node_history.disable_clearing = false;
15146
15147            match scroll_behavior {
15148                SelectSyntaxNodeScrollBehavior::CursorTop => {
15149                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15150                }
15151                SelectSyntaxNodeScrollBehavior::FitSelection => {
15152                    self.request_autoscroll(Autoscroll::fit(), cx);
15153                }
15154                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15155                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15156                }
15157            }
15158        }
15159    }
15160
15161    pub fn unwrap_syntax_node(
15162        &mut self,
15163        _: &UnwrapSyntaxNode,
15164        window: &mut Window,
15165        cx: &mut Context<Self>,
15166    ) {
15167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15168
15169        let buffer = self.buffer.read(cx).snapshot(cx);
15170        let selections = self
15171            .selections
15172            .all::<usize>(cx)
15173            .into_iter()
15174            // subtracting the offset requires sorting
15175            .sorted_by_key(|i| i.start);
15176
15177        let full_edits = selections
15178            .into_iter()
15179            .filter_map(|selection| {
15180                let child = if selection.is_empty()
15181                    && let Some((_, ancestor_range)) =
15182                        buffer.syntax_ancestor(selection.start..selection.end)
15183                {
15184                    ancestor_range
15185                } else {
15186                    selection.range()
15187                };
15188
15189                let mut parent = child.clone();
15190                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15191                    parent = ancestor_range;
15192                    if parent.start < child.start || parent.end > child.end {
15193                        break;
15194                    }
15195                }
15196
15197                if parent == child {
15198                    return None;
15199                }
15200                let text = buffer.text_for_range(child).collect::<String>();
15201                Some((selection.id, parent, text))
15202            })
15203            .collect::<Vec<_>>();
15204        if full_edits.is_empty() {
15205            return;
15206        }
15207
15208        self.transact(window, cx, |this, window, cx| {
15209            this.buffer.update(cx, |buffer, cx| {
15210                buffer.edit(
15211                    full_edits
15212                        .iter()
15213                        .map(|(_, p, t)| (p.clone(), t.clone()))
15214                        .collect::<Vec<_>>(),
15215                    None,
15216                    cx,
15217                );
15218            });
15219            this.change_selections(Default::default(), window, cx, |s| {
15220                let mut offset = 0;
15221                let mut selections = vec![];
15222                for (id, parent, text) in full_edits {
15223                    let start = parent.start - offset;
15224                    offset += parent.len() - text.len();
15225                    selections.push(Selection {
15226                        id,
15227                        start,
15228                        end: start + text.len(),
15229                        reversed: false,
15230                        goal: Default::default(),
15231                    });
15232                }
15233                s.select(selections);
15234            });
15235        });
15236    }
15237
15238    pub fn select_next_syntax_node(
15239        &mut self,
15240        _: &SelectNextSyntaxNode,
15241        window: &mut Window,
15242        cx: &mut Context<Self>,
15243    ) {
15244        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15245        if old_selections.is_empty() {
15246            return;
15247        }
15248
15249        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15250
15251        let buffer = self.buffer.read(cx).snapshot(cx);
15252        let mut selected_sibling = false;
15253
15254        let new_selections = old_selections
15255            .iter()
15256            .map(|selection| {
15257                let old_range = selection.start..selection.end;
15258
15259                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15260                    let new_range = node.byte_range();
15261                    selected_sibling = true;
15262                    Selection {
15263                        id: selection.id,
15264                        start: new_range.start,
15265                        end: new_range.end,
15266                        goal: SelectionGoal::None,
15267                        reversed: selection.reversed,
15268                    }
15269                } else {
15270                    selection.clone()
15271                }
15272            })
15273            .collect::<Vec<_>>();
15274
15275        if selected_sibling {
15276            self.change_selections(
15277                SelectionEffects::scroll(Autoscroll::fit()),
15278                window,
15279                cx,
15280                |s| {
15281                    s.select(new_selections);
15282                },
15283            );
15284        }
15285    }
15286
15287    pub fn select_prev_syntax_node(
15288        &mut self,
15289        _: &SelectPreviousSyntaxNode,
15290        window: &mut Window,
15291        cx: &mut Context<Self>,
15292    ) {
15293        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15294        if old_selections.is_empty() {
15295            return;
15296        }
15297
15298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15299
15300        let buffer = self.buffer.read(cx).snapshot(cx);
15301        let mut selected_sibling = false;
15302
15303        let new_selections = old_selections
15304            .iter()
15305            .map(|selection| {
15306                let old_range = selection.start..selection.end;
15307
15308                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15309                    let new_range = node.byte_range();
15310                    selected_sibling = true;
15311                    Selection {
15312                        id: selection.id,
15313                        start: new_range.start,
15314                        end: new_range.end,
15315                        goal: SelectionGoal::None,
15316                        reversed: selection.reversed,
15317                    }
15318                } else {
15319                    selection.clone()
15320                }
15321            })
15322            .collect::<Vec<_>>();
15323
15324        if selected_sibling {
15325            self.change_selections(
15326                SelectionEffects::scroll(Autoscroll::fit()),
15327                window,
15328                cx,
15329                |s| {
15330                    s.select(new_selections);
15331                },
15332            );
15333        }
15334    }
15335
15336    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15337        if !EditorSettings::get_global(cx).gutter.runnables {
15338            self.clear_tasks();
15339            return Task::ready(());
15340        }
15341        let project = self.project().map(Entity::downgrade);
15342        let task_sources = self.lsp_task_sources(cx);
15343        let multi_buffer = self.buffer.downgrade();
15344        cx.spawn_in(window, async move |editor, cx| {
15345            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15346            let Some(project) = project.and_then(|p| p.upgrade()) else {
15347                return;
15348            };
15349            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15350                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15351            }) else {
15352                return;
15353            };
15354
15355            let hide_runnables = project
15356                .update(cx, |project, _| project.is_via_collab())
15357                .unwrap_or(true);
15358            if hide_runnables {
15359                return;
15360            }
15361            let new_rows =
15362                cx.background_spawn({
15363                    let snapshot = display_snapshot.clone();
15364                    async move {
15365                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15366                    }
15367                })
15368                    .await;
15369            let Ok(lsp_tasks) =
15370                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15371            else {
15372                return;
15373            };
15374            let lsp_tasks = lsp_tasks.await;
15375
15376            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15377                lsp_tasks
15378                    .into_iter()
15379                    .flat_map(|(kind, tasks)| {
15380                        tasks.into_iter().filter_map(move |(location, task)| {
15381                            Some((kind.clone(), location?, task))
15382                        })
15383                    })
15384                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15385                        let buffer = location.target.buffer;
15386                        let buffer_snapshot = buffer.read(cx).snapshot();
15387                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15388                            |(excerpt_id, snapshot, _)| {
15389                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15390                                    display_snapshot
15391                                        .buffer_snapshot
15392                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15393                                } else {
15394                                    None
15395                                }
15396                            },
15397                        );
15398                        if let Some(offset) = offset {
15399                            let task_buffer_range =
15400                                location.target.range.to_point(&buffer_snapshot);
15401                            let context_buffer_range =
15402                                task_buffer_range.to_offset(&buffer_snapshot);
15403                            let context_range = BufferOffset(context_buffer_range.start)
15404                                ..BufferOffset(context_buffer_range.end);
15405
15406                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15407                                .or_insert_with(|| RunnableTasks {
15408                                    templates: Vec::new(),
15409                                    offset,
15410                                    column: task_buffer_range.start.column,
15411                                    extra_variables: HashMap::default(),
15412                                    context_range,
15413                                })
15414                                .templates
15415                                .push((kind, task.original_task().clone()));
15416                        }
15417
15418                        acc
15419                    })
15420            }) else {
15421                return;
15422            };
15423
15424            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15425                buffer.language_settings(cx).tasks.prefer_lsp
15426            }) else {
15427                return;
15428            };
15429
15430            let rows = Self::runnable_rows(
15431                project,
15432                display_snapshot,
15433                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15434                new_rows,
15435                cx.clone(),
15436            )
15437            .await;
15438            editor
15439                .update(cx, |editor, _| {
15440                    editor.clear_tasks();
15441                    for (key, mut value) in rows {
15442                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15443                            value.templates.extend(lsp_tasks.templates);
15444                        }
15445
15446                        editor.insert_tasks(key, value);
15447                    }
15448                    for (key, value) in lsp_tasks_by_rows {
15449                        editor.insert_tasks(key, value);
15450                    }
15451                })
15452                .ok();
15453        })
15454    }
15455    fn fetch_runnable_ranges(
15456        snapshot: &DisplaySnapshot,
15457        range: Range<Anchor>,
15458    ) -> Vec<language::RunnableRange> {
15459        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15460    }
15461
15462    fn runnable_rows(
15463        project: Entity<Project>,
15464        snapshot: DisplaySnapshot,
15465        prefer_lsp: bool,
15466        runnable_ranges: Vec<RunnableRange>,
15467        cx: AsyncWindowContext,
15468    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15469        cx.spawn(async move |cx| {
15470            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15471            for mut runnable in runnable_ranges {
15472                let Some(tasks) = cx
15473                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15474                    .ok()
15475                else {
15476                    continue;
15477                };
15478                let mut tasks = tasks.await;
15479
15480                if prefer_lsp {
15481                    tasks.retain(|(task_kind, _)| {
15482                        !matches!(task_kind, TaskSourceKind::Language { .. })
15483                    });
15484                }
15485                if tasks.is_empty() {
15486                    continue;
15487                }
15488
15489                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15490                let Some(row) = snapshot
15491                    .buffer_snapshot
15492                    .buffer_line_for_row(MultiBufferRow(point.row))
15493                    .map(|(_, range)| range.start.row)
15494                else {
15495                    continue;
15496                };
15497
15498                let context_range =
15499                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15500                runnable_rows.push((
15501                    (runnable.buffer_id, row),
15502                    RunnableTasks {
15503                        templates: tasks,
15504                        offset: snapshot
15505                            .buffer_snapshot
15506                            .anchor_before(runnable.run_range.start),
15507                        context_range,
15508                        column: point.column,
15509                        extra_variables: runnable.extra_captures,
15510                    },
15511                ));
15512            }
15513            runnable_rows
15514        })
15515    }
15516
15517    fn templates_with_tags(
15518        project: &Entity<Project>,
15519        runnable: &mut Runnable,
15520        cx: &mut App,
15521    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15522        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15523            let (worktree_id, file) = project
15524                .buffer_for_id(runnable.buffer, cx)
15525                .and_then(|buffer| buffer.read(cx).file())
15526                .map(|file| (file.worktree_id(cx), file.clone()))
15527                .unzip();
15528
15529            (
15530                project.task_store().read(cx).task_inventory().cloned(),
15531                worktree_id,
15532                file,
15533            )
15534        });
15535
15536        let tags = mem::take(&mut runnable.tags);
15537        let language = runnable.language.clone();
15538        cx.spawn(async move |cx| {
15539            let mut templates_with_tags = Vec::new();
15540            if let Some(inventory) = inventory {
15541                for RunnableTag(tag) in tags {
15542                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15543                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15544                    }) else {
15545                        return templates_with_tags;
15546                    };
15547                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15548                        move |(_, template)| {
15549                            template.tags.iter().any(|source_tag| source_tag == &tag)
15550                        },
15551                    ));
15552                }
15553            }
15554            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15555
15556            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15557                // Strongest source wins; if we have worktree tag binding, prefer that to
15558                // global and language bindings;
15559                // if we have a global binding, prefer that to language binding.
15560                let first_mismatch = templates_with_tags
15561                    .iter()
15562                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15563                if let Some(index) = first_mismatch {
15564                    templates_with_tags.truncate(index);
15565                }
15566            }
15567
15568            templates_with_tags
15569        })
15570    }
15571
15572    pub fn move_to_enclosing_bracket(
15573        &mut self,
15574        _: &MoveToEnclosingBracket,
15575        window: &mut Window,
15576        cx: &mut Context<Self>,
15577    ) {
15578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15579        self.change_selections(Default::default(), window, cx, |s| {
15580            s.move_offsets_with(|snapshot, selection| {
15581                let Some(enclosing_bracket_ranges) =
15582                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15583                else {
15584                    return;
15585                };
15586
15587                let mut best_length = usize::MAX;
15588                let mut best_inside = false;
15589                let mut best_in_bracket_range = false;
15590                let mut best_destination = None;
15591                for (open, close) in enclosing_bracket_ranges {
15592                    let close = close.to_inclusive();
15593                    let length = close.end() - open.start;
15594                    let inside = selection.start >= open.end && selection.end <= *close.start();
15595                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15596                        || close.contains(&selection.head());
15597
15598                    // If best is next to a bracket and current isn't, skip
15599                    if !in_bracket_range && best_in_bracket_range {
15600                        continue;
15601                    }
15602
15603                    // Prefer smaller lengths unless best is inside and current isn't
15604                    if length > best_length && (best_inside || !inside) {
15605                        continue;
15606                    }
15607
15608                    best_length = length;
15609                    best_inside = inside;
15610                    best_in_bracket_range = in_bracket_range;
15611                    best_destination = Some(
15612                        if close.contains(&selection.start) && close.contains(&selection.end) {
15613                            if inside { open.end } else { open.start }
15614                        } else if inside {
15615                            *close.start()
15616                        } else {
15617                            *close.end()
15618                        },
15619                    );
15620                }
15621
15622                if let Some(destination) = best_destination {
15623                    selection.collapse_to(destination, SelectionGoal::None);
15624                }
15625            })
15626        });
15627    }
15628
15629    pub fn undo_selection(
15630        &mut self,
15631        _: &UndoSelection,
15632        window: &mut Window,
15633        cx: &mut Context<Self>,
15634    ) {
15635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15636        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15637            self.selection_history.mode = SelectionHistoryMode::Undoing;
15638            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15639                this.end_selection(window, cx);
15640                this.change_selections(
15641                    SelectionEffects::scroll(Autoscroll::newest()),
15642                    window,
15643                    cx,
15644                    |s| s.select_anchors(entry.selections.to_vec()),
15645                );
15646            });
15647            self.selection_history.mode = SelectionHistoryMode::Normal;
15648
15649            self.select_next_state = entry.select_next_state;
15650            self.select_prev_state = entry.select_prev_state;
15651            self.add_selections_state = entry.add_selections_state;
15652        }
15653    }
15654
15655    pub fn redo_selection(
15656        &mut self,
15657        _: &RedoSelection,
15658        window: &mut Window,
15659        cx: &mut Context<Self>,
15660    ) {
15661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15662        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15663            self.selection_history.mode = SelectionHistoryMode::Redoing;
15664            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15665                this.end_selection(window, cx);
15666                this.change_selections(
15667                    SelectionEffects::scroll(Autoscroll::newest()),
15668                    window,
15669                    cx,
15670                    |s| s.select_anchors(entry.selections.to_vec()),
15671                );
15672            });
15673            self.selection_history.mode = SelectionHistoryMode::Normal;
15674
15675            self.select_next_state = entry.select_next_state;
15676            self.select_prev_state = entry.select_prev_state;
15677            self.add_selections_state = entry.add_selections_state;
15678        }
15679    }
15680
15681    pub fn expand_excerpts(
15682        &mut self,
15683        action: &ExpandExcerpts,
15684        _: &mut Window,
15685        cx: &mut Context<Self>,
15686    ) {
15687        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15688    }
15689
15690    pub fn expand_excerpts_down(
15691        &mut self,
15692        action: &ExpandExcerptsDown,
15693        _: &mut Window,
15694        cx: &mut Context<Self>,
15695    ) {
15696        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15697    }
15698
15699    pub fn expand_excerpts_up(
15700        &mut self,
15701        action: &ExpandExcerptsUp,
15702        _: &mut Window,
15703        cx: &mut Context<Self>,
15704    ) {
15705        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15706    }
15707
15708    pub fn expand_excerpts_for_direction(
15709        &mut self,
15710        lines: u32,
15711        direction: ExpandExcerptDirection,
15712
15713        cx: &mut Context<Self>,
15714    ) {
15715        let selections = self.selections.disjoint_anchors_arc();
15716
15717        let lines = if lines == 0 {
15718            EditorSettings::get_global(cx).expand_excerpt_lines
15719        } else {
15720            lines
15721        };
15722
15723        self.buffer.update(cx, |buffer, cx| {
15724            let snapshot = buffer.snapshot(cx);
15725            let mut excerpt_ids = selections
15726                .iter()
15727                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15728                .collect::<Vec<_>>();
15729            excerpt_ids.sort();
15730            excerpt_ids.dedup();
15731            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15732        })
15733    }
15734
15735    pub fn expand_excerpt(
15736        &mut self,
15737        excerpt: ExcerptId,
15738        direction: ExpandExcerptDirection,
15739        window: &mut Window,
15740        cx: &mut Context<Self>,
15741    ) {
15742        let current_scroll_position = self.scroll_position(cx);
15743        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15744        let mut should_scroll_up = false;
15745
15746        if direction == ExpandExcerptDirection::Down {
15747            let multi_buffer = self.buffer.read(cx);
15748            let snapshot = multi_buffer.snapshot(cx);
15749            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15750                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15751                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15752            {
15753                let buffer_snapshot = buffer.read(cx).snapshot();
15754                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15755                let last_row = buffer_snapshot.max_point().row;
15756                let lines_below = last_row.saturating_sub(excerpt_end_row);
15757                should_scroll_up = lines_below >= lines_to_expand;
15758            }
15759        }
15760
15761        self.buffer.update(cx, |buffer, cx| {
15762            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15763        });
15764
15765        if should_scroll_up {
15766            let new_scroll_position =
15767                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15768            self.set_scroll_position(new_scroll_position, window, cx);
15769        }
15770    }
15771
15772    pub fn go_to_singleton_buffer_point(
15773        &mut self,
15774        point: Point,
15775        window: &mut Window,
15776        cx: &mut Context<Self>,
15777    ) {
15778        self.go_to_singleton_buffer_range(point..point, window, cx);
15779    }
15780
15781    pub fn go_to_singleton_buffer_range(
15782        &mut self,
15783        range: Range<Point>,
15784        window: &mut Window,
15785        cx: &mut Context<Self>,
15786    ) {
15787        let multibuffer = self.buffer().read(cx);
15788        let Some(buffer) = multibuffer.as_singleton() else {
15789            return;
15790        };
15791        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15792            return;
15793        };
15794        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15795            return;
15796        };
15797        self.change_selections(
15798            SelectionEffects::default().nav_history(true),
15799            window,
15800            cx,
15801            |s| s.select_anchor_ranges([start..end]),
15802        );
15803    }
15804
15805    pub fn go_to_diagnostic(
15806        &mut self,
15807        action: &GoToDiagnostic,
15808        window: &mut Window,
15809        cx: &mut Context<Self>,
15810    ) {
15811        if !self.diagnostics_enabled() {
15812            return;
15813        }
15814        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15815        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15816    }
15817
15818    pub fn go_to_prev_diagnostic(
15819        &mut self,
15820        action: &GoToPreviousDiagnostic,
15821        window: &mut Window,
15822        cx: &mut Context<Self>,
15823    ) {
15824        if !self.diagnostics_enabled() {
15825            return;
15826        }
15827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15828        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15829    }
15830
15831    pub fn go_to_diagnostic_impl(
15832        &mut self,
15833        direction: Direction,
15834        severity: GoToDiagnosticSeverityFilter,
15835        window: &mut Window,
15836        cx: &mut Context<Self>,
15837    ) {
15838        let buffer = self.buffer.read(cx).snapshot(cx);
15839        let selection = self.selections.newest::<usize>(cx);
15840
15841        let mut active_group_id = None;
15842        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15843            && active_group.active_range.start.to_offset(&buffer) == selection.start
15844        {
15845            active_group_id = Some(active_group.group_id);
15846        }
15847
15848        fn filtered(
15849            snapshot: EditorSnapshot,
15850            severity: GoToDiagnosticSeverityFilter,
15851            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15852        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15853            diagnostics
15854                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15855                .filter(|entry| entry.range.start != entry.range.end)
15856                .filter(|entry| !entry.diagnostic.is_unnecessary)
15857                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15858        }
15859
15860        let snapshot = self.snapshot(window, cx);
15861        let before = filtered(
15862            snapshot.clone(),
15863            severity,
15864            buffer
15865                .diagnostics_in_range(0..selection.start)
15866                .filter(|entry| entry.range.start <= selection.start),
15867        );
15868        let after = filtered(
15869            snapshot,
15870            severity,
15871            buffer
15872                .diagnostics_in_range(selection.start..buffer.len())
15873                .filter(|entry| entry.range.start >= selection.start),
15874        );
15875
15876        let mut found: Option<DiagnosticEntry<usize>> = None;
15877        if direction == Direction::Prev {
15878            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15879            {
15880                for diagnostic in prev_diagnostics.into_iter().rev() {
15881                    if diagnostic.range.start != selection.start
15882                        || active_group_id
15883                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15884                    {
15885                        found = Some(diagnostic);
15886                        break 'outer;
15887                    }
15888                }
15889            }
15890        } else {
15891            for diagnostic in after.chain(before) {
15892                if diagnostic.range.start != selection.start
15893                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15894                {
15895                    found = Some(diagnostic);
15896                    break;
15897                }
15898            }
15899        }
15900        let Some(next_diagnostic) = found else {
15901            return;
15902        };
15903
15904        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15905        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15906            return;
15907        };
15908        self.change_selections(Default::default(), window, cx, |s| {
15909            s.select_ranges(vec![
15910                next_diagnostic.range.start..next_diagnostic.range.start,
15911            ])
15912        });
15913        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15914        self.refresh_edit_prediction(false, true, window, cx);
15915    }
15916
15917    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15919        let snapshot = self.snapshot(window, cx);
15920        let selection = self.selections.newest::<Point>(cx);
15921        self.go_to_hunk_before_or_after_position(
15922            &snapshot,
15923            selection.head(),
15924            Direction::Next,
15925            window,
15926            cx,
15927        );
15928    }
15929
15930    pub fn go_to_hunk_before_or_after_position(
15931        &mut self,
15932        snapshot: &EditorSnapshot,
15933        position: Point,
15934        direction: Direction,
15935        window: &mut Window,
15936        cx: &mut Context<Editor>,
15937    ) {
15938        let row = if direction == Direction::Next {
15939            self.hunk_after_position(snapshot, position)
15940                .map(|hunk| hunk.row_range.start)
15941        } else {
15942            self.hunk_before_position(snapshot, position)
15943        };
15944
15945        if let Some(row) = row {
15946            let destination = Point::new(row.0, 0);
15947            let autoscroll = Autoscroll::center();
15948
15949            self.unfold_ranges(&[destination..destination], false, false, cx);
15950            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15951                s.select_ranges([destination..destination]);
15952            });
15953        }
15954    }
15955
15956    fn hunk_after_position(
15957        &mut self,
15958        snapshot: &EditorSnapshot,
15959        position: Point,
15960    ) -> Option<MultiBufferDiffHunk> {
15961        snapshot
15962            .buffer_snapshot
15963            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15964            .find(|hunk| hunk.row_range.start.0 > position.row)
15965            .or_else(|| {
15966                snapshot
15967                    .buffer_snapshot
15968                    .diff_hunks_in_range(Point::zero()..position)
15969                    .find(|hunk| hunk.row_range.end.0 < position.row)
15970            })
15971    }
15972
15973    fn go_to_prev_hunk(
15974        &mut self,
15975        _: &GoToPreviousHunk,
15976        window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) {
15979        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15980        let snapshot = self.snapshot(window, cx);
15981        let selection = self.selections.newest::<Point>(cx);
15982        self.go_to_hunk_before_or_after_position(
15983            &snapshot,
15984            selection.head(),
15985            Direction::Prev,
15986            window,
15987            cx,
15988        );
15989    }
15990
15991    fn hunk_before_position(
15992        &mut self,
15993        snapshot: &EditorSnapshot,
15994        position: Point,
15995    ) -> Option<MultiBufferRow> {
15996        snapshot
15997            .buffer_snapshot
15998            .diff_hunk_before(position)
15999            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16000    }
16001
16002    fn go_to_next_change(
16003        &mut self,
16004        _: &GoToNextChange,
16005        window: &mut Window,
16006        cx: &mut Context<Self>,
16007    ) {
16008        if let Some(selections) = self
16009            .change_list
16010            .next_change(1, Direction::Next)
16011            .map(|s| s.to_vec())
16012        {
16013            self.change_selections(Default::default(), window, cx, |s| {
16014                let map = s.display_map();
16015                s.select_display_ranges(selections.iter().map(|a| {
16016                    let point = a.to_display_point(&map);
16017                    point..point
16018                }))
16019            })
16020        }
16021    }
16022
16023    fn go_to_previous_change(
16024        &mut self,
16025        _: &GoToPreviousChange,
16026        window: &mut Window,
16027        cx: &mut Context<Self>,
16028    ) {
16029        if let Some(selections) = self
16030            .change_list
16031            .next_change(1, Direction::Prev)
16032            .map(|s| s.to_vec())
16033        {
16034            self.change_selections(Default::default(), window, cx, |s| {
16035                let map = s.display_map();
16036                s.select_display_ranges(selections.iter().map(|a| {
16037                    let point = a.to_display_point(&map);
16038                    point..point
16039                }))
16040            })
16041        }
16042    }
16043
16044    pub fn go_to_next_document_highlight(
16045        &mut self,
16046        _: &GoToNextDocumentHighlight,
16047        window: &mut Window,
16048        cx: &mut Context<Self>,
16049    ) {
16050        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16051    }
16052
16053    pub fn go_to_prev_document_highlight(
16054        &mut self,
16055        _: &GoToPreviousDocumentHighlight,
16056        window: &mut Window,
16057        cx: &mut Context<Self>,
16058    ) {
16059        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16060    }
16061
16062    pub fn go_to_document_highlight_before_or_after_position(
16063        &mut self,
16064        direction: Direction,
16065        window: &mut Window,
16066        cx: &mut Context<Editor>,
16067    ) {
16068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16069        let snapshot = self.snapshot(window, cx);
16070        let buffer = &snapshot.buffer_snapshot;
16071        let position = self.selections.newest::<Point>(cx).head();
16072        let anchor_position = buffer.anchor_after(position);
16073
16074        // Get all document highlights (both read and write)
16075        let mut all_highlights = Vec::new();
16076
16077        if let Some((_, read_highlights)) = self
16078            .background_highlights
16079            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16080        {
16081            all_highlights.extend(read_highlights.iter());
16082        }
16083
16084        if let Some((_, write_highlights)) = self
16085            .background_highlights
16086            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16087        {
16088            all_highlights.extend(write_highlights.iter());
16089        }
16090
16091        if all_highlights.is_empty() {
16092            return;
16093        }
16094
16095        // Sort highlights by position
16096        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16097
16098        let target_highlight = match direction {
16099            Direction::Next => {
16100                // Find the first highlight after the current position
16101                all_highlights
16102                    .iter()
16103                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16104            }
16105            Direction::Prev => {
16106                // Find the last highlight before the current position
16107                all_highlights
16108                    .iter()
16109                    .rev()
16110                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16111            }
16112        };
16113
16114        if let Some(highlight) = target_highlight {
16115            let destination = highlight.start.to_point(buffer);
16116            let autoscroll = Autoscroll::center();
16117
16118            self.unfold_ranges(&[destination..destination], false, false, cx);
16119            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16120                s.select_ranges([destination..destination]);
16121            });
16122        }
16123    }
16124
16125    fn go_to_line<T: 'static>(
16126        &mut self,
16127        position: Anchor,
16128        highlight_color: Option<Hsla>,
16129        window: &mut Window,
16130        cx: &mut Context<Self>,
16131    ) {
16132        let snapshot = self.snapshot(window, cx).display_snapshot;
16133        let position = position.to_point(&snapshot.buffer_snapshot);
16134        let start = snapshot
16135            .buffer_snapshot
16136            .clip_point(Point::new(position.row, 0), Bias::Left);
16137        let end = start + Point::new(1, 0);
16138        let start = snapshot.buffer_snapshot.anchor_before(start);
16139        let end = snapshot.buffer_snapshot.anchor_before(end);
16140
16141        self.highlight_rows::<T>(
16142            start..end,
16143            highlight_color
16144                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16145            Default::default(),
16146            cx,
16147        );
16148
16149        if self.buffer.read(cx).is_singleton() {
16150            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16151        }
16152    }
16153
16154    pub fn go_to_definition(
16155        &mut self,
16156        _: &GoToDefinition,
16157        window: &mut Window,
16158        cx: &mut Context<Self>,
16159    ) -> Task<Result<Navigated>> {
16160        let definition =
16161            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16162        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16163        cx.spawn_in(window, async move |editor, cx| {
16164            if definition.await? == Navigated::Yes {
16165                return Ok(Navigated::Yes);
16166            }
16167            match fallback_strategy {
16168                GoToDefinitionFallback::None => Ok(Navigated::No),
16169                GoToDefinitionFallback::FindAllReferences => {
16170                    match editor.update_in(cx, |editor, window, cx| {
16171                        editor.find_all_references(&FindAllReferences, window, cx)
16172                    })? {
16173                        Some(references) => references.await,
16174                        None => Ok(Navigated::No),
16175                    }
16176                }
16177            }
16178        })
16179    }
16180
16181    pub fn go_to_declaration(
16182        &mut self,
16183        _: &GoToDeclaration,
16184        window: &mut Window,
16185        cx: &mut Context<Self>,
16186    ) -> Task<Result<Navigated>> {
16187        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16188    }
16189
16190    pub fn go_to_declaration_split(
16191        &mut self,
16192        _: &GoToDeclaration,
16193        window: &mut Window,
16194        cx: &mut Context<Self>,
16195    ) -> Task<Result<Navigated>> {
16196        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16197    }
16198
16199    pub fn go_to_implementation(
16200        &mut self,
16201        _: &GoToImplementation,
16202        window: &mut Window,
16203        cx: &mut Context<Self>,
16204    ) -> Task<Result<Navigated>> {
16205        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16206    }
16207
16208    pub fn go_to_implementation_split(
16209        &mut self,
16210        _: &GoToImplementationSplit,
16211        window: &mut Window,
16212        cx: &mut Context<Self>,
16213    ) -> Task<Result<Navigated>> {
16214        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16215    }
16216
16217    pub fn go_to_type_definition(
16218        &mut self,
16219        _: &GoToTypeDefinition,
16220        window: &mut Window,
16221        cx: &mut Context<Self>,
16222    ) -> Task<Result<Navigated>> {
16223        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16224    }
16225
16226    pub fn go_to_definition_split(
16227        &mut self,
16228        _: &GoToDefinitionSplit,
16229        window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) -> Task<Result<Navigated>> {
16232        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16233    }
16234
16235    pub fn go_to_type_definition_split(
16236        &mut self,
16237        _: &GoToTypeDefinitionSplit,
16238        window: &mut Window,
16239        cx: &mut Context<Self>,
16240    ) -> Task<Result<Navigated>> {
16241        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16242    }
16243
16244    fn go_to_definition_of_kind(
16245        &mut self,
16246        kind: GotoDefinitionKind,
16247        split: bool,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) -> Task<Result<Navigated>> {
16251        let Some(provider) = self.semantics_provider.clone() else {
16252            return Task::ready(Ok(Navigated::No));
16253        };
16254        let head = self.selections.newest::<usize>(cx).head();
16255        let buffer = self.buffer.read(cx);
16256        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16257            return Task::ready(Ok(Navigated::No));
16258        };
16259        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16260            return Task::ready(Ok(Navigated::No));
16261        };
16262
16263        cx.spawn_in(window, async move |editor, cx| {
16264            let Some(definitions) = definitions.await? else {
16265                return Ok(Navigated::No);
16266            };
16267            let navigated = editor
16268                .update_in(cx, |editor, window, cx| {
16269                    editor.navigate_to_hover_links(
16270                        Some(kind),
16271                        definitions
16272                            .into_iter()
16273                            .filter(|location| {
16274                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16275                            })
16276                            .map(HoverLink::Text)
16277                            .collect::<Vec<_>>(),
16278                        split,
16279                        window,
16280                        cx,
16281                    )
16282                })?
16283                .await?;
16284            anyhow::Ok(navigated)
16285        })
16286    }
16287
16288    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16289        let selection = self.selections.newest_anchor();
16290        let head = selection.head();
16291        let tail = selection.tail();
16292
16293        let Some((buffer, start_position)) =
16294            self.buffer.read(cx).text_anchor_for_position(head, cx)
16295        else {
16296            return;
16297        };
16298
16299        let end_position = if head != tail {
16300            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16301                return;
16302            };
16303            Some(pos)
16304        } else {
16305            None
16306        };
16307
16308        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16309            let url = if let Some(end_pos) = end_position {
16310                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16311            } else {
16312                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16313            };
16314
16315            if let Some(url) = url {
16316                editor.update(cx, |_, cx| {
16317                    cx.open_url(&url);
16318                })
16319            } else {
16320                Ok(())
16321            }
16322        });
16323
16324        url_finder.detach();
16325    }
16326
16327    pub fn open_selected_filename(
16328        &mut self,
16329        _: &OpenSelectedFilename,
16330        window: &mut Window,
16331        cx: &mut Context<Self>,
16332    ) {
16333        let Some(workspace) = self.workspace() else {
16334            return;
16335        };
16336
16337        let position = self.selections.newest_anchor().head();
16338
16339        let Some((buffer, buffer_position)) =
16340            self.buffer.read(cx).text_anchor_for_position(position, cx)
16341        else {
16342            return;
16343        };
16344
16345        let project = self.project.clone();
16346
16347        cx.spawn_in(window, async move |_, cx| {
16348            let result = find_file(&buffer, project, buffer_position, cx).await;
16349
16350            if let Some((_, path)) = result {
16351                workspace
16352                    .update_in(cx, |workspace, window, cx| {
16353                        workspace.open_resolved_path(path, window, cx)
16354                    })?
16355                    .await?;
16356            }
16357            anyhow::Ok(())
16358        })
16359        .detach();
16360    }
16361
16362    pub(crate) fn navigate_to_hover_links(
16363        &mut self,
16364        kind: Option<GotoDefinitionKind>,
16365        definitions: Vec<HoverLink>,
16366        split: bool,
16367        window: &mut Window,
16368        cx: &mut Context<Editor>,
16369    ) -> Task<Result<Navigated>> {
16370        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16371        let mut first_url_or_file = None;
16372        let definitions: Vec<_> = definitions
16373            .into_iter()
16374            .filter_map(|def| match def {
16375                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16376                HoverLink::InlayHint(lsp_location, server_id) => {
16377                    let computation =
16378                        self.compute_target_location(lsp_location, server_id, window, cx);
16379                    Some(cx.background_spawn(computation))
16380                }
16381                HoverLink::Url(url) => {
16382                    first_url_or_file = Some(Either::Left(url));
16383                    None
16384                }
16385                HoverLink::File(path) => {
16386                    first_url_or_file = Some(Either::Right(path));
16387                    None
16388                }
16389            })
16390            .collect();
16391
16392        let workspace = self.workspace();
16393
16394        cx.spawn_in(window, async move |editor, cx| {
16395            let locations: Vec<Location> = future::join_all(definitions)
16396                .await
16397                .into_iter()
16398                .filter_map(|location| location.transpose())
16399                .collect::<Result<_>>()
16400                .context("location tasks")?;
16401            let mut locations = cx.update(|_, cx| {
16402                locations
16403                    .into_iter()
16404                    .map(|location| {
16405                        let buffer = location.buffer.read(cx);
16406                        (location.buffer, location.range.to_point(buffer))
16407                    })
16408                    .into_group_map()
16409            })?;
16410            let mut num_locations = 0;
16411            for ranges in locations.values_mut() {
16412                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16413                ranges.dedup();
16414                num_locations += ranges.len();
16415            }
16416
16417            if num_locations > 1 {
16418                let Some(workspace) = workspace else {
16419                    return Ok(Navigated::No);
16420                };
16421
16422                let tab_kind = match kind {
16423                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16424                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16425                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16426                    Some(GotoDefinitionKind::Type) => "Types",
16427                };
16428                let title = editor
16429                    .update_in(cx, |_, _, cx| {
16430                        let target = locations
16431                            .iter()
16432                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16433                            .map(|(buffer, location)| {
16434                                buffer
16435                                    .read(cx)
16436                                    .text_for_range(location.clone())
16437                                    .collect::<String>()
16438                            })
16439                            .filter(|text| !text.contains('\n'))
16440                            .unique()
16441                            .take(3)
16442                            .join(", ");
16443                        if target.is_empty() {
16444                            tab_kind.to_owned()
16445                        } else {
16446                            format!("{tab_kind} for {target}")
16447                        }
16448                    })
16449                    .context("buffer title")?;
16450
16451                let opened = workspace
16452                    .update_in(cx, |workspace, window, cx| {
16453                        Self::open_locations_in_multibuffer(
16454                            workspace,
16455                            locations,
16456                            title,
16457                            split,
16458                            MultibufferSelectionMode::First,
16459                            window,
16460                            cx,
16461                        )
16462                    })
16463                    .is_ok();
16464
16465                anyhow::Ok(Navigated::from_bool(opened))
16466            } else if num_locations == 0 {
16467                // If there is one url or file, open it directly
16468                match first_url_or_file {
16469                    Some(Either::Left(url)) => {
16470                        cx.update(|_, cx| cx.open_url(&url))?;
16471                        Ok(Navigated::Yes)
16472                    }
16473                    Some(Either::Right(path)) => {
16474                        let Some(workspace) = workspace else {
16475                            return Ok(Navigated::No);
16476                        };
16477
16478                        workspace
16479                            .update_in(cx, |workspace, window, cx| {
16480                                workspace.open_resolved_path(path, window, cx)
16481                            })?
16482                            .await?;
16483                        Ok(Navigated::Yes)
16484                    }
16485                    None => Ok(Navigated::No),
16486                }
16487            } else {
16488                let Some(workspace) = workspace else {
16489                    return Ok(Navigated::No);
16490                };
16491
16492                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16493                let target_range = target_ranges.first().unwrap().clone();
16494
16495                editor.update_in(cx, |editor, window, cx| {
16496                    let range = target_range.to_point(target_buffer.read(cx));
16497                    let range = editor.range_for_match(&range);
16498                    let range = collapse_multiline_range(range);
16499
16500                    if !split
16501                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16502                    {
16503                        editor.go_to_singleton_buffer_range(range, window, cx);
16504                    } else {
16505                        let pane = workspace.read(cx).active_pane().clone();
16506                        window.defer(cx, move |window, cx| {
16507                            let target_editor: Entity<Self> =
16508                                workspace.update(cx, |workspace, cx| {
16509                                    let pane = if split {
16510                                        workspace.adjacent_pane(window, cx)
16511                                    } else {
16512                                        workspace.active_pane().clone()
16513                                    };
16514
16515                                    workspace.open_project_item(
16516                                        pane,
16517                                        target_buffer.clone(),
16518                                        true,
16519                                        true,
16520                                        window,
16521                                        cx,
16522                                    )
16523                                });
16524                            target_editor.update(cx, |target_editor, cx| {
16525                                // When selecting a definition in a different buffer, disable the nav history
16526                                // to avoid creating a history entry at the previous cursor location.
16527                                pane.update(cx, |pane, _| pane.disable_history());
16528                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16529                                pane.update(cx, |pane, _| pane.enable_history());
16530                            });
16531                        });
16532                    }
16533                    Navigated::Yes
16534                })
16535            }
16536        })
16537    }
16538
16539    fn compute_target_location(
16540        &self,
16541        lsp_location: lsp::Location,
16542        server_id: LanguageServerId,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) -> Task<anyhow::Result<Option<Location>>> {
16546        let Some(project) = self.project.clone() else {
16547            return Task::ready(Ok(None));
16548        };
16549
16550        cx.spawn_in(window, async move |editor, cx| {
16551            let location_task = editor.update(cx, |_, cx| {
16552                project.update(cx, |project, cx| {
16553                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16554                })
16555            })?;
16556            let location = Some({
16557                let target_buffer_handle = location_task.await.context("open local buffer")?;
16558                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16559                    let target_start = target_buffer
16560                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16561                    let target_end = target_buffer
16562                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16563                    target_buffer.anchor_after(target_start)
16564                        ..target_buffer.anchor_before(target_end)
16565                })?;
16566                Location {
16567                    buffer: target_buffer_handle,
16568                    range,
16569                }
16570            });
16571            Ok(location)
16572        })
16573    }
16574
16575    pub fn find_all_references(
16576        &mut self,
16577        _: &FindAllReferences,
16578        window: &mut Window,
16579        cx: &mut Context<Self>,
16580    ) -> Option<Task<Result<Navigated>>> {
16581        let selection = self.selections.newest::<usize>(cx);
16582        let multi_buffer = self.buffer.read(cx);
16583        let head = selection.head();
16584
16585        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16586        let head_anchor = multi_buffer_snapshot.anchor_at(
16587            head,
16588            if head < selection.tail() {
16589                Bias::Right
16590            } else {
16591                Bias::Left
16592            },
16593        );
16594
16595        match self
16596            .find_all_references_task_sources
16597            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16598        {
16599            Ok(_) => {
16600                log::info!(
16601                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16602                );
16603                return None;
16604            }
16605            Err(i) => {
16606                self.find_all_references_task_sources.insert(i, head_anchor);
16607            }
16608        }
16609
16610        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16611        let workspace = self.workspace()?;
16612        let project = workspace.read(cx).project().clone();
16613        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16614        Some(cx.spawn_in(window, async move |editor, cx| {
16615            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16616                if let Ok(i) = editor
16617                    .find_all_references_task_sources
16618                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16619                {
16620                    editor.find_all_references_task_sources.remove(i);
16621                }
16622            });
16623
16624            let Some(locations) = references.await? else {
16625                return anyhow::Ok(Navigated::No);
16626            };
16627            let mut locations = cx.update(|_, cx| {
16628                locations
16629                    .into_iter()
16630                    .map(|location| {
16631                        let buffer = location.buffer.read(cx);
16632                        (location.buffer, location.range.to_point(buffer))
16633                    })
16634                    .into_group_map()
16635            })?;
16636            if locations.is_empty() {
16637                return anyhow::Ok(Navigated::No);
16638            }
16639            for ranges in locations.values_mut() {
16640                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16641                ranges.dedup();
16642            }
16643
16644            workspace.update_in(cx, |workspace, window, cx| {
16645                let target = locations
16646                    .iter()
16647                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16648                    .map(|(buffer, location)| {
16649                        buffer
16650                            .read(cx)
16651                            .text_for_range(location.clone())
16652                            .collect::<String>()
16653                    })
16654                    .filter(|text| !text.contains('\n'))
16655                    .unique()
16656                    .take(3)
16657                    .join(", ");
16658                let title = if target.is_empty() {
16659                    "References".to_owned()
16660                } else {
16661                    format!("References to {target}")
16662                };
16663                Self::open_locations_in_multibuffer(
16664                    workspace,
16665                    locations,
16666                    title,
16667                    false,
16668                    MultibufferSelectionMode::First,
16669                    window,
16670                    cx,
16671                );
16672                Navigated::Yes
16673            })
16674        }))
16675    }
16676
16677    /// Opens a multibuffer with the given project locations in it
16678    pub fn open_locations_in_multibuffer(
16679        workspace: &mut Workspace,
16680        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16681        title: String,
16682        split: bool,
16683        multibuffer_selection_mode: MultibufferSelectionMode,
16684        window: &mut Window,
16685        cx: &mut Context<Workspace>,
16686    ) {
16687        if locations.is_empty() {
16688            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16689            return;
16690        }
16691
16692        let capability = workspace.project().read(cx).capability();
16693        let mut ranges = <Vec<Range<Anchor>>>::new();
16694
16695        // a key to find existing multibuffer editors with the same set of locations
16696        // to prevent us from opening more and more multibuffer tabs for searches and the like
16697        let mut key = (title.clone(), vec![]);
16698        let excerpt_buffer = cx.new(|cx| {
16699            let key = &mut key.1;
16700            let mut multibuffer = MultiBuffer::new(capability);
16701            for (buffer, mut ranges_for_buffer) in locations {
16702                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16703                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16704                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16705                    PathKey::for_buffer(&buffer, cx),
16706                    buffer.clone(),
16707                    ranges_for_buffer,
16708                    multibuffer_context_lines(cx),
16709                    cx,
16710                );
16711                ranges.extend(new_ranges)
16712            }
16713
16714            multibuffer.with_title(title)
16715        });
16716        let existing = workspace.active_pane().update(cx, |pane, cx| {
16717            pane.items()
16718                .filter_map(|item| item.downcast::<Editor>())
16719                .find(|editor| {
16720                    editor
16721                        .read(cx)
16722                        .lookup_key
16723                        .as_ref()
16724                        .and_then(|it| {
16725                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16726                        })
16727                        .is_some_and(|it| *it == key)
16728                })
16729        });
16730        let editor = existing.unwrap_or_else(|| {
16731            cx.new(|cx| {
16732                let mut editor = Editor::for_multibuffer(
16733                    excerpt_buffer,
16734                    Some(workspace.project().clone()),
16735                    window,
16736                    cx,
16737                );
16738                editor.lookup_key = Some(Box::new(key));
16739                editor
16740            })
16741        });
16742        editor.update(cx, |editor, cx| {
16743            match multibuffer_selection_mode {
16744                MultibufferSelectionMode::First => {
16745                    if let Some(first_range) = ranges.first() {
16746                        editor.change_selections(
16747                            SelectionEffects::no_scroll(),
16748                            window,
16749                            cx,
16750                            |selections| {
16751                                selections.clear_disjoint();
16752                                selections
16753                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16754                            },
16755                        );
16756                    }
16757                    editor.highlight_background::<Self>(
16758                        &ranges,
16759                        |theme| theme.colors().editor_highlighted_line_background,
16760                        cx,
16761                    );
16762                }
16763                MultibufferSelectionMode::All => {
16764                    editor.change_selections(
16765                        SelectionEffects::no_scroll(),
16766                        window,
16767                        cx,
16768                        |selections| {
16769                            selections.clear_disjoint();
16770                            selections.select_anchor_ranges(ranges);
16771                        },
16772                    );
16773                }
16774            }
16775            editor.register_buffers_with_language_servers(cx);
16776        });
16777
16778        let item = Box::new(editor);
16779        let item_id = item.item_id();
16780
16781        if split {
16782            workspace.split_item(SplitDirection::Right, item, window, cx);
16783        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16784            let (preview_item_id, preview_item_idx) =
16785                workspace.active_pane().read_with(cx, |pane, _| {
16786                    (pane.preview_item_id(), pane.preview_item_idx())
16787                });
16788
16789            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16790
16791            if let Some(preview_item_id) = preview_item_id {
16792                workspace.active_pane().update(cx, |pane, cx| {
16793                    pane.remove_item(preview_item_id, false, false, window, cx);
16794                });
16795            }
16796        } else {
16797            workspace.add_item_to_active_pane(item, None, true, window, cx);
16798        }
16799        workspace.active_pane().update(cx, |pane, cx| {
16800            pane.set_preview_item_id(Some(item_id), cx);
16801        });
16802    }
16803
16804    pub fn rename(
16805        &mut self,
16806        _: &Rename,
16807        window: &mut Window,
16808        cx: &mut Context<Self>,
16809    ) -> Option<Task<Result<()>>> {
16810        use language::ToOffset as _;
16811
16812        let provider = self.semantics_provider.clone()?;
16813        let selection = self.selections.newest_anchor().clone();
16814        let (cursor_buffer, cursor_buffer_position) = self
16815            .buffer
16816            .read(cx)
16817            .text_anchor_for_position(selection.head(), cx)?;
16818        let (tail_buffer, cursor_buffer_position_end) = self
16819            .buffer
16820            .read(cx)
16821            .text_anchor_for_position(selection.tail(), cx)?;
16822        if tail_buffer != cursor_buffer {
16823            return None;
16824        }
16825
16826        let snapshot = cursor_buffer.read(cx).snapshot();
16827        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16828        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16829        let prepare_rename = provider
16830            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16831            .unwrap_or_else(|| Task::ready(Ok(None)));
16832        drop(snapshot);
16833
16834        Some(cx.spawn_in(window, async move |this, cx| {
16835            let rename_range = if let Some(range) = prepare_rename.await? {
16836                Some(range)
16837            } else {
16838                this.update(cx, |this, cx| {
16839                    let buffer = this.buffer.read(cx).snapshot(cx);
16840                    let mut buffer_highlights = this
16841                        .document_highlights_for_position(selection.head(), &buffer)
16842                        .filter(|highlight| {
16843                            highlight.start.excerpt_id == selection.head().excerpt_id
16844                                && highlight.end.excerpt_id == selection.head().excerpt_id
16845                        });
16846                    buffer_highlights
16847                        .next()
16848                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16849                })?
16850            };
16851            if let Some(rename_range) = rename_range {
16852                this.update_in(cx, |this, window, cx| {
16853                    let snapshot = cursor_buffer.read(cx).snapshot();
16854                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16855                    let cursor_offset_in_rename_range =
16856                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16857                    let cursor_offset_in_rename_range_end =
16858                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16859
16860                    this.take_rename(false, window, cx);
16861                    let buffer = this.buffer.read(cx).read(cx);
16862                    let cursor_offset = selection.head().to_offset(&buffer);
16863                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16864                    let rename_end = rename_start + rename_buffer_range.len();
16865                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16866                    let mut old_highlight_id = None;
16867                    let old_name: Arc<str> = buffer
16868                        .chunks(rename_start..rename_end, true)
16869                        .map(|chunk| {
16870                            if old_highlight_id.is_none() {
16871                                old_highlight_id = chunk.syntax_highlight_id;
16872                            }
16873                            chunk.text
16874                        })
16875                        .collect::<String>()
16876                        .into();
16877
16878                    drop(buffer);
16879
16880                    // Position the selection in the rename editor so that it matches the current selection.
16881                    this.show_local_selections = false;
16882                    let rename_editor = cx.new(|cx| {
16883                        let mut editor = Editor::single_line(window, cx);
16884                        editor.buffer.update(cx, |buffer, cx| {
16885                            buffer.edit([(0..0, old_name.clone())], None, cx)
16886                        });
16887                        let rename_selection_range = match cursor_offset_in_rename_range
16888                            .cmp(&cursor_offset_in_rename_range_end)
16889                        {
16890                            Ordering::Equal => {
16891                                editor.select_all(&SelectAll, window, cx);
16892                                return editor;
16893                            }
16894                            Ordering::Less => {
16895                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16896                            }
16897                            Ordering::Greater => {
16898                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16899                            }
16900                        };
16901                        if rename_selection_range.end > old_name.len() {
16902                            editor.select_all(&SelectAll, window, cx);
16903                        } else {
16904                            editor.change_selections(Default::default(), window, cx, |s| {
16905                                s.select_ranges([rename_selection_range]);
16906                            });
16907                        }
16908                        editor
16909                    });
16910                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16911                        if e == &EditorEvent::Focused {
16912                            cx.emit(EditorEvent::FocusedIn)
16913                        }
16914                    })
16915                    .detach();
16916
16917                    let write_highlights =
16918                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16919                    let read_highlights =
16920                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16921                    let ranges = write_highlights
16922                        .iter()
16923                        .flat_map(|(_, ranges)| ranges.iter())
16924                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16925                        .cloned()
16926                        .collect();
16927
16928                    this.highlight_text::<Rename>(
16929                        ranges,
16930                        HighlightStyle {
16931                            fade_out: Some(0.6),
16932                            ..Default::default()
16933                        },
16934                        cx,
16935                    );
16936                    let rename_focus_handle = rename_editor.focus_handle(cx);
16937                    window.focus(&rename_focus_handle);
16938                    let block_id = this.insert_blocks(
16939                        [BlockProperties {
16940                            style: BlockStyle::Flex,
16941                            placement: BlockPlacement::Below(range.start),
16942                            height: Some(1),
16943                            render: Arc::new({
16944                                let rename_editor = rename_editor.clone();
16945                                move |cx: &mut BlockContext| {
16946                                    let mut text_style = cx.editor_style.text.clone();
16947                                    if let Some(highlight_style) = old_highlight_id
16948                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16949                                    {
16950                                        text_style = text_style.highlight(highlight_style);
16951                                    }
16952                                    div()
16953                                        .block_mouse_except_scroll()
16954                                        .pl(cx.anchor_x)
16955                                        .child(EditorElement::new(
16956                                            &rename_editor,
16957                                            EditorStyle {
16958                                                background: cx.theme().system().transparent,
16959                                                local_player: cx.editor_style.local_player,
16960                                                text: text_style,
16961                                                scrollbar_width: cx.editor_style.scrollbar_width,
16962                                                syntax: cx.editor_style.syntax.clone(),
16963                                                status: cx.editor_style.status.clone(),
16964                                                inlay_hints_style: HighlightStyle {
16965                                                    font_weight: Some(FontWeight::BOLD),
16966                                                    ..make_inlay_hints_style(cx.app)
16967                                                },
16968                                                edit_prediction_styles: make_suggestion_styles(
16969                                                    cx.app,
16970                                                ),
16971                                                ..EditorStyle::default()
16972                                            },
16973                                        ))
16974                                        .into_any_element()
16975                                }
16976                            }),
16977                            priority: 0,
16978                        }],
16979                        Some(Autoscroll::fit()),
16980                        cx,
16981                    )[0];
16982                    this.pending_rename = Some(RenameState {
16983                        range,
16984                        old_name,
16985                        editor: rename_editor,
16986                        block_id,
16987                    });
16988                })?;
16989            }
16990
16991            Ok(())
16992        }))
16993    }
16994
16995    pub fn confirm_rename(
16996        &mut self,
16997        _: &ConfirmRename,
16998        window: &mut Window,
16999        cx: &mut Context<Self>,
17000    ) -> Option<Task<Result<()>>> {
17001        let rename = self.take_rename(false, window, cx)?;
17002        let workspace = self.workspace()?.downgrade();
17003        let (buffer, start) = self
17004            .buffer
17005            .read(cx)
17006            .text_anchor_for_position(rename.range.start, cx)?;
17007        let (end_buffer, _) = self
17008            .buffer
17009            .read(cx)
17010            .text_anchor_for_position(rename.range.end, cx)?;
17011        if buffer != end_buffer {
17012            return None;
17013        }
17014
17015        let old_name = rename.old_name;
17016        let new_name = rename.editor.read(cx).text(cx);
17017
17018        let rename = self.semantics_provider.as_ref()?.perform_rename(
17019            &buffer,
17020            start,
17021            new_name.clone(),
17022            cx,
17023        )?;
17024
17025        Some(cx.spawn_in(window, async move |editor, cx| {
17026            let project_transaction = rename.await?;
17027            Self::open_project_transaction(
17028                &editor,
17029                workspace,
17030                project_transaction,
17031                format!("Rename: {}{}", old_name, new_name),
17032                cx,
17033            )
17034            .await?;
17035
17036            editor.update(cx, |editor, cx| {
17037                editor.refresh_document_highlights(cx);
17038            })?;
17039            Ok(())
17040        }))
17041    }
17042
17043    fn take_rename(
17044        &mut self,
17045        moving_cursor: bool,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) -> Option<RenameState> {
17049        let rename = self.pending_rename.take()?;
17050        if rename.editor.focus_handle(cx).is_focused(window) {
17051            window.focus(&self.focus_handle);
17052        }
17053
17054        self.remove_blocks(
17055            [rename.block_id].into_iter().collect(),
17056            Some(Autoscroll::fit()),
17057            cx,
17058        );
17059        self.clear_highlights::<Rename>(cx);
17060        self.show_local_selections = true;
17061
17062        if moving_cursor {
17063            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17064                editor.selections.newest::<usize>(cx).head()
17065            });
17066
17067            // Update the selection to match the position of the selection inside
17068            // the rename editor.
17069            let snapshot = self.buffer.read(cx).read(cx);
17070            let rename_range = rename.range.to_offset(&snapshot);
17071            let cursor_in_editor = snapshot
17072                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17073                .min(rename_range.end);
17074            drop(snapshot);
17075
17076            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17077                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17078            });
17079        } else {
17080            self.refresh_document_highlights(cx);
17081        }
17082
17083        Some(rename)
17084    }
17085
17086    pub fn pending_rename(&self) -> Option<&RenameState> {
17087        self.pending_rename.as_ref()
17088    }
17089
17090    fn format(
17091        &mut self,
17092        _: &Format,
17093        window: &mut Window,
17094        cx: &mut Context<Self>,
17095    ) -> Option<Task<Result<()>>> {
17096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17097
17098        let project = match &self.project {
17099            Some(project) => project.clone(),
17100            None => return None,
17101        };
17102
17103        Some(self.perform_format(
17104            project,
17105            FormatTrigger::Manual,
17106            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17107            window,
17108            cx,
17109        ))
17110    }
17111
17112    fn format_selections(
17113        &mut self,
17114        _: &FormatSelections,
17115        window: &mut Window,
17116        cx: &mut Context<Self>,
17117    ) -> Option<Task<Result<()>>> {
17118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17119
17120        let project = match &self.project {
17121            Some(project) => project.clone(),
17122            None => return None,
17123        };
17124
17125        let ranges = self
17126            .selections
17127            .all_adjusted(cx)
17128            .into_iter()
17129            .map(|selection| selection.range())
17130            .collect_vec();
17131
17132        Some(self.perform_format(
17133            project,
17134            FormatTrigger::Manual,
17135            FormatTarget::Ranges(ranges),
17136            window,
17137            cx,
17138        ))
17139    }
17140
17141    fn perform_format(
17142        &mut self,
17143        project: Entity<Project>,
17144        trigger: FormatTrigger,
17145        target: FormatTarget,
17146        window: &mut Window,
17147        cx: &mut Context<Self>,
17148    ) -> Task<Result<()>> {
17149        let buffer = self.buffer.clone();
17150        let (buffers, target) = match target {
17151            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17152            FormatTarget::Ranges(selection_ranges) => {
17153                let multi_buffer = buffer.read(cx);
17154                let snapshot = multi_buffer.read(cx);
17155                let mut buffers = HashSet::default();
17156                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17157                    BTreeMap::new();
17158                for selection_range in selection_ranges {
17159                    for (buffer, buffer_range, _) in
17160                        snapshot.range_to_buffer_ranges(selection_range)
17161                    {
17162                        let buffer_id = buffer.remote_id();
17163                        let start = buffer.anchor_before(buffer_range.start);
17164                        let end = buffer.anchor_after(buffer_range.end);
17165                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17166                        buffer_id_to_ranges
17167                            .entry(buffer_id)
17168                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17169                            .or_insert_with(|| vec![start..end]);
17170                    }
17171                }
17172                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17173            }
17174        };
17175
17176        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17177        let selections_prev = transaction_id_prev
17178            .and_then(|transaction_id_prev| {
17179                // default to selections as they were after the last edit, if we have them,
17180                // instead of how they are now.
17181                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17182                // will take you back to where you made the last edit, instead of staying where you scrolled
17183                self.selection_history
17184                    .transaction(transaction_id_prev)
17185                    .map(|t| t.0.clone())
17186            })
17187            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17188
17189        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17190        let format = project.update(cx, |project, cx| {
17191            project.format(buffers, target, true, trigger, cx)
17192        });
17193
17194        cx.spawn_in(window, async move |editor, cx| {
17195            let transaction = futures::select_biased! {
17196                transaction = format.log_err().fuse() => transaction,
17197                () = timeout => {
17198                    log::warn!("timed out waiting for formatting");
17199                    None
17200                }
17201            };
17202
17203            buffer
17204                .update(cx, |buffer, cx| {
17205                    if let Some(transaction) = transaction
17206                        && !buffer.is_singleton()
17207                    {
17208                        buffer.push_transaction(&transaction.0, cx);
17209                    }
17210                    cx.notify();
17211                })
17212                .ok();
17213
17214            if let Some(transaction_id_now) =
17215                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17216            {
17217                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17218                if has_new_transaction {
17219                    _ = editor.update(cx, |editor, _| {
17220                        editor
17221                            .selection_history
17222                            .insert_transaction(transaction_id_now, selections_prev);
17223                    });
17224                }
17225            }
17226
17227            Ok(())
17228        })
17229    }
17230
17231    fn organize_imports(
17232        &mut self,
17233        _: &OrganizeImports,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) -> Option<Task<Result<()>>> {
17237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17238        let project = match &self.project {
17239            Some(project) => project.clone(),
17240            None => return None,
17241        };
17242        Some(self.perform_code_action_kind(
17243            project,
17244            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17245            window,
17246            cx,
17247        ))
17248    }
17249
17250    fn perform_code_action_kind(
17251        &mut self,
17252        project: Entity<Project>,
17253        kind: CodeActionKind,
17254        window: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) -> Task<Result<()>> {
17257        let buffer = self.buffer.clone();
17258        let buffers = buffer.read(cx).all_buffers();
17259        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17260        let apply_action = project.update(cx, |project, cx| {
17261            project.apply_code_action_kind(buffers, kind, true, cx)
17262        });
17263        cx.spawn_in(window, async move |_, cx| {
17264            let transaction = futures::select_biased! {
17265                () = timeout => {
17266                    log::warn!("timed out waiting for executing code action");
17267                    None
17268                }
17269                transaction = apply_action.log_err().fuse() => transaction,
17270            };
17271            buffer
17272                .update(cx, |buffer, cx| {
17273                    // check if we need this
17274                    if let Some(transaction) = transaction
17275                        && !buffer.is_singleton()
17276                    {
17277                        buffer.push_transaction(&transaction.0, cx);
17278                    }
17279                    cx.notify();
17280                })
17281                .ok();
17282            Ok(())
17283        })
17284    }
17285
17286    pub fn restart_language_server(
17287        &mut self,
17288        _: &RestartLanguageServer,
17289        _: &mut Window,
17290        cx: &mut Context<Self>,
17291    ) {
17292        if let Some(project) = self.project.clone() {
17293            self.buffer.update(cx, |multi_buffer, cx| {
17294                project.update(cx, |project, cx| {
17295                    project.restart_language_servers_for_buffers(
17296                        multi_buffer.all_buffers().into_iter().collect(),
17297                        HashSet::default(),
17298                        cx,
17299                    );
17300                });
17301            })
17302        }
17303    }
17304
17305    pub fn stop_language_server(
17306        &mut self,
17307        _: &StopLanguageServer,
17308        _: &mut Window,
17309        cx: &mut Context<Self>,
17310    ) {
17311        if let Some(project) = self.project.clone() {
17312            self.buffer.update(cx, |multi_buffer, cx| {
17313                project.update(cx, |project, cx| {
17314                    project.stop_language_servers_for_buffers(
17315                        multi_buffer.all_buffers().into_iter().collect(),
17316                        HashSet::default(),
17317                        cx,
17318                    );
17319                    cx.emit(project::Event::RefreshInlayHints);
17320                });
17321            });
17322        }
17323    }
17324
17325    fn cancel_language_server_work(
17326        workspace: &mut Workspace,
17327        _: &actions::CancelLanguageServerWork,
17328        _: &mut Window,
17329        cx: &mut Context<Workspace>,
17330    ) {
17331        let project = workspace.project();
17332        let buffers = workspace
17333            .active_item(cx)
17334            .and_then(|item| item.act_as::<Editor>(cx))
17335            .map_or(HashSet::default(), |editor| {
17336                editor.read(cx).buffer.read(cx).all_buffers()
17337            });
17338        project.update(cx, |project, cx| {
17339            project.cancel_language_server_work_for_buffers(buffers, cx);
17340        });
17341    }
17342
17343    fn show_character_palette(
17344        &mut self,
17345        _: &ShowCharacterPalette,
17346        window: &mut Window,
17347        _: &mut Context<Self>,
17348    ) {
17349        window.show_character_palette();
17350    }
17351
17352    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17353        if !self.diagnostics_enabled() {
17354            return;
17355        }
17356
17357        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17358            let buffer = self.buffer.read(cx).snapshot(cx);
17359            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17360            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17361            let is_valid = buffer
17362                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17363                .any(|entry| {
17364                    entry.diagnostic.is_primary
17365                        && !entry.range.is_empty()
17366                        && entry.range.start == primary_range_start
17367                        && entry.diagnostic.message == active_diagnostics.active_message
17368                });
17369
17370            if !is_valid {
17371                self.dismiss_diagnostics(cx);
17372            }
17373        }
17374    }
17375
17376    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17377        match &self.active_diagnostics {
17378            ActiveDiagnostic::Group(group) => Some(group),
17379            _ => None,
17380        }
17381    }
17382
17383    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17384        if !self.diagnostics_enabled() {
17385            return;
17386        }
17387        self.dismiss_diagnostics(cx);
17388        self.active_diagnostics = ActiveDiagnostic::All;
17389    }
17390
17391    fn activate_diagnostics(
17392        &mut self,
17393        buffer_id: BufferId,
17394        diagnostic: DiagnosticEntry<usize>,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) {
17398        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17399            return;
17400        }
17401        self.dismiss_diagnostics(cx);
17402        let snapshot = self.snapshot(window, cx);
17403        let buffer = self.buffer.read(cx).snapshot(cx);
17404        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17405            return;
17406        };
17407
17408        let diagnostic_group = buffer
17409            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17410            .collect::<Vec<_>>();
17411
17412        let blocks =
17413            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17414
17415        let blocks = self.display_map.update(cx, |display_map, cx| {
17416            display_map.insert_blocks(blocks, cx).into_iter().collect()
17417        });
17418        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17419            active_range: buffer.anchor_before(diagnostic.range.start)
17420                ..buffer.anchor_after(diagnostic.range.end),
17421            active_message: diagnostic.diagnostic.message.clone(),
17422            group_id: diagnostic.diagnostic.group_id,
17423            blocks,
17424        });
17425        cx.notify();
17426    }
17427
17428    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17429        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17430            return;
17431        };
17432
17433        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17434        if let ActiveDiagnostic::Group(group) = prev {
17435            self.display_map.update(cx, |display_map, cx| {
17436                display_map.remove_blocks(group.blocks, cx);
17437            });
17438            cx.notify();
17439        }
17440    }
17441
17442    /// Disable inline diagnostics rendering for this editor.
17443    pub fn disable_inline_diagnostics(&mut self) {
17444        self.inline_diagnostics_enabled = false;
17445        self.inline_diagnostics_update = Task::ready(());
17446        self.inline_diagnostics.clear();
17447    }
17448
17449    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17450        self.diagnostics_enabled = false;
17451        self.dismiss_diagnostics(cx);
17452        self.inline_diagnostics_update = Task::ready(());
17453        self.inline_diagnostics.clear();
17454    }
17455
17456    pub fn disable_word_completions(&mut self) {
17457        self.word_completions_enabled = false;
17458    }
17459
17460    pub fn diagnostics_enabled(&self) -> bool {
17461        self.diagnostics_enabled && self.mode.is_full()
17462    }
17463
17464    pub fn inline_diagnostics_enabled(&self) -> bool {
17465        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17466    }
17467
17468    pub fn show_inline_diagnostics(&self) -> bool {
17469        self.show_inline_diagnostics
17470    }
17471
17472    pub fn toggle_inline_diagnostics(
17473        &mut self,
17474        _: &ToggleInlineDiagnostics,
17475        window: &mut Window,
17476        cx: &mut Context<Editor>,
17477    ) {
17478        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17479        self.refresh_inline_diagnostics(false, window, cx);
17480    }
17481
17482    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17483        self.diagnostics_max_severity = severity;
17484        self.display_map.update(cx, |display_map, _| {
17485            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17486        });
17487    }
17488
17489    pub fn toggle_diagnostics(
17490        &mut self,
17491        _: &ToggleDiagnostics,
17492        window: &mut Window,
17493        cx: &mut Context<Editor>,
17494    ) {
17495        if !self.diagnostics_enabled() {
17496            return;
17497        }
17498
17499        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17500            EditorSettings::get_global(cx)
17501                .diagnostics_max_severity
17502                .filter(|severity| severity != &DiagnosticSeverity::Off)
17503                .unwrap_or(DiagnosticSeverity::Hint)
17504        } else {
17505            DiagnosticSeverity::Off
17506        };
17507        self.set_max_diagnostics_severity(new_severity, cx);
17508        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17509            self.active_diagnostics = ActiveDiagnostic::None;
17510            self.inline_diagnostics_update = Task::ready(());
17511            self.inline_diagnostics.clear();
17512        } else {
17513            self.refresh_inline_diagnostics(false, window, cx);
17514        }
17515
17516        cx.notify();
17517    }
17518
17519    pub fn toggle_minimap(
17520        &mut self,
17521        _: &ToggleMinimap,
17522        window: &mut Window,
17523        cx: &mut Context<Editor>,
17524    ) {
17525        if self.supports_minimap(cx) {
17526            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17527        }
17528    }
17529
17530    fn refresh_inline_diagnostics(
17531        &mut self,
17532        debounce: bool,
17533        window: &mut Window,
17534        cx: &mut Context<Self>,
17535    ) {
17536        let max_severity = ProjectSettings::get_global(cx)
17537            .diagnostics
17538            .inline
17539            .max_severity
17540            .unwrap_or(self.diagnostics_max_severity);
17541
17542        if !self.inline_diagnostics_enabled()
17543            || !self.show_inline_diagnostics
17544            || max_severity == DiagnosticSeverity::Off
17545        {
17546            self.inline_diagnostics_update = Task::ready(());
17547            self.inline_diagnostics.clear();
17548            return;
17549        }
17550
17551        let debounce_ms = ProjectSettings::get_global(cx)
17552            .diagnostics
17553            .inline
17554            .update_debounce_ms;
17555        let debounce = if debounce && debounce_ms > 0 {
17556            Some(Duration::from_millis(debounce_ms))
17557        } else {
17558            None
17559        };
17560        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17561            if let Some(debounce) = debounce {
17562                cx.background_executor().timer(debounce).await;
17563            }
17564            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17565                editor
17566                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17567                    .ok()
17568            }) else {
17569                return;
17570            };
17571
17572            let new_inline_diagnostics = cx
17573                .background_spawn(async move {
17574                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17575                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17576                        let message = diagnostic_entry
17577                            .diagnostic
17578                            .message
17579                            .split_once('\n')
17580                            .map(|(line, _)| line)
17581                            .map(SharedString::new)
17582                            .unwrap_or_else(|| {
17583                                SharedString::from(diagnostic_entry.diagnostic.message)
17584                            });
17585                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17586                        let (Ok(i) | Err(i)) = inline_diagnostics
17587                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17588                        inline_diagnostics.insert(
17589                            i,
17590                            (
17591                                start_anchor,
17592                                InlineDiagnostic {
17593                                    message,
17594                                    group_id: diagnostic_entry.diagnostic.group_id,
17595                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17596                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17597                                    severity: diagnostic_entry.diagnostic.severity,
17598                                },
17599                            ),
17600                        );
17601                    }
17602                    inline_diagnostics
17603                })
17604                .await;
17605
17606            editor
17607                .update(cx, |editor, cx| {
17608                    editor.inline_diagnostics = new_inline_diagnostics;
17609                    cx.notify();
17610                })
17611                .ok();
17612        });
17613    }
17614
17615    fn pull_diagnostics(
17616        &mut self,
17617        buffer_id: Option<BufferId>,
17618        window: &Window,
17619        cx: &mut Context<Self>,
17620    ) -> Option<()> {
17621        if !self.mode().is_full() {
17622            return None;
17623        }
17624        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17625            .diagnostics
17626            .lsp_pull_diagnostics;
17627        if !pull_diagnostics_settings.enabled {
17628            return None;
17629        }
17630        let project = self.project()?.downgrade();
17631        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17632        let mut buffers = self.buffer.read(cx).all_buffers();
17633        if let Some(buffer_id) = buffer_id {
17634            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17635        }
17636
17637        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17638            cx.background_executor().timer(debounce).await;
17639
17640            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17641                buffers
17642                    .into_iter()
17643                    .filter_map(|buffer| {
17644                        project
17645                            .update(cx, |project, cx| {
17646                                project.lsp_store().update(cx, |lsp_store, cx| {
17647                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17648                                })
17649                            })
17650                            .ok()
17651                    })
17652                    .collect::<FuturesUnordered<_>>()
17653            }) else {
17654                return;
17655            };
17656
17657            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17658                match pull_task {
17659                    Ok(()) => {
17660                        if editor
17661                            .update_in(cx, |editor, window, cx| {
17662                                editor.update_diagnostics_state(window, cx);
17663                            })
17664                            .is_err()
17665                        {
17666                            return;
17667                        }
17668                    }
17669                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17670                }
17671            }
17672        });
17673
17674        Some(())
17675    }
17676
17677    pub fn set_selections_from_remote(
17678        &mut self,
17679        selections: Vec<Selection<Anchor>>,
17680        pending_selection: Option<Selection<Anchor>>,
17681        window: &mut Window,
17682        cx: &mut Context<Self>,
17683    ) {
17684        let old_cursor_position = self.selections.newest_anchor().head();
17685        self.selections.change_with(cx, |s| {
17686            s.select_anchors(selections);
17687            if let Some(pending_selection) = pending_selection {
17688                s.set_pending(pending_selection, SelectMode::Character);
17689            } else {
17690                s.clear_pending();
17691            }
17692        });
17693        self.selections_did_change(
17694            false,
17695            &old_cursor_position,
17696            SelectionEffects::default(),
17697            window,
17698            cx,
17699        );
17700    }
17701
17702    pub fn transact(
17703        &mut self,
17704        window: &mut Window,
17705        cx: &mut Context<Self>,
17706        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17707    ) -> Option<TransactionId> {
17708        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17709            this.start_transaction_at(Instant::now(), window, cx);
17710            update(this, window, cx);
17711            this.end_transaction_at(Instant::now(), cx)
17712        })
17713    }
17714
17715    pub fn start_transaction_at(
17716        &mut self,
17717        now: Instant,
17718        window: &mut Window,
17719        cx: &mut Context<Self>,
17720    ) -> Option<TransactionId> {
17721        self.end_selection(window, cx);
17722        if let Some(tx_id) = self
17723            .buffer
17724            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17725        {
17726            self.selection_history
17727                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17728            cx.emit(EditorEvent::TransactionBegun {
17729                transaction_id: tx_id,
17730            });
17731            Some(tx_id)
17732        } else {
17733            None
17734        }
17735    }
17736
17737    pub fn end_transaction_at(
17738        &mut self,
17739        now: Instant,
17740        cx: &mut Context<Self>,
17741    ) -> Option<TransactionId> {
17742        if let Some(transaction_id) = self
17743            .buffer
17744            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17745        {
17746            if let Some((_, end_selections)) =
17747                self.selection_history.transaction_mut(transaction_id)
17748            {
17749                *end_selections = Some(self.selections.disjoint_anchors_arc());
17750            } else {
17751                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17752            }
17753
17754            cx.emit(EditorEvent::Edited { transaction_id });
17755            Some(transaction_id)
17756        } else {
17757            None
17758        }
17759    }
17760
17761    pub fn modify_transaction_selection_history(
17762        &mut self,
17763        transaction_id: TransactionId,
17764        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17765    ) -> bool {
17766        self.selection_history
17767            .transaction_mut(transaction_id)
17768            .map(modify)
17769            .is_some()
17770    }
17771
17772    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17773        if self.selection_mark_mode {
17774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17775                s.move_with(|_, sel| {
17776                    sel.collapse_to(sel.head(), SelectionGoal::None);
17777                });
17778            })
17779        }
17780        self.selection_mark_mode = true;
17781        cx.notify();
17782    }
17783
17784    pub fn swap_selection_ends(
17785        &mut self,
17786        _: &actions::SwapSelectionEnds,
17787        window: &mut Window,
17788        cx: &mut Context<Self>,
17789    ) {
17790        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17791            s.move_with(|_, sel| {
17792                if sel.start != sel.end {
17793                    sel.reversed = !sel.reversed
17794                }
17795            });
17796        });
17797        self.request_autoscroll(Autoscroll::newest(), cx);
17798        cx.notify();
17799    }
17800
17801    pub fn toggle_focus(
17802        workspace: &mut Workspace,
17803        _: &actions::ToggleFocus,
17804        window: &mut Window,
17805        cx: &mut Context<Workspace>,
17806    ) {
17807        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17808            return;
17809        };
17810        workspace.activate_item(&item, true, true, window, cx);
17811    }
17812
17813    pub fn toggle_fold(
17814        &mut self,
17815        _: &actions::ToggleFold,
17816        window: &mut Window,
17817        cx: &mut Context<Self>,
17818    ) {
17819        if self.is_singleton(cx) {
17820            let selection = self.selections.newest::<Point>(cx);
17821
17822            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17823            let range = if selection.is_empty() {
17824                let point = selection.head().to_display_point(&display_map);
17825                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17826                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17827                    .to_point(&display_map);
17828                start..end
17829            } else {
17830                selection.range()
17831            };
17832            if display_map.folds_in_range(range).next().is_some() {
17833                self.unfold_lines(&Default::default(), window, cx)
17834            } else {
17835                self.fold(&Default::default(), window, cx)
17836            }
17837        } else {
17838            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17839            let buffer_ids: HashSet<_> = self
17840                .selections
17841                .disjoint_anchor_ranges()
17842                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17843                .collect();
17844
17845            let should_unfold = buffer_ids
17846                .iter()
17847                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17848
17849            for buffer_id in buffer_ids {
17850                if should_unfold {
17851                    self.unfold_buffer(buffer_id, cx);
17852                } else {
17853                    self.fold_buffer(buffer_id, cx);
17854                }
17855            }
17856        }
17857    }
17858
17859    pub fn toggle_fold_recursive(
17860        &mut self,
17861        _: &actions::ToggleFoldRecursive,
17862        window: &mut Window,
17863        cx: &mut Context<Self>,
17864    ) {
17865        let selection = self.selections.newest::<Point>(cx);
17866
17867        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17868        let range = if selection.is_empty() {
17869            let point = selection.head().to_display_point(&display_map);
17870            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17871            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17872                .to_point(&display_map);
17873            start..end
17874        } else {
17875            selection.range()
17876        };
17877        if display_map.folds_in_range(range).next().is_some() {
17878            self.unfold_recursive(&Default::default(), window, cx)
17879        } else {
17880            self.fold_recursive(&Default::default(), window, cx)
17881        }
17882    }
17883
17884    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17885        if self.is_singleton(cx) {
17886            let mut to_fold = Vec::new();
17887            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17888            let selections = self.selections.all_adjusted(cx);
17889
17890            for selection in selections {
17891                let range = selection.range().sorted();
17892                let buffer_start_row = range.start.row;
17893
17894                if range.start.row != range.end.row {
17895                    let mut found = false;
17896                    let mut row = range.start.row;
17897                    while row <= range.end.row {
17898                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17899                        {
17900                            found = true;
17901                            row = crease.range().end.row + 1;
17902                            to_fold.push(crease);
17903                        } else {
17904                            row += 1
17905                        }
17906                    }
17907                    if found {
17908                        continue;
17909                    }
17910                }
17911
17912                for row in (0..=range.start.row).rev() {
17913                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17914                        && crease.range().end.row >= buffer_start_row
17915                    {
17916                        to_fold.push(crease);
17917                        if row <= range.start.row {
17918                            break;
17919                        }
17920                    }
17921                }
17922            }
17923
17924            self.fold_creases(to_fold, true, window, cx);
17925        } else {
17926            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17927            let buffer_ids = self
17928                .selections
17929                .disjoint_anchor_ranges()
17930                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17931                .collect::<HashSet<_>>();
17932            for buffer_id in buffer_ids {
17933                self.fold_buffer(buffer_id, cx);
17934            }
17935        }
17936    }
17937
17938    pub fn toggle_fold_all(
17939        &mut self,
17940        _: &actions::ToggleFoldAll,
17941        window: &mut Window,
17942        cx: &mut Context<Self>,
17943    ) {
17944        if self.buffer.read(cx).is_singleton() {
17945            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17946            let has_folds = display_map
17947                .folds_in_range(0..display_map.buffer_snapshot.len())
17948                .next()
17949                .is_some();
17950
17951            if has_folds {
17952                self.unfold_all(&actions::UnfoldAll, window, cx);
17953            } else {
17954                self.fold_all(&actions::FoldAll, window, cx);
17955            }
17956        } else {
17957            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17958            let should_unfold = buffer_ids
17959                .iter()
17960                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17961
17962            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17963                editor
17964                    .update_in(cx, |editor, _, cx| {
17965                        for buffer_id in buffer_ids {
17966                            if should_unfold {
17967                                editor.unfold_buffer(buffer_id, cx);
17968                            } else {
17969                                editor.fold_buffer(buffer_id, cx);
17970                            }
17971                        }
17972                    })
17973                    .ok();
17974            });
17975        }
17976    }
17977
17978    fn fold_at_level(
17979        &mut self,
17980        fold_at: &FoldAtLevel,
17981        window: &mut Window,
17982        cx: &mut Context<Self>,
17983    ) {
17984        if !self.buffer.read(cx).is_singleton() {
17985            return;
17986        }
17987
17988        let fold_at_level = fold_at.0;
17989        let snapshot = self.buffer.read(cx).snapshot(cx);
17990        let mut to_fold = Vec::new();
17991        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17992
17993        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17994            while start_row < end_row {
17995                match self
17996                    .snapshot(window, cx)
17997                    .crease_for_buffer_row(MultiBufferRow(start_row))
17998                {
17999                    Some(crease) => {
18000                        let nested_start_row = crease.range().start.row + 1;
18001                        let nested_end_row = crease.range().end.row;
18002
18003                        if current_level < fold_at_level {
18004                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18005                        } else if current_level == fold_at_level {
18006                            to_fold.push(crease);
18007                        }
18008
18009                        start_row = nested_end_row + 1;
18010                    }
18011                    None => start_row += 1,
18012                }
18013            }
18014        }
18015
18016        self.fold_creases(to_fold, true, window, cx);
18017    }
18018
18019    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18020        if self.buffer.read(cx).is_singleton() {
18021            let mut fold_ranges = Vec::new();
18022            let snapshot = self.buffer.read(cx).snapshot(cx);
18023
18024            for row in 0..snapshot.max_row().0 {
18025                if let Some(foldable_range) = self
18026                    .snapshot(window, cx)
18027                    .crease_for_buffer_row(MultiBufferRow(row))
18028                {
18029                    fold_ranges.push(foldable_range);
18030                }
18031            }
18032
18033            self.fold_creases(fold_ranges, true, window, cx);
18034        } else {
18035            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18036                editor
18037                    .update_in(cx, |editor, _, cx| {
18038                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18039                            editor.fold_buffer(buffer_id, cx);
18040                        }
18041                    })
18042                    .ok();
18043            });
18044        }
18045    }
18046
18047    pub fn fold_function_bodies(
18048        &mut self,
18049        _: &actions::FoldFunctionBodies,
18050        window: &mut Window,
18051        cx: &mut Context<Self>,
18052    ) {
18053        let snapshot = self.buffer.read(cx).snapshot(cx);
18054
18055        let ranges = snapshot
18056            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18057            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18058            .collect::<Vec<_>>();
18059
18060        let creases = ranges
18061            .into_iter()
18062            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18063            .collect();
18064
18065        self.fold_creases(creases, true, window, cx);
18066    }
18067
18068    pub fn fold_recursive(
18069        &mut self,
18070        _: &actions::FoldRecursive,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        let mut to_fold = Vec::new();
18075        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18076        let selections = self.selections.all_adjusted(cx);
18077
18078        for selection in selections {
18079            let range = selection.range().sorted();
18080            let buffer_start_row = range.start.row;
18081
18082            if range.start.row != range.end.row {
18083                let mut found = false;
18084                for row in range.start.row..=range.end.row {
18085                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18086                        found = true;
18087                        to_fold.push(crease);
18088                    }
18089                }
18090                if found {
18091                    continue;
18092                }
18093            }
18094
18095            for row in (0..=range.start.row).rev() {
18096                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18097                    if crease.range().end.row >= buffer_start_row {
18098                        to_fold.push(crease);
18099                    } else {
18100                        break;
18101                    }
18102                }
18103            }
18104        }
18105
18106        self.fold_creases(to_fold, true, window, cx);
18107    }
18108
18109    pub fn fold_at(
18110        &mut self,
18111        buffer_row: MultiBufferRow,
18112        window: &mut Window,
18113        cx: &mut Context<Self>,
18114    ) {
18115        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18116
18117        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18118            let autoscroll = self
18119                .selections
18120                .all::<Point>(cx)
18121                .iter()
18122                .any(|selection| crease.range().overlaps(&selection.range()));
18123
18124            self.fold_creases(vec![crease], autoscroll, window, cx);
18125        }
18126    }
18127
18128    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18129        if self.is_singleton(cx) {
18130            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18131            let buffer = &display_map.buffer_snapshot;
18132            let selections = self.selections.all::<Point>(cx);
18133            let ranges = selections
18134                .iter()
18135                .map(|s| {
18136                    let range = s.display_range(&display_map).sorted();
18137                    let mut start = range.start.to_point(&display_map);
18138                    let mut end = range.end.to_point(&display_map);
18139                    start.column = 0;
18140                    end.column = buffer.line_len(MultiBufferRow(end.row));
18141                    start..end
18142                })
18143                .collect::<Vec<_>>();
18144
18145            self.unfold_ranges(&ranges, true, true, cx);
18146        } else {
18147            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18148            let buffer_ids = self
18149                .selections
18150                .disjoint_anchor_ranges()
18151                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18152                .collect::<HashSet<_>>();
18153            for buffer_id in buffer_ids {
18154                self.unfold_buffer(buffer_id, cx);
18155            }
18156        }
18157    }
18158
18159    pub fn unfold_recursive(
18160        &mut self,
18161        _: &UnfoldRecursive,
18162        _window: &mut Window,
18163        cx: &mut Context<Self>,
18164    ) {
18165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18166        let selections = self.selections.all::<Point>(cx);
18167        let ranges = selections
18168            .iter()
18169            .map(|s| {
18170                let mut range = s.display_range(&display_map).sorted();
18171                *range.start.column_mut() = 0;
18172                *range.end.column_mut() = display_map.line_len(range.end.row());
18173                let start = range.start.to_point(&display_map);
18174                let end = range.end.to_point(&display_map);
18175                start..end
18176            })
18177            .collect::<Vec<_>>();
18178
18179        self.unfold_ranges(&ranges, true, true, cx);
18180    }
18181
18182    pub fn unfold_at(
18183        &mut self,
18184        buffer_row: MultiBufferRow,
18185        _window: &mut Window,
18186        cx: &mut Context<Self>,
18187    ) {
18188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18189
18190        let intersection_range = Point::new(buffer_row.0, 0)
18191            ..Point::new(
18192                buffer_row.0,
18193                display_map.buffer_snapshot.line_len(buffer_row),
18194            );
18195
18196        let autoscroll = self
18197            .selections
18198            .all::<Point>(cx)
18199            .iter()
18200            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18201
18202        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18203    }
18204
18205    pub fn unfold_all(
18206        &mut self,
18207        _: &actions::UnfoldAll,
18208        _window: &mut Window,
18209        cx: &mut Context<Self>,
18210    ) {
18211        if self.buffer.read(cx).is_singleton() {
18212            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18213            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18214        } else {
18215            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18216                editor
18217                    .update(cx, |editor, cx| {
18218                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18219                            editor.unfold_buffer(buffer_id, cx);
18220                        }
18221                    })
18222                    .ok();
18223            });
18224        }
18225    }
18226
18227    pub fn fold_selected_ranges(
18228        &mut self,
18229        _: &FoldSelectedRanges,
18230        window: &mut Window,
18231        cx: &mut Context<Self>,
18232    ) {
18233        let selections = self.selections.all_adjusted(cx);
18234        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18235        let ranges = selections
18236            .into_iter()
18237            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18238            .collect::<Vec<_>>();
18239        self.fold_creases(ranges, true, window, cx);
18240    }
18241
18242    pub fn fold_ranges<T: ToOffset + Clone>(
18243        &mut self,
18244        ranges: Vec<Range<T>>,
18245        auto_scroll: bool,
18246        window: &mut Window,
18247        cx: &mut Context<Self>,
18248    ) {
18249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18250        let ranges = ranges
18251            .into_iter()
18252            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18253            .collect::<Vec<_>>();
18254        self.fold_creases(ranges, auto_scroll, window, cx);
18255    }
18256
18257    pub fn fold_creases<T: ToOffset + Clone>(
18258        &mut self,
18259        creases: Vec<Crease<T>>,
18260        auto_scroll: bool,
18261        _window: &mut Window,
18262        cx: &mut Context<Self>,
18263    ) {
18264        if creases.is_empty() {
18265            return;
18266        }
18267
18268        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18269
18270        if auto_scroll {
18271            self.request_autoscroll(Autoscroll::fit(), cx);
18272        }
18273
18274        cx.notify();
18275
18276        self.scrollbar_marker_state.dirty = true;
18277        self.folds_did_change(cx);
18278    }
18279
18280    /// Removes any folds whose ranges intersect any of the given ranges.
18281    pub fn unfold_ranges<T: ToOffset + Clone>(
18282        &mut self,
18283        ranges: &[Range<T>],
18284        inclusive: bool,
18285        auto_scroll: bool,
18286        cx: &mut Context<Self>,
18287    ) {
18288        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18289            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18290        });
18291        self.folds_did_change(cx);
18292    }
18293
18294    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18295        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18296            return;
18297        }
18298        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18299        self.display_map.update(cx, |display_map, cx| {
18300            display_map.fold_buffers([buffer_id], cx)
18301        });
18302        cx.emit(EditorEvent::BufferFoldToggled {
18303            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18304            folded: true,
18305        });
18306        cx.notify();
18307    }
18308
18309    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18310        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18311            return;
18312        }
18313        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18314        self.display_map.update(cx, |display_map, cx| {
18315            display_map.unfold_buffers([buffer_id], cx);
18316        });
18317        cx.emit(EditorEvent::BufferFoldToggled {
18318            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18319            folded: false,
18320        });
18321        cx.notify();
18322    }
18323
18324    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18325        self.display_map.read(cx).is_buffer_folded(buffer)
18326    }
18327
18328    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18329        self.display_map.read(cx).folded_buffers()
18330    }
18331
18332    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18333        self.display_map.update(cx, |display_map, cx| {
18334            display_map.disable_header_for_buffer(buffer_id, cx);
18335        });
18336        cx.notify();
18337    }
18338
18339    /// Removes any folds with the given ranges.
18340    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18341        &mut self,
18342        ranges: &[Range<T>],
18343        type_id: TypeId,
18344        auto_scroll: bool,
18345        cx: &mut Context<Self>,
18346    ) {
18347        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18348            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18349        });
18350        self.folds_did_change(cx);
18351    }
18352
18353    fn remove_folds_with<T: ToOffset + Clone>(
18354        &mut self,
18355        ranges: &[Range<T>],
18356        auto_scroll: bool,
18357        cx: &mut Context<Self>,
18358        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18359    ) {
18360        if ranges.is_empty() {
18361            return;
18362        }
18363
18364        let mut buffers_affected = HashSet::default();
18365        let multi_buffer = self.buffer().read(cx);
18366        for range in ranges {
18367            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18368                buffers_affected.insert(buffer.read(cx).remote_id());
18369            };
18370        }
18371
18372        self.display_map.update(cx, update);
18373
18374        if auto_scroll {
18375            self.request_autoscroll(Autoscroll::fit(), cx);
18376        }
18377
18378        cx.notify();
18379        self.scrollbar_marker_state.dirty = true;
18380        self.active_indent_guides_state.dirty = true;
18381    }
18382
18383    pub fn update_renderer_widths(
18384        &mut self,
18385        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18386        cx: &mut Context<Self>,
18387    ) -> bool {
18388        self.display_map
18389            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18390    }
18391
18392    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18393        self.display_map.read(cx).fold_placeholder.clone()
18394    }
18395
18396    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18397        self.buffer.update(cx, |buffer, cx| {
18398            buffer.set_all_diff_hunks_expanded(cx);
18399        });
18400    }
18401
18402    pub fn expand_all_diff_hunks(
18403        &mut self,
18404        _: &ExpandAllDiffHunks,
18405        _window: &mut Window,
18406        cx: &mut Context<Self>,
18407    ) {
18408        self.buffer.update(cx, |buffer, cx| {
18409            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18410        });
18411    }
18412
18413    pub fn toggle_selected_diff_hunks(
18414        &mut self,
18415        _: &ToggleSelectedDiffHunks,
18416        _window: &mut Window,
18417        cx: &mut Context<Self>,
18418    ) {
18419        let ranges: Vec<_> = self
18420            .selections
18421            .disjoint_anchors()
18422            .iter()
18423            .map(|s| s.range())
18424            .collect();
18425        self.toggle_diff_hunks_in_ranges(ranges, cx);
18426    }
18427
18428    pub fn diff_hunks_in_ranges<'a>(
18429        &'a self,
18430        ranges: &'a [Range<Anchor>],
18431        buffer: &'a MultiBufferSnapshot,
18432    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18433        ranges.iter().flat_map(move |range| {
18434            let end_excerpt_id = range.end.excerpt_id;
18435            let range = range.to_point(buffer);
18436            let mut peek_end = range.end;
18437            if range.end.row < buffer.max_row().0 {
18438                peek_end = Point::new(range.end.row + 1, 0);
18439            }
18440            buffer
18441                .diff_hunks_in_range(range.start..peek_end)
18442                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18443        })
18444    }
18445
18446    pub fn has_stageable_diff_hunks_in_ranges(
18447        &self,
18448        ranges: &[Range<Anchor>],
18449        snapshot: &MultiBufferSnapshot,
18450    ) -> bool {
18451        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18452        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18453    }
18454
18455    pub fn toggle_staged_selected_diff_hunks(
18456        &mut self,
18457        _: &::git::ToggleStaged,
18458        _: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        let snapshot = self.buffer.read(cx).snapshot(cx);
18462        let ranges: Vec<_> = self
18463            .selections
18464            .disjoint_anchors()
18465            .iter()
18466            .map(|s| s.range())
18467            .collect();
18468        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18469        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18470    }
18471
18472    pub fn set_render_diff_hunk_controls(
18473        &mut self,
18474        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18475        cx: &mut Context<Self>,
18476    ) {
18477        self.render_diff_hunk_controls = render_diff_hunk_controls;
18478        cx.notify();
18479    }
18480
18481    pub fn stage_and_next(
18482        &mut self,
18483        _: &::git::StageAndNext,
18484        window: &mut Window,
18485        cx: &mut Context<Self>,
18486    ) {
18487        self.do_stage_or_unstage_and_next(true, window, cx);
18488    }
18489
18490    pub fn unstage_and_next(
18491        &mut self,
18492        _: &::git::UnstageAndNext,
18493        window: &mut Window,
18494        cx: &mut Context<Self>,
18495    ) {
18496        self.do_stage_or_unstage_and_next(false, window, cx);
18497    }
18498
18499    pub fn stage_or_unstage_diff_hunks(
18500        &mut self,
18501        stage: bool,
18502        ranges: Vec<Range<Anchor>>,
18503        cx: &mut Context<Self>,
18504    ) {
18505        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18506        cx.spawn(async move |this, cx| {
18507            task.await?;
18508            this.update(cx, |this, cx| {
18509                let snapshot = this.buffer.read(cx).snapshot(cx);
18510                let chunk_by = this
18511                    .diff_hunks_in_ranges(&ranges, &snapshot)
18512                    .chunk_by(|hunk| hunk.buffer_id);
18513                for (buffer_id, hunks) in &chunk_by {
18514                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18515                }
18516            })
18517        })
18518        .detach_and_log_err(cx);
18519    }
18520
18521    fn save_buffers_for_ranges_if_needed(
18522        &mut self,
18523        ranges: &[Range<Anchor>],
18524        cx: &mut Context<Editor>,
18525    ) -> Task<Result<()>> {
18526        let multibuffer = self.buffer.read(cx);
18527        let snapshot = multibuffer.read(cx);
18528        let buffer_ids: HashSet<_> = ranges
18529            .iter()
18530            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18531            .collect();
18532        drop(snapshot);
18533
18534        let mut buffers = HashSet::default();
18535        for buffer_id in buffer_ids {
18536            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18537                let buffer = buffer_entity.read(cx);
18538                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18539                {
18540                    buffers.insert(buffer_entity);
18541                }
18542            }
18543        }
18544
18545        if let Some(project) = &self.project {
18546            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18547        } else {
18548            Task::ready(Ok(()))
18549        }
18550    }
18551
18552    fn do_stage_or_unstage_and_next(
18553        &mut self,
18554        stage: bool,
18555        window: &mut Window,
18556        cx: &mut Context<Self>,
18557    ) {
18558        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18559
18560        if ranges.iter().any(|range| range.start != range.end) {
18561            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18562            return;
18563        }
18564
18565        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18566        let snapshot = self.snapshot(window, cx);
18567        let position = self.selections.newest::<Point>(cx).head();
18568        let mut row = snapshot
18569            .buffer_snapshot
18570            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18571            .find(|hunk| hunk.row_range.start.0 > position.row)
18572            .map(|hunk| hunk.row_range.start);
18573
18574        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18575        // Outside of the project diff editor, wrap around to the beginning.
18576        if !all_diff_hunks_expanded {
18577            row = row.or_else(|| {
18578                snapshot
18579                    .buffer_snapshot
18580                    .diff_hunks_in_range(Point::zero()..position)
18581                    .find(|hunk| hunk.row_range.end.0 < position.row)
18582                    .map(|hunk| hunk.row_range.start)
18583            });
18584        }
18585
18586        if let Some(row) = row {
18587            let destination = Point::new(row.0, 0);
18588            let autoscroll = Autoscroll::center();
18589
18590            self.unfold_ranges(&[destination..destination], false, false, cx);
18591            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18592                s.select_ranges([destination..destination]);
18593            });
18594        }
18595    }
18596
18597    fn do_stage_or_unstage(
18598        &self,
18599        stage: bool,
18600        buffer_id: BufferId,
18601        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18602        cx: &mut App,
18603    ) -> Option<()> {
18604        let project = self.project()?;
18605        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18606        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18607        let buffer_snapshot = buffer.read(cx).snapshot();
18608        let file_exists = buffer_snapshot
18609            .file()
18610            .is_some_and(|file| file.disk_state().exists());
18611        diff.update(cx, |diff, cx| {
18612            diff.stage_or_unstage_hunks(
18613                stage,
18614                &hunks
18615                    .map(|hunk| buffer_diff::DiffHunk {
18616                        buffer_range: hunk.buffer_range,
18617                        diff_base_byte_range: hunk.diff_base_byte_range,
18618                        secondary_status: hunk.secondary_status,
18619                        range: Point::zero()..Point::zero(), // unused
18620                    })
18621                    .collect::<Vec<_>>(),
18622                &buffer_snapshot,
18623                file_exists,
18624                cx,
18625            )
18626        });
18627        None
18628    }
18629
18630    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18631        let ranges: Vec<_> = self
18632            .selections
18633            .disjoint_anchors()
18634            .iter()
18635            .map(|s| s.range())
18636            .collect();
18637        self.buffer
18638            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18639    }
18640
18641    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18642        self.buffer.update(cx, |buffer, cx| {
18643            let ranges = vec![Anchor::min()..Anchor::max()];
18644            if !buffer.all_diff_hunks_expanded()
18645                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18646            {
18647                buffer.collapse_diff_hunks(ranges, cx);
18648                true
18649            } else {
18650                false
18651            }
18652        })
18653    }
18654
18655    fn toggle_diff_hunks_in_ranges(
18656        &mut self,
18657        ranges: Vec<Range<Anchor>>,
18658        cx: &mut Context<Editor>,
18659    ) {
18660        self.buffer.update(cx, |buffer, cx| {
18661            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18662            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18663        })
18664    }
18665
18666    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18667        self.buffer.update(cx, |buffer, cx| {
18668            let snapshot = buffer.snapshot(cx);
18669            let excerpt_id = range.end.excerpt_id;
18670            let point_range = range.to_point(&snapshot);
18671            let expand = !buffer.single_hunk_is_expanded(range, cx);
18672            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18673        })
18674    }
18675
18676    pub(crate) fn apply_all_diff_hunks(
18677        &mut self,
18678        _: &ApplyAllDiffHunks,
18679        window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18683
18684        let buffers = self.buffer.read(cx).all_buffers();
18685        for branch_buffer in buffers {
18686            branch_buffer.update(cx, |branch_buffer, cx| {
18687                branch_buffer.merge_into_base(Vec::new(), cx);
18688            });
18689        }
18690
18691        if let Some(project) = self.project.clone() {
18692            self.save(
18693                SaveOptions {
18694                    format: true,
18695                    autosave: false,
18696                },
18697                project,
18698                window,
18699                cx,
18700            )
18701            .detach_and_log_err(cx);
18702        }
18703    }
18704
18705    pub(crate) fn apply_selected_diff_hunks(
18706        &mut self,
18707        _: &ApplyDiffHunk,
18708        window: &mut Window,
18709        cx: &mut Context<Self>,
18710    ) {
18711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18712        let snapshot = self.snapshot(window, cx);
18713        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18714        let mut ranges_by_buffer = HashMap::default();
18715        self.transact(window, cx, |editor, _window, cx| {
18716            for hunk in hunks {
18717                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18718                    ranges_by_buffer
18719                        .entry(buffer.clone())
18720                        .or_insert_with(Vec::new)
18721                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18722                }
18723            }
18724
18725            for (buffer, ranges) in ranges_by_buffer {
18726                buffer.update(cx, |buffer, cx| {
18727                    buffer.merge_into_base(ranges, cx);
18728                });
18729            }
18730        });
18731
18732        if let Some(project) = self.project.clone() {
18733            self.save(
18734                SaveOptions {
18735                    format: true,
18736                    autosave: false,
18737                },
18738                project,
18739                window,
18740                cx,
18741            )
18742            .detach_and_log_err(cx);
18743        }
18744    }
18745
18746    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18747        if hovered != self.gutter_hovered {
18748            self.gutter_hovered = hovered;
18749            cx.notify();
18750        }
18751    }
18752
18753    pub fn insert_blocks(
18754        &mut self,
18755        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18756        autoscroll: Option<Autoscroll>,
18757        cx: &mut Context<Self>,
18758    ) -> Vec<CustomBlockId> {
18759        let blocks = self
18760            .display_map
18761            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18762        if let Some(autoscroll) = autoscroll {
18763            self.request_autoscroll(autoscroll, cx);
18764        }
18765        cx.notify();
18766        blocks
18767    }
18768
18769    pub fn resize_blocks(
18770        &mut self,
18771        heights: HashMap<CustomBlockId, u32>,
18772        autoscroll: Option<Autoscroll>,
18773        cx: &mut Context<Self>,
18774    ) {
18775        self.display_map
18776            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18777        if let Some(autoscroll) = autoscroll {
18778            self.request_autoscroll(autoscroll, cx);
18779        }
18780        cx.notify();
18781    }
18782
18783    pub fn replace_blocks(
18784        &mut self,
18785        renderers: HashMap<CustomBlockId, RenderBlock>,
18786        autoscroll: Option<Autoscroll>,
18787        cx: &mut Context<Self>,
18788    ) {
18789        self.display_map
18790            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18791        if let Some(autoscroll) = autoscroll {
18792            self.request_autoscroll(autoscroll, cx);
18793        }
18794        cx.notify();
18795    }
18796
18797    pub fn remove_blocks(
18798        &mut self,
18799        block_ids: HashSet<CustomBlockId>,
18800        autoscroll: Option<Autoscroll>,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.display_map.update(cx, |display_map, cx| {
18804            display_map.remove_blocks(block_ids, cx)
18805        });
18806        if let Some(autoscroll) = autoscroll {
18807            self.request_autoscroll(autoscroll, cx);
18808        }
18809        cx.notify();
18810    }
18811
18812    pub fn row_for_block(
18813        &self,
18814        block_id: CustomBlockId,
18815        cx: &mut Context<Self>,
18816    ) -> Option<DisplayRow> {
18817        self.display_map
18818            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18819    }
18820
18821    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18822        self.focused_block = Some(focused_block);
18823    }
18824
18825    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18826        self.focused_block.take()
18827    }
18828
18829    pub fn insert_creases(
18830        &mut self,
18831        creases: impl IntoIterator<Item = Crease<Anchor>>,
18832        cx: &mut Context<Self>,
18833    ) -> Vec<CreaseId> {
18834        self.display_map
18835            .update(cx, |map, cx| map.insert_creases(creases, cx))
18836    }
18837
18838    pub fn remove_creases(
18839        &mut self,
18840        ids: impl IntoIterator<Item = CreaseId>,
18841        cx: &mut Context<Self>,
18842    ) -> Vec<(CreaseId, Range<Anchor>)> {
18843        self.display_map
18844            .update(cx, |map, cx| map.remove_creases(ids, cx))
18845    }
18846
18847    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18848        self.display_map
18849            .update(cx, |map, cx| map.snapshot(cx))
18850            .longest_row()
18851    }
18852
18853    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18854        self.display_map
18855            .update(cx, |map, cx| map.snapshot(cx))
18856            .max_point()
18857    }
18858
18859    pub fn text(&self, cx: &App) -> String {
18860        self.buffer.read(cx).read(cx).text()
18861    }
18862
18863    pub fn is_empty(&self, cx: &App) -> bool {
18864        self.buffer.read(cx).read(cx).is_empty()
18865    }
18866
18867    pub fn text_option(&self, cx: &App) -> Option<String> {
18868        let text = self.text(cx);
18869        let text = text.trim();
18870
18871        if text.is_empty() {
18872            return None;
18873        }
18874
18875        Some(text.to_string())
18876    }
18877
18878    pub fn set_text(
18879        &mut self,
18880        text: impl Into<Arc<str>>,
18881        window: &mut Window,
18882        cx: &mut Context<Self>,
18883    ) {
18884        self.transact(window, cx, |this, _, cx| {
18885            this.buffer
18886                .read(cx)
18887                .as_singleton()
18888                .expect("you can only call set_text on editors for singleton buffers")
18889                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18890        });
18891    }
18892
18893    pub fn display_text(&self, cx: &mut App) -> String {
18894        self.display_map
18895            .update(cx, |map, cx| map.snapshot(cx))
18896            .text()
18897    }
18898
18899    fn create_minimap(
18900        &self,
18901        minimap_settings: MinimapSettings,
18902        window: &mut Window,
18903        cx: &mut Context<Self>,
18904    ) -> Option<Entity<Self>> {
18905        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18906            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18907    }
18908
18909    fn initialize_new_minimap(
18910        &self,
18911        minimap_settings: MinimapSettings,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) -> Entity<Self> {
18915        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18916
18917        let mut minimap = Editor::new_internal(
18918            EditorMode::Minimap {
18919                parent: cx.weak_entity(),
18920            },
18921            self.buffer.clone(),
18922            None,
18923            Some(self.display_map.clone()),
18924            window,
18925            cx,
18926        );
18927        minimap.scroll_manager.clone_state(&self.scroll_manager);
18928        minimap.set_text_style_refinement(TextStyleRefinement {
18929            font_size: Some(MINIMAP_FONT_SIZE),
18930            font_weight: Some(MINIMAP_FONT_WEIGHT),
18931            ..Default::default()
18932        });
18933        minimap.update_minimap_configuration(minimap_settings, cx);
18934        cx.new(|_| minimap)
18935    }
18936
18937    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18938        let current_line_highlight = minimap_settings
18939            .current_line_highlight
18940            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18941        self.set_current_line_highlight(Some(current_line_highlight));
18942    }
18943
18944    pub fn minimap(&self) -> Option<&Entity<Self>> {
18945        self.minimap
18946            .as_ref()
18947            .filter(|_| self.minimap_visibility.visible())
18948    }
18949
18950    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18951        let mut wrap_guides = smallvec![];
18952
18953        if self.show_wrap_guides == Some(false) {
18954            return wrap_guides;
18955        }
18956
18957        let settings = self.buffer.read(cx).language_settings(cx);
18958        if settings.show_wrap_guides {
18959            match self.soft_wrap_mode(cx) {
18960                SoftWrap::Column(soft_wrap) => {
18961                    wrap_guides.push((soft_wrap as usize, true));
18962                }
18963                SoftWrap::Bounded(soft_wrap) => {
18964                    wrap_guides.push((soft_wrap as usize, true));
18965                }
18966                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18967            }
18968            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18969        }
18970
18971        wrap_guides
18972    }
18973
18974    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18975        let settings = self.buffer.read(cx).language_settings(cx);
18976        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18977        match mode {
18978            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18979                SoftWrap::None
18980            }
18981            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18982            language_settings::SoftWrap::PreferredLineLength => {
18983                SoftWrap::Column(settings.preferred_line_length)
18984            }
18985            language_settings::SoftWrap::Bounded => {
18986                SoftWrap::Bounded(settings.preferred_line_length)
18987            }
18988        }
18989    }
18990
18991    pub fn set_soft_wrap_mode(
18992        &mut self,
18993        mode: language_settings::SoftWrap,
18994
18995        cx: &mut Context<Self>,
18996    ) {
18997        self.soft_wrap_mode_override = Some(mode);
18998        cx.notify();
18999    }
19000
19001    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19002        self.hard_wrap = hard_wrap;
19003        cx.notify();
19004    }
19005
19006    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19007        self.text_style_refinement = Some(style);
19008    }
19009
19010    /// called by the Element so we know what style we were most recently rendered with.
19011    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19012        // We intentionally do not inform the display map about the minimap style
19013        // so that wrapping is not recalculated and stays consistent for the editor
19014        // and its linked minimap.
19015        if !self.mode.is_minimap() {
19016            let font = style.text.font();
19017            let font_size = style.text.font_size.to_pixels(window.rem_size());
19018            let display_map = self
19019                .placeholder_display_map
19020                .as_ref()
19021                .filter(|_| self.is_empty(cx))
19022                .unwrap_or(&self.display_map);
19023
19024            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19025        }
19026        self.style = Some(style);
19027    }
19028
19029    pub fn style(&self) -> Option<&EditorStyle> {
19030        self.style.as_ref()
19031    }
19032
19033    // Called by the element. This method is not designed to be called outside of the editor
19034    // element's layout code because it does not notify when rewrapping is computed synchronously.
19035    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19036        if self.is_empty(cx) {
19037            self.placeholder_display_map
19038                .as_ref()
19039                .map_or(false, |display_map| {
19040                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19041                })
19042        } else {
19043            self.display_map
19044                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19045        }
19046    }
19047
19048    pub fn set_soft_wrap(&mut self) {
19049        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19050    }
19051
19052    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19053        if self.soft_wrap_mode_override.is_some() {
19054            self.soft_wrap_mode_override.take();
19055        } else {
19056            let soft_wrap = match self.soft_wrap_mode(cx) {
19057                SoftWrap::GitDiff => return,
19058                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19059                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19060                    language_settings::SoftWrap::None
19061                }
19062            };
19063            self.soft_wrap_mode_override = Some(soft_wrap);
19064        }
19065        cx.notify();
19066    }
19067
19068    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19069        let Some(workspace) = self.workspace() else {
19070            return;
19071        };
19072        let fs = workspace.read(cx).app_state().fs.clone();
19073        let current_show = TabBarSettings::get_global(cx).show;
19074        update_settings_file(fs, cx, move |setting, _| {
19075            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19076        });
19077    }
19078
19079    pub fn toggle_indent_guides(
19080        &mut self,
19081        _: &ToggleIndentGuides,
19082        _: &mut Window,
19083        cx: &mut Context<Self>,
19084    ) {
19085        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19086            self.buffer
19087                .read(cx)
19088                .language_settings(cx)
19089                .indent_guides
19090                .enabled
19091        });
19092        self.show_indent_guides = Some(!currently_enabled);
19093        cx.notify();
19094    }
19095
19096    fn should_show_indent_guides(&self) -> Option<bool> {
19097        self.show_indent_guides
19098    }
19099
19100    pub fn toggle_line_numbers(
19101        &mut self,
19102        _: &ToggleLineNumbers,
19103        _: &mut Window,
19104        cx: &mut Context<Self>,
19105    ) {
19106        let mut editor_settings = EditorSettings::get_global(cx).clone();
19107        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19108        EditorSettings::override_global(editor_settings, cx);
19109    }
19110
19111    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19112        if let Some(show_line_numbers) = self.show_line_numbers {
19113            return show_line_numbers;
19114        }
19115        EditorSettings::get_global(cx).gutter.line_numbers
19116    }
19117
19118    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19119        self.use_relative_line_numbers
19120            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19121    }
19122
19123    pub fn toggle_relative_line_numbers(
19124        &mut self,
19125        _: &ToggleRelativeLineNumbers,
19126        _: &mut Window,
19127        cx: &mut Context<Self>,
19128    ) {
19129        let is_relative = self.should_use_relative_line_numbers(cx);
19130        self.set_relative_line_number(Some(!is_relative), cx)
19131    }
19132
19133    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19134        self.use_relative_line_numbers = is_relative;
19135        cx.notify();
19136    }
19137
19138    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19139        self.show_gutter = show_gutter;
19140        cx.notify();
19141    }
19142
19143    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19144        self.show_scrollbars = ScrollbarAxes {
19145            horizontal: show,
19146            vertical: show,
19147        };
19148        cx.notify();
19149    }
19150
19151    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19152        self.show_scrollbars.vertical = show;
19153        cx.notify();
19154    }
19155
19156    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19157        self.show_scrollbars.horizontal = show;
19158        cx.notify();
19159    }
19160
19161    pub fn set_minimap_visibility(
19162        &mut self,
19163        minimap_visibility: MinimapVisibility,
19164        window: &mut Window,
19165        cx: &mut Context<Self>,
19166    ) {
19167        if self.minimap_visibility != minimap_visibility {
19168            if minimap_visibility.visible() && self.minimap.is_none() {
19169                let minimap_settings = EditorSettings::get_global(cx).minimap;
19170                self.minimap =
19171                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19172            }
19173            self.minimap_visibility = minimap_visibility;
19174            cx.notify();
19175        }
19176    }
19177
19178    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19179        self.set_show_scrollbars(false, cx);
19180        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19181    }
19182
19183    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19184        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19185    }
19186
19187    /// Normally the text in full mode and auto height editors is padded on the
19188    /// left side by roughly half a character width for improved hit testing.
19189    ///
19190    /// Use this method to disable this for cases where this is not wanted (e.g.
19191    /// if you want to align the editor text with some other text above or below)
19192    /// or if you want to add this padding to single-line editors.
19193    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19194        self.offset_content = offset_content;
19195        cx.notify();
19196    }
19197
19198    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19199        self.show_line_numbers = Some(show_line_numbers);
19200        cx.notify();
19201    }
19202
19203    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19204        self.disable_expand_excerpt_buttons = true;
19205        cx.notify();
19206    }
19207
19208    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19209        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19210        cx.notify();
19211    }
19212
19213    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19214        self.show_code_actions = Some(show_code_actions);
19215        cx.notify();
19216    }
19217
19218    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19219        self.show_runnables = Some(show_runnables);
19220        cx.notify();
19221    }
19222
19223    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19224        self.show_breakpoints = Some(show_breakpoints);
19225        cx.notify();
19226    }
19227
19228    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19229        if self.display_map.read(cx).masked != masked {
19230            self.display_map.update(cx, |map, _| map.masked = masked);
19231        }
19232        cx.notify()
19233    }
19234
19235    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19236        self.show_wrap_guides = Some(show_wrap_guides);
19237        cx.notify();
19238    }
19239
19240    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19241        self.show_indent_guides = Some(show_indent_guides);
19242        cx.notify();
19243    }
19244
19245    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19246        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19247            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19248                && let Some(dir) = file.abs_path(cx).parent()
19249            {
19250                return Some(dir.to_owned());
19251            }
19252
19253            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19254                return Some(project_path.path.to_path_buf());
19255            }
19256        }
19257
19258        None
19259    }
19260
19261    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19262        self.active_excerpt(cx)?
19263            .1
19264            .read(cx)
19265            .file()
19266            .and_then(|f| f.as_local())
19267    }
19268
19269    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19270        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19271            let buffer = buffer.read(cx);
19272            if let Some(project_path) = buffer.project_path(cx) {
19273                let project = self.project()?.read(cx);
19274                project.absolute_path(&project_path, cx)
19275            } else {
19276                buffer
19277                    .file()
19278                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19279            }
19280        })
19281    }
19282
19283    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19284        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19285            let project_path = buffer.read(cx).project_path(cx)?;
19286            let project = self.project()?.read(cx);
19287            let entry = project.entry_for_path(&project_path, cx)?;
19288            let path = entry.path.to_path_buf();
19289            Some(path)
19290        })
19291    }
19292
19293    pub fn reveal_in_finder(
19294        &mut self,
19295        _: &RevealInFileManager,
19296        _window: &mut Window,
19297        cx: &mut Context<Self>,
19298    ) {
19299        if let Some(target) = self.target_file(cx) {
19300            cx.reveal_path(&target.abs_path(cx));
19301        }
19302    }
19303
19304    pub fn copy_path(
19305        &mut self,
19306        _: &zed_actions::workspace::CopyPath,
19307        _window: &mut Window,
19308        cx: &mut Context<Self>,
19309    ) {
19310        if let Some(path) = self.target_file_abs_path(cx)
19311            && let Some(path) = path.to_str()
19312        {
19313            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19314        } else {
19315            cx.propagate();
19316        }
19317    }
19318
19319    pub fn copy_relative_path(
19320        &mut self,
19321        _: &zed_actions::workspace::CopyRelativePath,
19322        _window: &mut Window,
19323        cx: &mut Context<Self>,
19324    ) {
19325        if let Some(path) = self.target_file_path(cx)
19326            && let Some(path) = path.to_str()
19327        {
19328            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19329        } else {
19330            cx.propagate();
19331        }
19332    }
19333
19334    /// Returns the project path for the editor's buffer, if any buffer is
19335    /// opened in the editor.
19336    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19337        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19338            buffer.read(cx).project_path(cx)
19339        } else {
19340            None
19341        }
19342    }
19343
19344    // Returns true if the editor handled a go-to-line request
19345    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19346        maybe!({
19347            let breakpoint_store = self.breakpoint_store.as_ref()?;
19348
19349            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19350            else {
19351                self.clear_row_highlights::<ActiveDebugLine>();
19352                return None;
19353            };
19354
19355            let position = active_stack_frame.position;
19356            let buffer_id = position.buffer_id?;
19357            let snapshot = self
19358                .project
19359                .as_ref()?
19360                .read(cx)
19361                .buffer_for_id(buffer_id, cx)?
19362                .read(cx)
19363                .snapshot();
19364
19365            let mut handled = false;
19366            for (id, ExcerptRange { context, .. }) in
19367                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19368            {
19369                if context.start.cmp(&position, &snapshot).is_ge()
19370                    || context.end.cmp(&position, &snapshot).is_lt()
19371                {
19372                    continue;
19373                }
19374                let snapshot = self.buffer.read(cx).snapshot(cx);
19375                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19376
19377                handled = true;
19378                self.clear_row_highlights::<ActiveDebugLine>();
19379
19380                self.go_to_line::<ActiveDebugLine>(
19381                    multibuffer_anchor,
19382                    Some(cx.theme().colors().editor_debugger_active_line_background),
19383                    window,
19384                    cx,
19385                );
19386
19387                cx.notify();
19388            }
19389
19390            handled.then_some(())
19391        })
19392        .is_some()
19393    }
19394
19395    pub fn copy_file_name_without_extension(
19396        &mut self,
19397        _: &CopyFileNameWithoutExtension,
19398        _: &mut Window,
19399        cx: &mut Context<Self>,
19400    ) {
19401        if let Some(file) = self.target_file(cx)
19402            && let Some(file_stem) = file.path().file_stem()
19403            && let Some(name) = file_stem.to_str()
19404        {
19405            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19406        }
19407    }
19408
19409    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19410        if let Some(file) = self.target_file(cx)
19411            && let Some(file_name) = file.path().file_name()
19412            && let Some(name) = file_name.to_str()
19413        {
19414            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19415        }
19416    }
19417
19418    pub fn toggle_git_blame(
19419        &mut self,
19420        _: &::git::Blame,
19421        window: &mut Window,
19422        cx: &mut Context<Self>,
19423    ) {
19424        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19425
19426        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19427            self.start_git_blame(true, window, cx);
19428        }
19429
19430        cx.notify();
19431    }
19432
19433    pub fn toggle_git_blame_inline(
19434        &mut self,
19435        _: &ToggleGitBlameInline,
19436        window: &mut Window,
19437        cx: &mut Context<Self>,
19438    ) {
19439        self.toggle_git_blame_inline_internal(true, window, cx);
19440        cx.notify();
19441    }
19442
19443    pub fn open_git_blame_commit(
19444        &mut self,
19445        _: &OpenGitBlameCommit,
19446        window: &mut Window,
19447        cx: &mut Context<Self>,
19448    ) {
19449        self.open_git_blame_commit_internal(window, cx);
19450    }
19451
19452    fn open_git_blame_commit_internal(
19453        &mut self,
19454        window: &mut Window,
19455        cx: &mut Context<Self>,
19456    ) -> Option<()> {
19457        let blame = self.blame.as_ref()?;
19458        let snapshot = self.snapshot(window, cx);
19459        let cursor = self.selections.newest::<Point>(cx).head();
19460        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19461        let (_, blame_entry) = blame
19462            .update(cx, |blame, cx| {
19463                blame
19464                    .blame_for_rows(
19465                        &[RowInfo {
19466                            buffer_id: Some(buffer.remote_id()),
19467                            buffer_row: Some(point.row),
19468                            ..Default::default()
19469                        }],
19470                        cx,
19471                    )
19472                    .next()
19473            })
19474            .flatten()?;
19475        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19476        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19477        let workspace = self.workspace()?.downgrade();
19478        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19479        None
19480    }
19481
19482    pub fn git_blame_inline_enabled(&self) -> bool {
19483        self.git_blame_inline_enabled
19484    }
19485
19486    pub fn toggle_selection_menu(
19487        &mut self,
19488        _: &ToggleSelectionMenu,
19489        _: &mut Window,
19490        cx: &mut Context<Self>,
19491    ) {
19492        self.show_selection_menu = self
19493            .show_selection_menu
19494            .map(|show_selections_menu| !show_selections_menu)
19495            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19496
19497        cx.notify();
19498    }
19499
19500    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19501        self.show_selection_menu
19502            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19503    }
19504
19505    fn start_git_blame(
19506        &mut self,
19507        user_triggered: bool,
19508        window: &mut Window,
19509        cx: &mut Context<Self>,
19510    ) {
19511        if let Some(project) = self.project() {
19512            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19513                && buffer.read(cx).file().is_none()
19514            {
19515                return;
19516            }
19517
19518            let focused = self.focus_handle(cx).contains_focused(window, cx);
19519
19520            let project = project.clone();
19521            let blame = cx
19522                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19523            self.blame_subscription =
19524                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19525            self.blame = Some(blame);
19526        }
19527    }
19528
19529    fn toggle_git_blame_inline_internal(
19530        &mut self,
19531        user_triggered: bool,
19532        window: &mut Window,
19533        cx: &mut Context<Self>,
19534    ) {
19535        if self.git_blame_inline_enabled {
19536            self.git_blame_inline_enabled = false;
19537            self.show_git_blame_inline = false;
19538            self.show_git_blame_inline_delay_task.take();
19539        } else {
19540            self.git_blame_inline_enabled = true;
19541            self.start_git_blame_inline(user_triggered, window, cx);
19542        }
19543
19544        cx.notify();
19545    }
19546
19547    fn start_git_blame_inline(
19548        &mut self,
19549        user_triggered: bool,
19550        window: &mut Window,
19551        cx: &mut Context<Self>,
19552    ) {
19553        self.start_git_blame(user_triggered, window, cx);
19554
19555        if ProjectSettings::get_global(cx)
19556            .git
19557            .inline_blame_delay()
19558            .is_some()
19559        {
19560            self.start_inline_blame_timer(window, cx);
19561        } else {
19562            self.show_git_blame_inline = true
19563        }
19564    }
19565
19566    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19567        self.blame.as_ref()
19568    }
19569
19570    pub fn show_git_blame_gutter(&self) -> bool {
19571        self.show_git_blame_gutter
19572    }
19573
19574    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19575        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19576    }
19577
19578    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19579        self.show_git_blame_inline
19580            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19581            && !self.newest_selection_head_on_empty_line(cx)
19582            && self.has_blame_entries(cx)
19583    }
19584
19585    fn has_blame_entries(&self, cx: &App) -> bool {
19586        self.blame()
19587            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19588    }
19589
19590    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19591        let cursor_anchor = self.selections.newest_anchor().head();
19592
19593        let snapshot = self.buffer.read(cx).snapshot(cx);
19594        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19595
19596        snapshot.line_len(buffer_row) == 0
19597    }
19598
19599    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19600        let buffer_and_selection = maybe!({
19601            let selection = self.selections.newest::<Point>(cx);
19602            let selection_range = selection.range();
19603
19604            let multi_buffer = self.buffer().read(cx);
19605            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19606            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19607
19608            let (buffer, range, _) = if selection.reversed {
19609                buffer_ranges.first()
19610            } else {
19611                buffer_ranges.last()
19612            }?;
19613
19614            let selection = text::ToPoint::to_point(&range.start, buffer).row
19615                ..text::ToPoint::to_point(&range.end, buffer).row;
19616            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19617        });
19618
19619        let Some((buffer, selection)) = buffer_and_selection else {
19620            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19621        };
19622
19623        let Some(project) = self.project() else {
19624            return Task::ready(Err(anyhow!("editor does not have project")));
19625        };
19626
19627        project.update(cx, |project, cx| {
19628            project.get_permalink_to_line(&buffer, selection, cx)
19629        })
19630    }
19631
19632    pub fn copy_permalink_to_line(
19633        &mut self,
19634        _: &CopyPermalinkToLine,
19635        window: &mut Window,
19636        cx: &mut Context<Self>,
19637    ) {
19638        let permalink_task = self.get_permalink_to_line(cx);
19639        let workspace = self.workspace();
19640
19641        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19642            Ok(permalink) => {
19643                cx.update(|_, cx| {
19644                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19645                })
19646                .ok();
19647            }
19648            Err(err) => {
19649                let message = format!("Failed to copy permalink: {err}");
19650
19651                anyhow::Result::<()>::Err(err).log_err();
19652
19653                if let Some(workspace) = workspace {
19654                    workspace
19655                        .update_in(cx, |workspace, _, cx| {
19656                            struct CopyPermalinkToLine;
19657
19658                            workspace.show_toast(
19659                                Toast::new(
19660                                    NotificationId::unique::<CopyPermalinkToLine>(),
19661                                    message,
19662                                ),
19663                                cx,
19664                            )
19665                        })
19666                        .ok();
19667                }
19668            }
19669        })
19670        .detach();
19671    }
19672
19673    pub fn copy_file_location(
19674        &mut self,
19675        _: &CopyFileLocation,
19676        _: &mut Window,
19677        cx: &mut Context<Self>,
19678    ) {
19679        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19680        if let Some(file) = self.target_file(cx)
19681            && let Some(path) = file.path().to_str()
19682        {
19683            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19684        }
19685    }
19686
19687    pub fn open_permalink_to_line(
19688        &mut self,
19689        _: &OpenPermalinkToLine,
19690        window: &mut Window,
19691        cx: &mut Context<Self>,
19692    ) {
19693        let permalink_task = self.get_permalink_to_line(cx);
19694        let workspace = self.workspace();
19695
19696        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19697            Ok(permalink) => {
19698                cx.update(|_, cx| {
19699                    cx.open_url(permalink.as_ref());
19700                })
19701                .ok();
19702            }
19703            Err(err) => {
19704                let message = format!("Failed to open permalink: {err}");
19705
19706                anyhow::Result::<()>::Err(err).log_err();
19707
19708                if let Some(workspace) = workspace {
19709                    workspace
19710                        .update(cx, |workspace, cx| {
19711                            struct OpenPermalinkToLine;
19712
19713                            workspace.show_toast(
19714                                Toast::new(
19715                                    NotificationId::unique::<OpenPermalinkToLine>(),
19716                                    message,
19717                                ),
19718                                cx,
19719                            )
19720                        })
19721                        .ok();
19722                }
19723            }
19724        })
19725        .detach();
19726    }
19727
19728    pub fn insert_uuid_v4(
19729        &mut self,
19730        _: &InsertUuidV4,
19731        window: &mut Window,
19732        cx: &mut Context<Self>,
19733    ) {
19734        self.insert_uuid(UuidVersion::V4, window, cx);
19735    }
19736
19737    pub fn insert_uuid_v7(
19738        &mut self,
19739        _: &InsertUuidV7,
19740        window: &mut Window,
19741        cx: &mut Context<Self>,
19742    ) {
19743        self.insert_uuid(UuidVersion::V7, window, cx);
19744    }
19745
19746    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19748        self.transact(window, cx, |this, window, cx| {
19749            let edits = this
19750                .selections
19751                .all::<Point>(cx)
19752                .into_iter()
19753                .map(|selection| {
19754                    let uuid = match version {
19755                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19756                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19757                    };
19758
19759                    (selection.range(), uuid.to_string())
19760                });
19761            this.edit(edits, cx);
19762            this.refresh_edit_prediction(true, false, window, cx);
19763        });
19764    }
19765
19766    pub fn open_selections_in_multibuffer(
19767        &mut self,
19768        _: &OpenSelectionsInMultibuffer,
19769        window: &mut Window,
19770        cx: &mut Context<Self>,
19771    ) {
19772        let multibuffer = self.buffer.read(cx);
19773
19774        let Some(buffer) = multibuffer.as_singleton() else {
19775            return;
19776        };
19777
19778        let Some(workspace) = self.workspace() else {
19779            return;
19780        };
19781
19782        let title = multibuffer.title(cx).to_string();
19783
19784        let locations = self
19785            .selections
19786            .all_anchors(cx)
19787            .iter()
19788            .map(|selection| {
19789                (
19790                    buffer.clone(),
19791                    (selection.start.text_anchor..selection.end.text_anchor)
19792                        .to_point(buffer.read(cx)),
19793                )
19794            })
19795            .into_group_map();
19796
19797        cx.spawn_in(window, async move |_, cx| {
19798            workspace.update_in(cx, |workspace, window, cx| {
19799                Self::open_locations_in_multibuffer(
19800                    workspace,
19801                    locations,
19802                    format!("Selections for '{title}'"),
19803                    false,
19804                    MultibufferSelectionMode::All,
19805                    window,
19806                    cx,
19807                );
19808            })
19809        })
19810        .detach();
19811    }
19812
19813    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19814    /// last highlight added will be used.
19815    ///
19816    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19817    pub fn highlight_rows<T: 'static>(
19818        &mut self,
19819        range: Range<Anchor>,
19820        color: Hsla,
19821        options: RowHighlightOptions,
19822        cx: &mut Context<Self>,
19823    ) {
19824        let snapshot = self.buffer().read(cx).snapshot(cx);
19825        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19826        let ix = row_highlights.binary_search_by(|highlight| {
19827            Ordering::Equal
19828                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19829                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19830        });
19831
19832        if let Err(mut ix) = ix {
19833            let index = post_inc(&mut self.highlight_order);
19834
19835            // If this range intersects with the preceding highlight, then merge it with
19836            // the preceding highlight. Otherwise insert a new highlight.
19837            let mut merged = false;
19838            if ix > 0 {
19839                let prev_highlight = &mut row_highlights[ix - 1];
19840                if prev_highlight
19841                    .range
19842                    .end
19843                    .cmp(&range.start, &snapshot)
19844                    .is_ge()
19845                {
19846                    ix -= 1;
19847                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19848                        prev_highlight.range.end = range.end;
19849                    }
19850                    merged = true;
19851                    prev_highlight.index = index;
19852                    prev_highlight.color = color;
19853                    prev_highlight.options = options;
19854                }
19855            }
19856
19857            if !merged {
19858                row_highlights.insert(
19859                    ix,
19860                    RowHighlight {
19861                        range,
19862                        index,
19863                        color,
19864                        options,
19865                        type_id: TypeId::of::<T>(),
19866                    },
19867                );
19868            }
19869
19870            // If any of the following highlights intersect with this one, merge them.
19871            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19872                let highlight = &row_highlights[ix];
19873                if next_highlight
19874                    .range
19875                    .start
19876                    .cmp(&highlight.range.end, &snapshot)
19877                    .is_le()
19878                {
19879                    if next_highlight
19880                        .range
19881                        .end
19882                        .cmp(&highlight.range.end, &snapshot)
19883                        .is_gt()
19884                    {
19885                        row_highlights[ix].range.end = next_highlight.range.end;
19886                    }
19887                    row_highlights.remove(ix + 1);
19888                } else {
19889                    break;
19890                }
19891            }
19892        }
19893    }
19894
19895    /// Remove any highlighted row ranges of the given type that intersect the
19896    /// given ranges.
19897    pub fn remove_highlighted_rows<T: 'static>(
19898        &mut self,
19899        ranges_to_remove: Vec<Range<Anchor>>,
19900        cx: &mut Context<Self>,
19901    ) {
19902        let snapshot = self.buffer().read(cx).snapshot(cx);
19903        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19904        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19905        row_highlights.retain(|highlight| {
19906            while let Some(range_to_remove) = ranges_to_remove.peek() {
19907                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19908                    Ordering::Less | Ordering::Equal => {
19909                        ranges_to_remove.next();
19910                    }
19911                    Ordering::Greater => {
19912                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19913                            Ordering::Less | Ordering::Equal => {
19914                                return false;
19915                            }
19916                            Ordering::Greater => break,
19917                        }
19918                    }
19919                }
19920            }
19921
19922            true
19923        })
19924    }
19925
19926    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19927    pub fn clear_row_highlights<T: 'static>(&mut self) {
19928        self.highlighted_rows.remove(&TypeId::of::<T>());
19929    }
19930
19931    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19932    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19933        self.highlighted_rows
19934            .get(&TypeId::of::<T>())
19935            .map_or(&[] as &[_], |vec| vec.as_slice())
19936            .iter()
19937            .map(|highlight| (highlight.range.clone(), highlight.color))
19938    }
19939
19940    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19941    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19942    /// Allows to ignore certain kinds of highlights.
19943    pub fn highlighted_display_rows(
19944        &self,
19945        window: &mut Window,
19946        cx: &mut App,
19947    ) -> BTreeMap<DisplayRow, LineHighlight> {
19948        let snapshot = self.snapshot(window, cx);
19949        let mut used_highlight_orders = HashMap::default();
19950        self.highlighted_rows
19951            .iter()
19952            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19953            .fold(
19954                BTreeMap::<DisplayRow, LineHighlight>::new(),
19955                |mut unique_rows, highlight| {
19956                    let start = highlight.range.start.to_display_point(&snapshot);
19957                    let end = highlight.range.end.to_display_point(&snapshot);
19958                    let start_row = start.row().0;
19959                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19960                        && end.column() == 0
19961                    {
19962                        end.row().0.saturating_sub(1)
19963                    } else {
19964                        end.row().0
19965                    };
19966                    for row in start_row..=end_row {
19967                        let used_index =
19968                            used_highlight_orders.entry(row).or_insert(highlight.index);
19969                        if highlight.index >= *used_index {
19970                            *used_index = highlight.index;
19971                            unique_rows.insert(
19972                                DisplayRow(row),
19973                                LineHighlight {
19974                                    include_gutter: highlight.options.include_gutter,
19975                                    border: None,
19976                                    background: highlight.color.into(),
19977                                    type_id: Some(highlight.type_id),
19978                                },
19979                            );
19980                        }
19981                    }
19982                    unique_rows
19983                },
19984            )
19985    }
19986
19987    pub fn highlighted_display_row_for_autoscroll(
19988        &self,
19989        snapshot: &DisplaySnapshot,
19990    ) -> Option<DisplayRow> {
19991        self.highlighted_rows
19992            .values()
19993            .flat_map(|highlighted_rows| highlighted_rows.iter())
19994            .filter_map(|highlight| {
19995                if highlight.options.autoscroll {
19996                    Some(highlight.range.start.to_display_point(snapshot).row())
19997                } else {
19998                    None
19999                }
20000            })
20001            .min()
20002    }
20003
20004    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20005        self.highlight_background::<SearchWithinRange>(
20006            ranges,
20007            |colors| colors.colors().editor_document_highlight_read_background,
20008            cx,
20009        )
20010    }
20011
20012    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20013        self.breadcrumb_header = Some(new_header);
20014    }
20015
20016    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20017        self.clear_background_highlights::<SearchWithinRange>(cx);
20018    }
20019
20020    pub fn highlight_background<T: 'static>(
20021        &mut self,
20022        ranges: &[Range<Anchor>],
20023        color_fetcher: fn(&Theme) -> Hsla,
20024        cx: &mut Context<Self>,
20025    ) {
20026        self.background_highlights.insert(
20027            HighlightKey::Type(TypeId::of::<T>()),
20028            (color_fetcher, Arc::from(ranges)),
20029        );
20030        self.scrollbar_marker_state.dirty = true;
20031        cx.notify();
20032    }
20033
20034    pub fn highlight_background_key<T: 'static>(
20035        &mut self,
20036        key: usize,
20037        ranges: &[Range<Anchor>],
20038        color_fetcher: fn(&Theme) -> Hsla,
20039        cx: &mut Context<Self>,
20040    ) {
20041        self.background_highlights.insert(
20042            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20043            (color_fetcher, Arc::from(ranges)),
20044        );
20045        self.scrollbar_marker_state.dirty = true;
20046        cx.notify();
20047    }
20048
20049    pub fn clear_background_highlights<T: 'static>(
20050        &mut self,
20051        cx: &mut Context<Self>,
20052    ) -> Option<BackgroundHighlight> {
20053        let text_highlights = self
20054            .background_highlights
20055            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20056        if !text_highlights.1.is_empty() {
20057            self.scrollbar_marker_state.dirty = true;
20058            cx.notify();
20059        }
20060        Some(text_highlights)
20061    }
20062
20063    pub fn highlight_gutter<T: 'static>(
20064        &mut self,
20065        ranges: impl Into<Vec<Range<Anchor>>>,
20066        color_fetcher: fn(&App) -> Hsla,
20067        cx: &mut Context<Self>,
20068    ) {
20069        self.gutter_highlights
20070            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20071        cx.notify();
20072    }
20073
20074    pub fn clear_gutter_highlights<T: 'static>(
20075        &mut self,
20076        cx: &mut Context<Self>,
20077    ) -> Option<GutterHighlight> {
20078        cx.notify();
20079        self.gutter_highlights.remove(&TypeId::of::<T>())
20080    }
20081
20082    pub fn insert_gutter_highlight<T: 'static>(
20083        &mut self,
20084        range: Range<Anchor>,
20085        color_fetcher: fn(&App) -> Hsla,
20086        cx: &mut Context<Self>,
20087    ) {
20088        let snapshot = self.buffer().read(cx).snapshot(cx);
20089        let mut highlights = self
20090            .gutter_highlights
20091            .remove(&TypeId::of::<T>())
20092            .map(|(_, highlights)| highlights)
20093            .unwrap_or_default();
20094        let ix = highlights.binary_search_by(|highlight| {
20095            Ordering::Equal
20096                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20097                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20098        });
20099        if let Err(ix) = ix {
20100            highlights.insert(ix, range);
20101        }
20102        self.gutter_highlights
20103            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20104    }
20105
20106    pub fn remove_gutter_highlights<T: 'static>(
20107        &mut self,
20108        ranges_to_remove: Vec<Range<Anchor>>,
20109        cx: &mut Context<Self>,
20110    ) {
20111        let snapshot = self.buffer().read(cx).snapshot(cx);
20112        let Some((color_fetcher, mut gutter_highlights)) =
20113            self.gutter_highlights.remove(&TypeId::of::<T>())
20114        else {
20115            return;
20116        };
20117        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20118        gutter_highlights.retain(|highlight| {
20119            while let Some(range_to_remove) = ranges_to_remove.peek() {
20120                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20121                    Ordering::Less | Ordering::Equal => {
20122                        ranges_to_remove.next();
20123                    }
20124                    Ordering::Greater => {
20125                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20126                            Ordering::Less | Ordering::Equal => {
20127                                return false;
20128                            }
20129                            Ordering::Greater => break,
20130                        }
20131                    }
20132                }
20133            }
20134
20135            true
20136        });
20137        self.gutter_highlights
20138            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20139    }
20140
20141    #[cfg(feature = "test-support")]
20142    pub fn all_text_highlights(
20143        &self,
20144        window: &mut Window,
20145        cx: &mut Context<Self>,
20146    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20147        let snapshot = self.snapshot(window, cx);
20148        self.display_map.update(cx, |display_map, _| {
20149            display_map
20150                .all_text_highlights()
20151                .map(|highlight| {
20152                    let (style, ranges) = highlight.as_ref();
20153                    (
20154                        *style,
20155                        ranges
20156                            .iter()
20157                            .map(|range| range.clone().to_display_points(&snapshot))
20158                            .collect(),
20159                    )
20160                })
20161                .collect()
20162        })
20163    }
20164
20165    #[cfg(feature = "test-support")]
20166    pub fn all_text_background_highlights(
20167        &self,
20168        window: &mut Window,
20169        cx: &mut Context<Self>,
20170    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20171        let snapshot = self.snapshot(window, cx);
20172        let buffer = &snapshot.buffer_snapshot;
20173        let start = buffer.anchor_before(0);
20174        let end = buffer.anchor_after(buffer.len());
20175        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20176    }
20177
20178    #[cfg(any(test, feature = "test-support"))]
20179    pub fn sorted_background_highlights_in_range(
20180        &self,
20181        search_range: Range<Anchor>,
20182        display_snapshot: &DisplaySnapshot,
20183        theme: &Theme,
20184    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20185        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20186        res.sort_by(|a, b| {
20187            a.0.start
20188                .cmp(&b.0.start)
20189                .then_with(|| a.0.end.cmp(&b.0.end))
20190                .then_with(|| a.1.cmp(&b.1))
20191        });
20192        res
20193    }
20194
20195    #[cfg(feature = "test-support")]
20196    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20197        let snapshot = self.buffer().read(cx).snapshot(cx);
20198
20199        let highlights = self
20200            .background_highlights
20201            .get(&HighlightKey::Type(TypeId::of::<
20202                items::BufferSearchHighlights,
20203            >()));
20204
20205        if let Some((_color, ranges)) = highlights {
20206            ranges
20207                .iter()
20208                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20209                .collect_vec()
20210        } else {
20211            vec![]
20212        }
20213    }
20214
20215    fn document_highlights_for_position<'a>(
20216        &'a self,
20217        position: Anchor,
20218        buffer: &'a MultiBufferSnapshot,
20219    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20220        let read_highlights = self
20221            .background_highlights
20222            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20223            .map(|h| &h.1);
20224        let write_highlights = self
20225            .background_highlights
20226            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20227            .map(|h| &h.1);
20228        let left_position = position.bias_left(buffer);
20229        let right_position = position.bias_right(buffer);
20230        read_highlights
20231            .into_iter()
20232            .chain(write_highlights)
20233            .flat_map(move |ranges| {
20234                let start_ix = match ranges.binary_search_by(|probe| {
20235                    let cmp = probe.end.cmp(&left_position, buffer);
20236                    if cmp.is_ge() {
20237                        Ordering::Greater
20238                    } else {
20239                        Ordering::Less
20240                    }
20241                }) {
20242                    Ok(i) | Err(i) => i,
20243                };
20244
20245                ranges[start_ix..]
20246                    .iter()
20247                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20248            })
20249    }
20250
20251    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20252        self.background_highlights
20253            .get(&HighlightKey::Type(TypeId::of::<T>()))
20254            .is_some_and(|(_, highlights)| !highlights.is_empty())
20255    }
20256
20257    /// Returns all background highlights for a given range.
20258    ///
20259    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20260    pub fn background_highlights_in_range(
20261        &self,
20262        search_range: Range<Anchor>,
20263        display_snapshot: &DisplaySnapshot,
20264        theme: &Theme,
20265    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20266        let mut results = Vec::new();
20267        for (color_fetcher, ranges) in self.background_highlights.values() {
20268            let color = color_fetcher(theme);
20269            let start_ix = match ranges.binary_search_by(|probe| {
20270                let cmp = probe
20271                    .end
20272                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20273                if cmp.is_gt() {
20274                    Ordering::Greater
20275                } else {
20276                    Ordering::Less
20277                }
20278            }) {
20279                Ok(i) | Err(i) => i,
20280            };
20281            for range in &ranges[start_ix..] {
20282                if range
20283                    .start
20284                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20285                    .is_ge()
20286                {
20287                    break;
20288                }
20289
20290                let start = range.start.to_display_point(display_snapshot);
20291                let end = range.end.to_display_point(display_snapshot);
20292                results.push((start..end, color))
20293            }
20294        }
20295        results
20296    }
20297
20298    pub fn gutter_highlights_in_range(
20299        &self,
20300        search_range: Range<Anchor>,
20301        display_snapshot: &DisplaySnapshot,
20302        cx: &App,
20303    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20304        let mut results = Vec::new();
20305        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20306            let color = color_fetcher(cx);
20307            let start_ix = match ranges.binary_search_by(|probe| {
20308                let cmp = probe
20309                    .end
20310                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20311                if cmp.is_gt() {
20312                    Ordering::Greater
20313                } else {
20314                    Ordering::Less
20315                }
20316            }) {
20317                Ok(i) | Err(i) => i,
20318            };
20319            for range in &ranges[start_ix..] {
20320                if range
20321                    .start
20322                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20323                    .is_ge()
20324                {
20325                    break;
20326                }
20327
20328                let start = range.start.to_display_point(display_snapshot);
20329                let end = range.end.to_display_point(display_snapshot);
20330                results.push((start..end, color))
20331            }
20332        }
20333        results
20334    }
20335
20336    /// Get the text ranges corresponding to the redaction query
20337    pub fn redacted_ranges(
20338        &self,
20339        search_range: Range<Anchor>,
20340        display_snapshot: &DisplaySnapshot,
20341        cx: &App,
20342    ) -> Vec<Range<DisplayPoint>> {
20343        display_snapshot
20344            .buffer_snapshot
20345            .redacted_ranges(search_range, |file| {
20346                if let Some(file) = file {
20347                    file.is_private()
20348                        && EditorSettings::get(
20349                            Some(SettingsLocation {
20350                                worktree_id: file.worktree_id(cx),
20351                                path: file.path().as_ref(),
20352                            }),
20353                            cx,
20354                        )
20355                        .redact_private_values
20356                } else {
20357                    false
20358                }
20359            })
20360            .map(|range| {
20361                range.start.to_display_point(display_snapshot)
20362                    ..range.end.to_display_point(display_snapshot)
20363            })
20364            .collect()
20365    }
20366
20367    pub fn highlight_text_key<T: 'static>(
20368        &mut self,
20369        key: usize,
20370        ranges: Vec<Range<Anchor>>,
20371        style: HighlightStyle,
20372        cx: &mut Context<Self>,
20373    ) {
20374        self.display_map.update(cx, |map, _| {
20375            map.highlight_text(
20376                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20377                ranges,
20378                style,
20379            );
20380        });
20381        cx.notify();
20382    }
20383
20384    pub fn highlight_text<T: 'static>(
20385        &mut self,
20386        ranges: Vec<Range<Anchor>>,
20387        style: HighlightStyle,
20388        cx: &mut Context<Self>,
20389    ) {
20390        self.display_map.update(cx, |map, _| {
20391            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20392        });
20393        cx.notify();
20394    }
20395
20396    pub(crate) fn highlight_inlays<T: 'static>(
20397        &mut self,
20398        highlights: Vec<InlayHighlight>,
20399        style: HighlightStyle,
20400        cx: &mut Context<Self>,
20401    ) {
20402        self.display_map.update(cx, |map, _| {
20403            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20404        });
20405        cx.notify();
20406    }
20407
20408    pub fn text_highlights<'a, T: 'static>(
20409        &'a self,
20410        cx: &'a App,
20411    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20412        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20413    }
20414
20415    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20416        let cleared = self
20417            .display_map
20418            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20419        if cleared {
20420            cx.notify();
20421        }
20422    }
20423
20424    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20425        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20426            && self.focus_handle.is_focused(window)
20427    }
20428
20429    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20430        self.show_cursor_when_unfocused = is_enabled;
20431        cx.notify();
20432    }
20433
20434    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20435        cx.notify();
20436    }
20437
20438    fn on_debug_session_event(
20439        &mut self,
20440        _session: Entity<Session>,
20441        event: &SessionEvent,
20442        cx: &mut Context<Self>,
20443    ) {
20444        if let SessionEvent::InvalidateInlineValue = event {
20445            self.refresh_inline_values(cx);
20446        }
20447    }
20448
20449    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20450        let Some(project) = self.project.clone() else {
20451            return;
20452        };
20453
20454        if !self.inline_value_cache.enabled {
20455            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20456            self.splice_inlays(&inlays, Vec::new(), cx);
20457            return;
20458        }
20459
20460        let current_execution_position = self
20461            .highlighted_rows
20462            .get(&TypeId::of::<ActiveDebugLine>())
20463            .and_then(|lines| lines.last().map(|line| line.range.end));
20464
20465        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20466            let inline_values = editor
20467                .update(cx, |editor, cx| {
20468                    let Some(current_execution_position) = current_execution_position else {
20469                        return Some(Task::ready(Ok(Vec::new())));
20470                    };
20471
20472                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20473                        let snapshot = buffer.snapshot(cx);
20474
20475                        let excerpt = snapshot.excerpt_containing(
20476                            current_execution_position..current_execution_position,
20477                        )?;
20478
20479                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20480                    })?;
20481
20482                    let range =
20483                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20484
20485                    project.inline_values(buffer, range, cx)
20486                })
20487                .ok()
20488                .flatten()?
20489                .await
20490                .context("refreshing debugger inlays")
20491                .log_err()?;
20492
20493            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20494
20495            for (buffer_id, inline_value) in inline_values
20496                .into_iter()
20497                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20498            {
20499                buffer_inline_values
20500                    .entry(buffer_id)
20501                    .or_default()
20502                    .push(inline_value);
20503            }
20504
20505            editor
20506                .update(cx, |editor, cx| {
20507                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20508                    let mut new_inlays = Vec::default();
20509
20510                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20511                        let buffer_id = buffer_snapshot.remote_id();
20512                        buffer_inline_values
20513                            .get(&buffer_id)
20514                            .into_iter()
20515                            .flatten()
20516                            .for_each(|hint| {
20517                                let inlay = Inlay::debugger(
20518                                    post_inc(&mut editor.next_inlay_id),
20519                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20520                                    hint.text(),
20521                                );
20522                                if !inlay.text.chars().contains(&'\n') {
20523                                    new_inlays.push(inlay);
20524                                }
20525                            });
20526                    }
20527
20528                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20529                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20530
20531                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20532                })
20533                .ok()?;
20534            Some(())
20535        });
20536    }
20537
20538    fn on_buffer_event(
20539        &mut self,
20540        multibuffer: &Entity<MultiBuffer>,
20541        event: &multi_buffer::Event,
20542        window: &mut Window,
20543        cx: &mut Context<Self>,
20544    ) {
20545        match event {
20546            multi_buffer::Event::Edited {
20547                singleton_buffer_edited,
20548                edited_buffer,
20549            } => {
20550                self.scrollbar_marker_state.dirty = true;
20551                self.active_indent_guides_state.dirty = true;
20552                self.refresh_active_diagnostics(cx);
20553                self.refresh_code_actions(window, cx);
20554                self.refresh_selected_text_highlights(true, window, cx);
20555                self.refresh_single_line_folds(window, cx);
20556                refresh_matching_bracket_highlights(self, window, cx);
20557                if self.has_active_edit_prediction() {
20558                    self.update_visible_edit_prediction(window, cx);
20559                }
20560                if let Some(project) = self.project.as_ref()
20561                    && let Some(edited_buffer) = edited_buffer
20562                {
20563                    project.update(cx, |project, cx| {
20564                        self.registered_buffers
20565                            .entry(edited_buffer.read(cx).remote_id())
20566                            .or_insert_with(|| {
20567                                project.register_buffer_with_language_servers(edited_buffer, cx)
20568                            });
20569                    });
20570                }
20571                cx.emit(EditorEvent::BufferEdited);
20572                cx.emit(SearchEvent::MatchesInvalidated);
20573
20574                if let Some(buffer) = edited_buffer {
20575                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20576                }
20577
20578                if *singleton_buffer_edited {
20579                    if let Some(buffer) = edited_buffer
20580                        && buffer.read(cx).file().is_none()
20581                    {
20582                        cx.emit(EditorEvent::TitleChanged);
20583                    }
20584                    if let Some(project) = &self.project {
20585                        #[allow(clippy::mutable_key_type)]
20586                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20587                            multibuffer
20588                                .all_buffers()
20589                                .into_iter()
20590                                .filter_map(|buffer| {
20591                                    buffer.update(cx, |buffer, cx| {
20592                                        let language = buffer.language()?;
20593                                        let should_discard = project.update(cx, |project, cx| {
20594                                            project.is_local()
20595                                                && !project.has_language_servers_for(buffer, cx)
20596                                        });
20597                                        should_discard.not().then_some(language.clone())
20598                                    })
20599                                })
20600                                .collect::<HashSet<_>>()
20601                        });
20602                        if !languages_affected.is_empty() {
20603                            self.refresh_inlay_hints(
20604                                InlayHintRefreshReason::BufferEdited(languages_affected),
20605                                cx,
20606                            );
20607                        }
20608                    }
20609                }
20610
20611                let Some(project) = &self.project else { return };
20612                let (telemetry, is_via_ssh) = {
20613                    let project = project.read(cx);
20614                    let telemetry = project.client().telemetry().clone();
20615                    let is_via_ssh = project.is_via_remote_server();
20616                    (telemetry, is_via_ssh)
20617                };
20618                refresh_linked_ranges(self, window, cx);
20619                telemetry.log_edit_event("editor", is_via_ssh);
20620            }
20621            multi_buffer::Event::ExcerptsAdded {
20622                buffer,
20623                predecessor,
20624                excerpts,
20625            } => {
20626                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20627                let buffer_id = buffer.read(cx).remote_id();
20628                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20629                    && let Some(project) = &self.project
20630                {
20631                    update_uncommitted_diff_for_buffer(
20632                        cx.entity(),
20633                        project,
20634                        [buffer.clone()],
20635                        self.buffer.clone(),
20636                        cx,
20637                    )
20638                    .detach();
20639                }
20640                if self.active_diagnostics != ActiveDiagnostic::All {
20641                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20642                }
20643                cx.emit(EditorEvent::ExcerptsAdded {
20644                    buffer: buffer.clone(),
20645                    predecessor: *predecessor,
20646                    excerpts: excerpts.clone(),
20647                });
20648                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20649            }
20650            multi_buffer::Event::ExcerptsRemoved {
20651                ids,
20652                removed_buffer_ids,
20653            } => {
20654                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20655                let buffer = self.buffer.read(cx);
20656                self.registered_buffers
20657                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20658                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20659                cx.emit(EditorEvent::ExcerptsRemoved {
20660                    ids: ids.clone(),
20661                    removed_buffer_ids: removed_buffer_ids.clone(),
20662                });
20663            }
20664            multi_buffer::Event::ExcerptsEdited {
20665                excerpt_ids,
20666                buffer_ids,
20667            } => {
20668                self.display_map.update(cx, |map, cx| {
20669                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20670                });
20671                cx.emit(EditorEvent::ExcerptsEdited {
20672                    ids: excerpt_ids.clone(),
20673                });
20674            }
20675            multi_buffer::Event::ExcerptsExpanded { ids } => {
20676                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20677                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20678            }
20679            multi_buffer::Event::Reparsed(buffer_id) => {
20680                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20681                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20682
20683                cx.emit(EditorEvent::Reparsed(*buffer_id));
20684            }
20685            multi_buffer::Event::DiffHunksToggled => {
20686                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20687            }
20688            multi_buffer::Event::LanguageChanged(buffer_id) => {
20689                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20690                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20691                cx.emit(EditorEvent::Reparsed(*buffer_id));
20692                cx.notify();
20693            }
20694            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20695            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20696            multi_buffer::Event::FileHandleChanged
20697            | multi_buffer::Event::Reloaded
20698            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20699            multi_buffer::Event::DiagnosticsUpdated => {
20700                self.update_diagnostics_state(window, cx);
20701            }
20702            _ => {}
20703        };
20704    }
20705
20706    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20707        if !self.diagnostics_enabled() {
20708            return;
20709        }
20710        self.refresh_active_diagnostics(cx);
20711        self.refresh_inline_diagnostics(true, window, cx);
20712        self.scrollbar_marker_state.dirty = true;
20713        cx.notify();
20714    }
20715
20716    pub fn start_temporary_diff_override(&mut self) {
20717        self.load_diff_task.take();
20718        self.temporary_diff_override = true;
20719    }
20720
20721    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20722        self.temporary_diff_override = false;
20723        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20724        self.buffer.update(cx, |buffer, cx| {
20725            buffer.set_all_diff_hunks_collapsed(cx);
20726        });
20727
20728        if let Some(project) = self.project.clone() {
20729            self.load_diff_task = Some(
20730                update_uncommitted_diff_for_buffer(
20731                    cx.entity(),
20732                    &project,
20733                    self.buffer.read(cx).all_buffers(),
20734                    self.buffer.clone(),
20735                    cx,
20736                )
20737                .shared(),
20738            );
20739        }
20740    }
20741
20742    fn on_display_map_changed(
20743        &mut self,
20744        _: Entity<DisplayMap>,
20745        _: &mut Window,
20746        cx: &mut Context<Self>,
20747    ) {
20748        cx.notify();
20749    }
20750
20751    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20752        if self.diagnostics_enabled() {
20753            let new_severity = EditorSettings::get_global(cx)
20754                .diagnostics_max_severity
20755                .unwrap_or(DiagnosticSeverity::Hint);
20756            self.set_max_diagnostics_severity(new_severity, cx);
20757        }
20758        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20759        self.update_edit_prediction_settings(cx);
20760        self.refresh_edit_prediction(true, false, window, cx);
20761        self.refresh_inline_values(cx);
20762        self.refresh_inlay_hints(
20763            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20764                self.selections.newest_anchor().head(),
20765                &self.buffer.read(cx).snapshot(cx),
20766                cx,
20767            )),
20768            cx,
20769        );
20770
20771        let old_cursor_shape = self.cursor_shape;
20772        let old_show_breadcrumbs = self.show_breadcrumbs;
20773
20774        {
20775            let editor_settings = EditorSettings::get_global(cx);
20776            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20777            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20778            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20779            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20780        }
20781
20782        if old_cursor_shape != self.cursor_shape {
20783            cx.emit(EditorEvent::CursorShapeChanged);
20784        }
20785
20786        if old_show_breadcrumbs != self.show_breadcrumbs {
20787            cx.emit(EditorEvent::BreadcrumbsChanged);
20788        }
20789
20790        let project_settings = ProjectSettings::get_global(cx);
20791        self.serialize_dirty_buffers =
20792            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20793
20794        if self.mode.is_full() {
20795            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20796            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20797            if self.show_inline_diagnostics != show_inline_diagnostics {
20798                self.show_inline_diagnostics = show_inline_diagnostics;
20799                self.refresh_inline_diagnostics(false, window, cx);
20800            }
20801
20802            if self.git_blame_inline_enabled != inline_blame_enabled {
20803                self.toggle_git_blame_inline_internal(false, window, cx);
20804            }
20805
20806            let minimap_settings = EditorSettings::get_global(cx).minimap;
20807            if self.minimap_visibility != MinimapVisibility::Disabled {
20808                if self.minimap_visibility.settings_visibility()
20809                    != minimap_settings.minimap_enabled()
20810                {
20811                    self.set_minimap_visibility(
20812                        MinimapVisibility::for_mode(self.mode(), cx),
20813                        window,
20814                        cx,
20815                    );
20816                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20817                    minimap_entity.update(cx, |minimap_editor, cx| {
20818                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20819                    })
20820                }
20821            }
20822        }
20823
20824        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20825            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20826        }) {
20827            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20828                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20829            }
20830            self.refresh_colors(false, None, window, cx);
20831        }
20832
20833        cx.notify();
20834    }
20835
20836    pub fn set_searchable(&mut self, searchable: bool) {
20837        self.searchable = searchable;
20838    }
20839
20840    pub fn searchable(&self) -> bool {
20841        self.searchable
20842    }
20843
20844    fn open_proposed_changes_editor(
20845        &mut self,
20846        _: &OpenProposedChangesEditor,
20847        window: &mut Window,
20848        cx: &mut Context<Self>,
20849    ) {
20850        let Some(workspace) = self.workspace() else {
20851            cx.propagate();
20852            return;
20853        };
20854
20855        let selections = self.selections.all::<usize>(cx);
20856        let multi_buffer = self.buffer.read(cx);
20857        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20858        let mut new_selections_by_buffer = HashMap::default();
20859        for selection in selections {
20860            for (buffer, range, _) in
20861                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20862            {
20863                let mut range = range.to_point(buffer);
20864                range.start.column = 0;
20865                range.end.column = buffer.line_len(range.end.row);
20866                new_selections_by_buffer
20867                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20868                    .or_insert(Vec::new())
20869                    .push(range)
20870            }
20871        }
20872
20873        let proposed_changes_buffers = new_selections_by_buffer
20874            .into_iter()
20875            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20876            .collect::<Vec<_>>();
20877        let proposed_changes_editor = cx.new(|cx| {
20878            ProposedChangesEditor::new(
20879                "Proposed changes",
20880                proposed_changes_buffers,
20881                self.project.clone(),
20882                window,
20883                cx,
20884            )
20885        });
20886
20887        window.defer(cx, move |window, cx| {
20888            workspace.update(cx, |workspace, cx| {
20889                workspace.active_pane().update(cx, |pane, cx| {
20890                    pane.add_item(
20891                        Box::new(proposed_changes_editor),
20892                        true,
20893                        true,
20894                        None,
20895                        window,
20896                        cx,
20897                    );
20898                });
20899            });
20900        });
20901    }
20902
20903    pub fn open_excerpts_in_split(
20904        &mut self,
20905        _: &OpenExcerptsSplit,
20906        window: &mut Window,
20907        cx: &mut Context<Self>,
20908    ) {
20909        self.open_excerpts_common(None, true, window, cx)
20910    }
20911
20912    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20913        self.open_excerpts_common(None, false, window, cx)
20914    }
20915
20916    fn open_excerpts_common(
20917        &mut self,
20918        jump_data: Option<JumpData>,
20919        split: bool,
20920        window: &mut Window,
20921        cx: &mut Context<Self>,
20922    ) {
20923        let Some(workspace) = self.workspace() else {
20924            cx.propagate();
20925            return;
20926        };
20927
20928        if self.buffer.read(cx).is_singleton() {
20929            cx.propagate();
20930            return;
20931        }
20932
20933        let mut new_selections_by_buffer = HashMap::default();
20934        match &jump_data {
20935            Some(JumpData::MultiBufferPoint {
20936                excerpt_id,
20937                position,
20938                anchor,
20939                line_offset_from_top,
20940            }) => {
20941                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20942                if let Some(buffer) = multi_buffer_snapshot
20943                    .buffer_id_for_excerpt(*excerpt_id)
20944                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20945                {
20946                    let buffer_snapshot = buffer.read(cx).snapshot();
20947                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20948                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20949                    } else {
20950                        buffer_snapshot.clip_point(*position, Bias::Left)
20951                    };
20952                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20953                    new_selections_by_buffer.insert(
20954                        buffer,
20955                        (
20956                            vec![jump_to_offset..jump_to_offset],
20957                            Some(*line_offset_from_top),
20958                        ),
20959                    );
20960                }
20961            }
20962            Some(JumpData::MultiBufferRow {
20963                row,
20964                line_offset_from_top,
20965            }) => {
20966                let point = MultiBufferPoint::new(row.0, 0);
20967                if let Some((buffer, buffer_point, _)) =
20968                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20969                {
20970                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20971                    new_selections_by_buffer
20972                        .entry(buffer)
20973                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20974                        .0
20975                        .push(buffer_offset..buffer_offset)
20976                }
20977            }
20978            None => {
20979                let selections = self.selections.all::<usize>(cx);
20980                let multi_buffer = self.buffer.read(cx);
20981                for selection in selections {
20982                    for (snapshot, range, _, anchor) in multi_buffer
20983                        .snapshot(cx)
20984                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20985                    {
20986                        if let Some(anchor) = anchor {
20987                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20988                            else {
20989                                continue;
20990                            };
20991                            let offset = text::ToOffset::to_offset(
20992                                &anchor.text_anchor,
20993                                &buffer_handle.read(cx).snapshot(),
20994                            );
20995                            let range = offset..offset;
20996                            new_selections_by_buffer
20997                                .entry(buffer_handle)
20998                                .or_insert((Vec::new(), None))
20999                                .0
21000                                .push(range)
21001                        } else {
21002                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21003                            else {
21004                                continue;
21005                            };
21006                            new_selections_by_buffer
21007                                .entry(buffer_handle)
21008                                .or_insert((Vec::new(), None))
21009                                .0
21010                                .push(range)
21011                        }
21012                    }
21013                }
21014            }
21015        }
21016
21017        new_selections_by_buffer
21018            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21019
21020        if new_selections_by_buffer.is_empty() {
21021            return;
21022        }
21023
21024        // We defer the pane interaction because we ourselves are a workspace item
21025        // and activating a new item causes the pane to call a method on us reentrantly,
21026        // which panics if we're on the stack.
21027        window.defer(cx, move |window, cx| {
21028            workspace.update(cx, |workspace, cx| {
21029                let pane = if split {
21030                    workspace.adjacent_pane(window, cx)
21031                } else {
21032                    workspace.active_pane().clone()
21033                };
21034
21035                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21036                    let editor = buffer
21037                        .read(cx)
21038                        .file()
21039                        .is_none()
21040                        .then(|| {
21041                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21042                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21043                            // Instead, we try to activate the existing editor in the pane first.
21044                            let (editor, pane_item_index) =
21045                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21046                                    let editor = item.downcast::<Editor>()?;
21047                                    let singleton_buffer =
21048                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21049                                    if singleton_buffer == buffer {
21050                                        Some((editor, i))
21051                                    } else {
21052                                        None
21053                                    }
21054                                })?;
21055                            pane.update(cx, |pane, cx| {
21056                                pane.activate_item(pane_item_index, true, true, window, cx)
21057                            });
21058                            Some(editor)
21059                        })
21060                        .flatten()
21061                        .unwrap_or_else(|| {
21062                            workspace.open_project_item::<Self>(
21063                                pane.clone(),
21064                                buffer,
21065                                true,
21066                                true,
21067                                window,
21068                                cx,
21069                            )
21070                        });
21071
21072                    editor.update(cx, |editor, cx| {
21073                        let autoscroll = match scroll_offset {
21074                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21075                            None => Autoscroll::newest(),
21076                        };
21077                        let nav_history = editor.nav_history.take();
21078                        editor.change_selections(
21079                            SelectionEffects::scroll(autoscroll),
21080                            window,
21081                            cx,
21082                            |s| {
21083                                s.select_ranges(ranges);
21084                            },
21085                        );
21086                        editor.nav_history = nav_history;
21087                    });
21088                }
21089            })
21090        });
21091    }
21092
21093    // For now, don't allow opening excerpts in buffers that aren't backed by
21094    // regular project files.
21095    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21096        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21097    }
21098
21099    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21100        let snapshot = self.buffer.read(cx).read(cx);
21101        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21102        Some(
21103            ranges
21104                .iter()
21105                .map(move |range| {
21106                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21107                })
21108                .collect(),
21109        )
21110    }
21111
21112    fn selection_replacement_ranges(
21113        &self,
21114        range: Range<OffsetUtf16>,
21115        cx: &mut App,
21116    ) -> Vec<Range<OffsetUtf16>> {
21117        let selections = self.selections.all::<OffsetUtf16>(cx);
21118        let newest_selection = selections
21119            .iter()
21120            .max_by_key(|selection| selection.id)
21121            .unwrap();
21122        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21123        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21124        let snapshot = self.buffer.read(cx).read(cx);
21125        selections
21126            .into_iter()
21127            .map(|mut selection| {
21128                selection.start.0 =
21129                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21130                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21131                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21132                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21133            })
21134            .collect()
21135    }
21136
21137    fn report_editor_event(
21138        &self,
21139        reported_event: ReportEditorEvent,
21140        file_extension: Option<String>,
21141        cx: &App,
21142    ) {
21143        if cfg!(any(test, feature = "test-support")) {
21144            return;
21145        }
21146
21147        let Some(project) = &self.project else { return };
21148
21149        // If None, we are in a file without an extension
21150        let file = self
21151            .buffer
21152            .read(cx)
21153            .as_singleton()
21154            .and_then(|b| b.read(cx).file());
21155        let file_extension = file_extension.or(file
21156            .as_ref()
21157            .and_then(|file| Path::new(file.file_name(cx)).extension())
21158            .and_then(|e| e.to_str())
21159            .map(|a| a.to_string()));
21160
21161        let vim_mode = vim_enabled(cx);
21162
21163        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21164        let copilot_enabled = edit_predictions_provider
21165            == language::language_settings::EditPredictionProvider::Copilot;
21166        let copilot_enabled_for_language = self
21167            .buffer
21168            .read(cx)
21169            .language_settings(cx)
21170            .show_edit_predictions;
21171
21172        let project = project.read(cx);
21173        let event_type = reported_event.event_type();
21174
21175        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21176            telemetry::event!(
21177                event_type,
21178                type = if auto_saved {"autosave"} else {"manual"},
21179                file_extension,
21180                vim_mode,
21181                copilot_enabled,
21182                copilot_enabled_for_language,
21183                edit_predictions_provider,
21184                is_via_ssh = project.is_via_remote_server(),
21185            );
21186        } else {
21187            telemetry::event!(
21188                event_type,
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        };
21197    }
21198
21199    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21200    /// with each line being an array of {text, highlight} objects.
21201    fn copy_highlight_json(
21202        &mut self,
21203        _: &CopyHighlightJson,
21204        window: &mut Window,
21205        cx: &mut Context<Self>,
21206    ) {
21207        #[derive(Serialize)]
21208        struct Chunk<'a> {
21209            text: String,
21210            highlight: Option<&'a str>,
21211        }
21212
21213        let snapshot = self.buffer.read(cx).snapshot(cx);
21214        let range = self
21215            .selected_text_range(false, window, cx)
21216            .and_then(|selection| {
21217                if selection.range.is_empty() {
21218                    None
21219                } else {
21220                    Some(selection.range)
21221                }
21222            })
21223            .unwrap_or_else(|| 0..snapshot.len());
21224
21225        let chunks = snapshot.chunks(range, true);
21226        let mut lines = Vec::new();
21227        let mut line: VecDeque<Chunk> = VecDeque::new();
21228
21229        let Some(style) = self.style.as_ref() else {
21230            return;
21231        };
21232
21233        for chunk in chunks {
21234            let highlight = chunk
21235                .syntax_highlight_id
21236                .and_then(|id| id.name(&style.syntax));
21237            let mut chunk_lines = chunk.text.split('\n').peekable();
21238            while let Some(text) = chunk_lines.next() {
21239                let mut merged_with_last_token = false;
21240                if let Some(last_token) = line.back_mut()
21241                    && last_token.highlight == highlight
21242                {
21243                    last_token.text.push_str(text);
21244                    merged_with_last_token = true;
21245                }
21246
21247                if !merged_with_last_token {
21248                    line.push_back(Chunk {
21249                        text: text.into(),
21250                        highlight,
21251                    });
21252                }
21253
21254                if chunk_lines.peek().is_some() {
21255                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21256                        line.pop_front();
21257                    }
21258                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21259                        line.pop_back();
21260                    }
21261
21262                    lines.push(mem::take(&mut line));
21263                }
21264            }
21265        }
21266
21267        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21268            return;
21269        };
21270        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21271    }
21272
21273    pub fn open_context_menu(
21274        &mut self,
21275        _: &OpenContextMenu,
21276        window: &mut Window,
21277        cx: &mut Context<Self>,
21278    ) {
21279        self.request_autoscroll(Autoscroll::newest(), cx);
21280        let position = self.selections.newest_display(cx).start;
21281        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21282    }
21283
21284    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21285        &self.inlay_hint_cache
21286    }
21287
21288    pub fn replay_insert_event(
21289        &mut self,
21290        text: &str,
21291        relative_utf16_range: Option<Range<isize>>,
21292        window: &mut Window,
21293        cx: &mut Context<Self>,
21294    ) {
21295        if !self.input_enabled {
21296            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21297            return;
21298        }
21299        if let Some(relative_utf16_range) = relative_utf16_range {
21300            let selections = self.selections.all::<OffsetUtf16>(cx);
21301            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21302                let new_ranges = selections.into_iter().map(|range| {
21303                    let start = OffsetUtf16(
21304                        range
21305                            .head()
21306                            .0
21307                            .saturating_add_signed(relative_utf16_range.start),
21308                    );
21309                    let end = OffsetUtf16(
21310                        range
21311                            .head()
21312                            .0
21313                            .saturating_add_signed(relative_utf16_range.end),
21314                    );
21315                    start..end
21316                });
21317                s.select_ranges(new_ranges);
21318            });
21319        }
21320
21321        self.handle_input(text, window, cx);
21322    }
21323
21324    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21325        let Some(provider) = self.semantics_provider.as_ref() else {
21326            return false;
21327        };
21328
21329        let mut supports = false;
21330        self.buffer().update(cx, |this, cx| {
21331            this.for_each_buffer(|buffer| {
21332                supports |= provider.supports_inlay_hints(buffer, cx);
21333            });
21334        });
21335
21336        supports
21337    }
21338
21339    pub fn is_focused(&self, window: &Window) -> bool {
21340        self.focus_handle.is_focused(window)
21341    }
21342
21343    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21344        cx.emit(EditorEvent::Focused);
21345
21346        if let Some(descendant) = self
21347            .last_focused_descendant
21348            .take()
21349            .and_then(|descendant| descendant.upgrade())
21350        {
21351            window.focus(&descendant);
21352        } else {
21353            if let Some(blame) = self.blame.as_ref() {
21354                blame.update(cx, GitBlame::focus)
21355            }
21356
21357            self.blink_manager.update(cx, BlinkManager::enable);
21358            self.show_cursor_names(window, cx);
21359            self.buffer.update(cx, |buffer, cx| {
21360                buffer.finalize_last_transaction(cx);
21361                if self.leader_id.is_none() {
21362                    buffer.set_active_selections(
21363                        &self.selections.disjoint_anchors_arc(),
21364                        self.selections.line_mode,
21365                        self.cursor_shape,
21366                        cx,
21367                    );
21368                }
21369            });
21370        }
21371    }
21372
21373    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21374        cx.emit(EditorEvent::FocusedIn)
21375    }
21376
21377    fn handle_focus_out(
21378        &mut self,
21379        event: FocusOutEvent,
21380        _window: &mut Window,
21381        cx: &mut Context<Self>,
21382    ) {
21383        if event.blurred != self.focus_handle {
21384            self.last_focused_descendant = Some(event.blurred);
21385        }
21386        self.selection_drag_state = SelectionDragState::None;
21387        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21388    }
21389
21390    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21391        self.blink_manager.update(cx, BlinkManager::disable);
21392        self.buffer
21393            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21394
21395        if let Some(blame) = self.blame.as_ref() {
21396            blame.update(cx, GitBlame::blur)
21397        }
21398        if !self.hover_state.focused(window, cx) {
21399            hide_hover(self, cx);
21400        }
21401        if !self
21402            .context_menu
21403            .borrow()
21404            .as_ref()
21405            .is_some_and(|context_menu| context_menu.focused(window, cx))
21406        {
21407            self.hide_context_menu(window, cx);
21408        }
21409        self.discard_edit_prediction(false, cx);
21410        cx.emit(EditorEvent::Blurred);
21411        cx.notify();
21412    }
21413
21414    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21415        let mut pending: String = window
21416            .pending_input_keystrokes()
21417            .into_iter()
21418            .flatten()
21419            .filter_map(|keystroke| {
21420                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21421                    keystroke.key_char.clone()
21422                } else {
21423                    None
21424                }
21425            })
21426            .collect();
21427
21428        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21429            pending = "".to_string();
21430        }
21431
21432        let existing_pending = self
21433            .text_highlights::<PendingInput>(cx)
21434            .map(|(_, ranges)| ranges.to_vec());
21435        if existing_pending.is_none() && pending.is_empty() {
21436            return;
21437        }
21438        let transaction =
21439            self.transact(window, cx, |this, window, cx| {
21440                let selections = this.selections.all::<usize>(cx);
21441                let edits = selections
21442                    .iter()
21443                    .map(|selection| (selection.end..selection.end, pending.clone()));
21444                this.edit(edits, cx);
21445                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21446                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21447                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21448                    }));
21449                });
21450                if let Some(existing_ranges) = existing_pending {
21451                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21452                    this.edit(edits, cx);
21453                }
21454            });
21455
21456        let snapshot = self.snapshot(window, cx);
21457        let ranges = self
21458            .selections
21459            .all::<usize>(cx)
21460            .into_iter()
21461            .map(|selection| {
21462                snapshot.buffer_snapshot.anchor_after(selection.end)
21463                    ..snapshot
21464                        .buffer_snapshot
21465                        .anchor_before(selection.end + pending.len())
21466            })
21467            .collect();
21468
21469        if pending.is_empty() {
21470            self.clear_highlights::<PendingInput>(cx);
21471        } else {
21472            self.highlight_text::<PendingInput>(
21473                ranges,
21474                HighlightStyle {
21475                    underline: Some(UnderlineStyle {
21476                        thickness: px(1.),
21477                        color: None,
21478                        wavy: false,
21479                    }),
21480                    ..Default::default()
21481                },
21482                cx,
21483            );
21484        }
21485
21486        self.ime_transaction = self.ime_transaction.or(transaction);
21487        if let Some(transaction) = self.ime_transaction {
21488            self.buffer.update(cx, |buffer, cx| {
21489                buffer.group_until_transaction(transaction, cx);
21490            });
21491        }
21492
21493        if self.text_highlights::<PendingInput>(cx).is_none() {
21494            self.ime_transaction.take();
21495        }
21496    }
21497
21498    pub fn register_action_renderer(
21499        &mut self,
21500        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21501    ) -> Subscription {
21502        let id = self.next_editor_action_id.post_inc();
21503        self.editor_actions
21504            .borrow_mut()
21505            .insert(id, Box::new(listener));
21506
21507        let editor_actions = self.editor_actions.clone();
21508        Subscription::new(move || {
21509            editor_actions.borrow_mut().remove(&id);
21510        })
21511    }
21512
21513    pub fn register_action<A: Action>(
21514        &mut self,
21515        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21516    ) -> Subscription {
21517        let id = self.next_editor_action_id.post_inc();
21518        let listener = Arc::new(listener);
21519        self.editor_actions.borrow_mut().insert(
21520            id,
21521            Box::new(move |_, window, _| {
21522                let listener = listener.clone();
21523                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21524                    let action = action.downcast_ref().unwrap();
21525                    if phase == DispatchPhase::Bubble {
21526                        listener(action, window, cx)
21527                    }
21528                })
21529            }),
21530        );
21531
21532        let editor_actions = self.editor_actions.clone();
21533        Subscription::new(move || {
21534            editor_actions.borrow_mut().remove(&id);
21535        })
21536    }
21537
21538    pub fn file_header_size(&self) -> u32 {
21539        FILE_HEADER_HEIGHT
21540    }
21541
21542    pub fn restore(
21543        &mut self,
21544        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21545        window: &mut Window,
21546        cx: &mut Context<Self>,
21547    ) {
21548        let workspace = self.workspace();
21549        let project = self.project();
21550        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21551            let mut tasks = Vec::new();
21552            for (buffer_id, changes) in revert_changes {
21553                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21554                    buffer.update(cx, |buffer, cx| {
21555                        buffer.edit(
21556                            changes
21557                                .into_iter()
21558                                .map(|(range, text)| (range, text.to_string())),
21559                            None,
21560                            cx,
21561                        );
21562                    });
21563
21564                    if let Some(project) =
21565                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21566                    {
21567                        project.update(cx, |project, cx| {
21568                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21569                        })
21570                    }
21571                }
21572            }
21573            tasks
21574        });
21575        cx.spawn_in(window, async move |_, cx| {
21576            for (buffer, task) in save_tasks {
21577                let result = task.await;
21578                if result.is_err() {
21579                    let Some(path) = buffer
21580                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21581                        .ok()
21582                    else {
21583                        continue;
21584                    };
21585                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21586                        let Some(task) = cx
21587                            .update_window_entity(workspace, |workspace, window, cx| {
21588                                workspace
21589                                    .open_path_preview(path, None, false, false, false, window, cx)
21590                            })
21591                            .ok()
21592                        else {
21593                            continue;
21594                        };
21595                        task.await.log_err();
21596                    }
21597                }
21598            }
21599        })
21600        .detach();
21601        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21602            selections.refresh()
21603        });
21604    }
21605
21606    pub fn to_pixel_point(
21607        &self,
21608        source: multi_buffer::Anchor,
21609        editor_snapshot: &EditorSnapshot,
21610        window: &mut Window,
21611    ) -> Option<gpui::Point<Pixels>> {
21612        let source_point = source.to_display_point(editor_snapshot);
21613        self.display_to_pixel_point(source_point, editor_snapshot, window)
21614    }
21615
21616    pub fn display_to_pixel_point(
21617        &self,
21618        source: DisplayPoint,
21619        editor_snapshot: &EditorSnapshot,
21620        window: &mut Window,
21621    ) -> Option<gpui::Point<Pixels>> {
21622        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21623        let text_layout_details = self.text_layout_details(window);
21624        let scroll_top = text_layout_details
21625            .scroll_anchor
21626            .scroll_position(editor_snapshot)
21627            .y;
21628
21629        if source.row().as_f32() < scroll_top.floor() {
21630            return None;
21631        }
21632        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21633        let source_y = line_height * (source.row().as_f32() - scroll_top);
21634        Some(gpui::Point::new(source_x, source_y))
21635    }
21636
21637    pub fn has_visible_completions_menu(&self) -> bool {
21638        !self.edit_prediction_preview_is_active()
21639            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21640                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21641            })
21642    }
21643
21644    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21645        if self.mode.is_minimap() {
21646            return;
21647        }
21648        self.addons
21649            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21650    }
21651
21652    pub fn unregister_addon<T: Addon>(&mut self) {
21653        self.addons.remove(&std::any::TypeId::of::<T>());
21654    }
21655
21656    pub fn addon<T: Addon>(&self) -> Option<&T> {
21657        let type_id = std::any::TypeId::of::<T>();
21658        self.addons
21659            .get(&type_id)
21660            .and_then(|item| item.to_any().downcast_ref::<T>())
21661    }
21662
21663    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21664        let type_id = std::any::TypeId::of::<T>();
21665        self.addons
21666            .get_mut(&type_id)
21667            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21668    }
21669
21670    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21671        let text_layout_details = self.text_layout_details(window);
21672        let style = &text_layout_details.editor_style;
21673        let font_id = window.text_system().resolve_font(&style.text.font());
21674        let font_size = style.text.font_size.to_pixels(window.rem_size());
21675        let line_height = style.text.line_height_in_pixels(window.rem_size());
21676        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21677        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21678
21679        CharacterDimensions {
21680            em_width,
21681            em_advance,
21682            line_height,
21683        }
21684    }
21685
21686    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21687        self.load_diff_task.clone()
21688    }
21689
21690    fn read_metadata_from_db(
21691        &mut self,
21692        item_id: u64,
21693        workspace_id: WorkspaceId,
21694        window: &mut Window,
21695        cx: &mut Context<Editor>,
21696    ) {
21697        if self.is_singleton(cx)
21698            && !self.mode.is_minimap()
21699            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21700        {
21701            let buffer_snapshot = OnceCell::new();
21702
21703            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21704                && !folds.is_empty()
21705            {
21706                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21707                self.fold_ranges(
21708                    folds
21709                        .into_iter()
21710                        .map(|(start, end)| {
21711                            snapshot.clip_offset(start, Bias::Left)
21712                                ..snapshot.clip_offset(end, Bias::Right)
21713                        })
21714                        .collect(),
21715                    false,
21716                    window,
21717                    cx,
21718                );
21719            }
21720
21721            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21722                && !selections.is_empty()
21723            {
21724                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21725                // skip adding the initial selection to selection history
21726                self.selection_history.mode = SelectionHistoryMode::Skipping;
21727                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21728                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21729                        snapshot.clip_offset(start, Bias::Left)
21730                            ..snapshot.clip_offset(end, Bias::Right)
21731                    }));
21732                });
21733                self.selection_history.mode = SelectionHistoryMode::Normal;
21734            };
21735        }
21736
21737        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21738    }
21739
21740    fn update_lsp_data(
21741        &mut self,
21742        ignore_cache: bool,
21743        for_buffer: Option<BufferId>,
21744        window: &mut Window,
21745        cx: &mut Context<'_, Self>,
21746    ) {
21747        self.pull_diagnostics(for_buffer, window, cx);
21748        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21749    }
21750}
21751
21752fn edit_for_markdown_paste<'a>(
21753    buffer: &MultiBufferSnapshot,
21754    range: Range<usize>,
21755    to_insert: &'a str,
21756    url: Option<url::Url>,
21757) -> (Range<usize>, Cow<'a, str>) {
21758    if url.is_none() {
21759        return (range, Cow::Borrowed(to_insert));
21760    };
21761
21762    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21763
21764    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21765        Cow::Borrowed(to_insert)
21766    } else {
21767        Cow::Owned(format!("[{old_text}]({to_insert})"))
21768    };
21769    (range, new_text)
21770}
21771
21772fn vim_enabled(cx: &App) -> bool {
21773    vim_mode_setting::VimModeSetting::try_get(cx)
21774        .map(|vim_mode| vim_mode.0)
21775        .unwrap_or(false)
21776}
21777
21778fn process_completion_for_edit(
21779    completion: &Completion,
21780    intent: CompletionIntent,
21781    buffer: &Entity<Buffer>,
21782    cursor_position: &text::Anchor,
21783    cx: &mut Context<Editor>,
21784) -> CompletionEdit {
21785    let buffer = buffer.read(cx);
21786    let buffer_snapshot = buffer.snapshot();
21787    let (snippet, new_text) = if completion.is_snippet() {
21788        // Workaround for typescript language server issues so that methods don't expand within
21789        // strings and functions with type expressions. The previous point is used because the query
21790        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21791        let mut snippet_source = completion.new_text.clone();
21792        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21793        previous_point.column = previous_point.column.saturating_sub(1);
21794        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21795            && scope.prefers_label_for_snippet_in_completion()
21796            && let Some(label) = completion.label()
21797            && matches!(
21798                completion.kind(),
21799                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21800            )
21801        {
21802            snippet_source = label;
21803        }
21804        match Snippet::parse(&snippet_source).log_err() {
21805            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21806            None => (None, completion.new_text.clone()),
21807        }
21808    } else {
21809        (None, completion.new_text.clone())
21810    };
21811
21812    let mut range_to_replace = {
21813        let replace_range = &completion.replace_range;
21814        if let CompletionSource::Lsp {
21815            insert_range: Some(insert_range),
21816            ..
21817        } = &completion.source
21818        {
21819            debug_assert_eq!(
21820                insert_range.start, replace_range.start,
21821                "insert_range and replace_range should start at the same position"
21822            );
21823            debug_assert!(
21824                insert_range
21825                    .start
21826                    .cmp(cursor_position, &buffer_snapshot)
21827                    .is_le(),
21828                "insert_range should start before or at cursor position"
21829            );
21830            debug_assert!(
21831                replace_range
21832                    .start
21833                    .cmp(cursor_position, &buffer_snapshot)
21834                    .is_le(),
21835                "replace_range should start before or at cursor position"
21836            );
21837
21838            let should_replace = match intent {
21839                CompletionIntent::CompleteWithInsert => false,
21840                CompletionIntent::CompleteWithReplace => true,
21841                CompletionIntent::Complete | CompletionIntent::Compose => {
21842                    let insert_mode =
21843                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21844                            .completions
21845                            .lsp_insert_mode;
21846                    match insert_mode {
21847                        LspInsertMode::Insert => false,
21848                        LspInsertMode::Replace => true,
21849                        LspInsertMode::ReplaceSubsequence => {
21850                            let mut text_to_replace = buffer.chars_for_range(
21851                                buffer.anchor_before(replace_range.start)
21852                                    ..buffer.anchor_after(replace_range.end),
21853                            );
21854                            let mut current_needle = text_to_replace.next();
21855                            for haystack_ch in completion.label.text.chars() {
21856                                if let Some(needle_ch) = current_needle
21857                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21858                                {
21859                                    current_needle = text_to_replace.next();
21860                                }
21861                            }
21862                            current_needle.is_none()
21863                        }
21864                        LspInsertMode::ReplaceSuffix => {
21865                            if replace_range
21866                                .end
21867                                .cmp(cursor_position, &buffer_snapshot)
21868                                .is_gt()
21869                            {
21870                                let range_after_cursor = *cursor_position..replace_range.end;
21871                                let text_after_cursor = buffer
21872                                    .text_for_range(
21873                                        buffer.anchor_before(range_after_cursor.start)
21874                                            ..buffer.anchor_after(range_after_cursor.end),
21875                                    )
21876                                    .collect::<String>()
21877                                    .to_ascii_lowercase();
21878                                completion
21879                                    .label
21880                                    .text
21881                                    .to_ascii_lowercase()
21882                                    .ends_with(&text_after_cursor)
21883                            } else {
21884                                true
21885                            }
21886                        }
21887                    }
21888                }
21889            };
21890
21891            if should_replace {
21892                replace_range.clone()
21893            } else {
21894                insert_range.clone()
21895            }
21896        } else {
21897            replace_range.clone()
21898        }
21899    };
21900
21901    if range_to_replace
21902        .end
21903        .cmp(cursor_position, &buffer_snapshot)
21904        .is_lt()
21905    {
21906        range_to_replace.end = *cursor_position;
21907    }
21908
21909    CompletionEdit {
21910        new_text,
21911        replace_range: range_to_replace.to_offset(buffer),
21912        snippet,
21913    }
21914}
21915
21916struct CompletionEdit {
21917    new_text: String,
21918    replace_range: Range<usize>,
21919    snippet: Option<Snippet>,
21920}
21921
21922fn insert_extra_newline_brackets(
21923    buffer: &MultiBufferSnapshot,
21924    range: Range<usize>,
21925    language: &language::LanguageScope,
21926) -> bool {
21927    let leading_whitespace_len = buffer
21928        .reversed_chars_at(range.start)
21929        .take_while(|c| c.is_whitespace() && *c != '\n')
21930        .map(|c| c.len_utf8())
21931        .sum::<usize>();
21932    let trailing_whitespace_len = buffer
21933        .chars_at(range.end)
21934        .take_while(|c| c.is_whitespace() && *c != '\n')
21935        .map(|c| c.len_utf8())
21936        .sum::<usize>();
21937    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21938
21939    language.brackets().any(|(pair, enabled)| {
21940        let pair_start = pair.start.trim_end();
21941        let pair_end = pair.end.trim_start();
21942
21943        enabled
21944            && pair.newline
21945            && buffer.contains_str_at(range.end, pair_end)
21946            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21947    })
21948}
21949
21950fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21951    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21952        [(buffer, range, _)] => (*buffer, range.clone()),
21953        _ => return false,
21954    };
21955    let pair = {
21956        let mut result: Option<BracketMatch> = None;
21957
21958        for pair in buffer
21959            .all_bracket_ranges(range.clone())
21960            .filter(move |pair| {
21961                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21962            })
21963        {
21964            let len = pair.close_range.end - pair.open_range.start;
21965
21966            if let Some(existing) = &result {
21967                let existing_len = existing.close_range.end - existing.open_range.start;
21968                if len > existing_len {
21969                    continue;
21970                }
21971            }
21972
21973            result = Some(pair);
21974        }
21975
21976        result
21977    };
21978    let Some(pair) = pair else {
21979        return false;
21980    };
21981    pair.newline_only
21982        && buffer
21983            .chars_for_range(pair.open_range.end..range.start)
21984            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21985            .all(|c| c.is_whitespace() && c != '\n')
21986}
21987
21988fn update_uncommitted_diff_for_buffer(
21989    editor: Entity<Editor>,
21990    project: &Entity<Project>,
21991    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21992    buffer: Entity<MultiBuffer>,
21993    cx: &mut App,
21994) -> Task<()> {
21995    let mut tasks = Vec::new();
21996    project.update(cx, |project, cx| {
21997        for buffer in buffers {
21998            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21999                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22000            }
22001        }
22002    });
22003    cx.spawn(async move |cx| {
22004        let diffs = future::join_all(tasks).await;
22005        if editor
22006            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22007            .unwrap_or(false)
22008        {
22009            return;
22010        }
22011
22012        buffer
22013            .update(cx, |buffer, cx| {
22014                for diff in diffs.into_iter().flatten() {
22015                    buffer.add_diff(diff, cx);
22016                }
22017            })
22018            .ok();
22019    })
22020}
22021
22022fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22023    let tab_size = tab_size.get() as usize;
22024    let mut width = offset;
22025
22026    for ch in text.chars() {
22027        width += if ch == '\t' {
22028            tab_size - (width % tab_size)
22029        } else {
22030            1
22031        };
22032    }
22033
22034    width - offset
22035}
22036
22037#[cfg(test)]
22038mod tests {
22039    use super::*;
22040
22041    #[test]
22042    fn test_string_size_with_expanded_tabs() {
22043        let nz = |val| NonZeroU32::new(val).unwrap();
22044        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22045        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22046        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22047        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22048        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22049        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22050        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22051        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22052    }
22053}
22054
22055/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22056struct WordBreakingTokenizer<'a> {
22057    input: &'a str,
22058}
22059
22060impl<'a> WordBreakingTokenizer<'a> {
22061    fn new(input: &'a str) -> Self {
22062        Self { input }
22063    }
22064}
22065
22066fn is_char_ideographic(ch: char) -> bool {
22067    use unicode_script::Script::*;
22068    use unicode_script::UnicodeScript;
22069    matches!(ch.script(), Han | Tangut | Yi)
22070}
22071
22072fn is_grapheme_ideographic(text: &str) -> bool {
22073    text.chars().any(is_char_ideographic)
22074}
22075
22076fn is_grapheme_whitespace(text: &str) -> bool {
22077    text.chars().any(|x| x.is_whitespace())
22078}
22079
22080fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22081    text.chars()
22082        .next()
22083        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22084}
22085
22086#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22087enum WordBreakToken<'a> {
22088    Word { token: &'a str, grapheme_len: usize },
22089    InlineWhitespace { token: &'a str, grapheme_len: usize },
22090    Newline,
22091}
22092
22093impl<'a> Iterator for WordBreakingTokenizer<'a> {
22094    /// Yields a span, the count of graphemes in the token, and whether it was
22095    /// whitespace. Note that it also breaks at word boundaries.
22096    type Item = WordBreakToken<'a>;
22097
22098    fn next(&mut self) -> Option<Self::Item> {
22099        use unicode_segmentation::UnicodeSegmentation;
22100        if self.input.is_empty() {
22101            return None;
22102        }
22103
22104        let mut iter = self.input.graphemes(true).peekable();
22105        let mut offset = 0;
22106        let mut grapheme_len = 0;
22107        if let Some(first_grapheme) = iter.next() {
22108            let is_newline = first_grapheme == "\n";
22109            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22110            offset += first_grapheme.len();
22111            grapheme_len += 1;
22112            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22113                if let Some(grapheme) = iter.peek().copied()
22114                    && should_stay_with_preceding_ideograph(grapheme)
22115                {
22116                    offset += grapheme.len();
22117                    grapheme_len += 1;
22118                }
22119            } else {
22120                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22121                let mut next_word_bound = words.peek().copied();
22122                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22123                    next_word_bound = words.next();
22124                }
22125                while let Some(grapheme) = iter.peek().copied() {
22126                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22127                        break;
22128                    };
22129                    if is_grapheme_whitespace(grapheme) != is_whitespace
22130                        || (grapheme == "\n") != is_newline
22131                    {
22132                        break;
22133                    };
22134                    offset += grapheme.len();
22135                    grapheme_len += 1;
22136                    iter.next();
22137                }
22138            }
22139            let token = &self.input[..offset];
22140            self.input = &self.input[offset..];
22141            if token == "\n" {
22142                Some(WordBreakToken::Newline)
22143            } else if is_whitespace {
22144                Some(WordBreakToken::InlineWhitespace {
22145                    token,
22146                    grapheme_len,
22147                })
22148            } else {
22149                Some(WordBreakToken::Word {
22150                    token,
22151                    grapheme_len,
22152                })
22153            }
22154        } else {
22155            None
22156        }
22157    }
22158}
22159
22160#[test]
22161fn test_word_breaking_tokenizer() {
22162    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22163        ("", &[]),
22164        ("  ", &[whitespace("  ", 2)]),
22165        ("Ʒ", &[word("Ʒ", 1)]),
22166        ("Ǽ", &[word("Ǽ", 1)]),
22167        ("", &[word("", 1)]),
22168        ("⋑⋑", &[word("⋑⋑", 2)]),
22169        (
22170            "原理,进而",
22171            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22172        ),
22173        (
22174            "hello world",
22175            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22176        ),
22177        (
22178            "hello, world",
22179            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22180        ),
22181        (
22182            "  hello world",
22183            &[
22184                whitespace("  ", 2),
22185                word("hello", 5),
22186                whitespace(" ", 1),
22187                word("world", 5),
22188            ],
22189        ),
22190        (
22191            "这是什么 \n 钢笔",
22192            &[
22193                word("", 1),
22194                word("", 1),
22195                word("", 1),
22196                word("", 1),
22197                whitespace(" ", 1),
22198                newline(),
22199                whitespace(" ", 1),
22200                word("", 1),
22201                word("", 1),
22202            ],
22203        ),
22204        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22205    ];
22206
22207    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22208        WordBreakToken::Word {
22209            token,
22210            grapheme_len,
22211        }
22212    }
22213
22214    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22215        WordBreakToken::InlineWhitespace {
22216            token,
22217            grapheme_len,
22218        }
22219    }
22220
22221    fn newline() -> WordBreakToken<'static> {
22222        WordBreakToken::Newline
22223    }
22224
22225    for (input, result) in tests {
22226        assert_eq!(
22227            WordBreakingTokenizer::new(input)
22228                .collect::<Vec<_>>()
22229                .as_slice(),
22230            *result,
22231        );
22232    }
22233}
22234
22235fn wrap_with_prefix(
22236    first_line_prefix: String,
22237    subsequent_lines_prefix: String,
22238    unwrapped_text: String,
22239    wrap_column: usize,
22240    tab_size: NonZeroU32,
22241    preserve_existing_whitespace: bool,
22242) -> String {
22243    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22244    let subsequent_lines_prefix_len =
22245        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22246    let mut wrapped_text = String::new();
22247    let mut current_line = first_line_prefix;
22248    let mut is_first_line = true;
22249
22250    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22251    let mut current_line_len = first_line_prefix_len;
22252    let mut in_whitespace = false;
22253    for token in tokenizer {
22254        let have_preceding_whitespace = in_whitespace;
22255        match token {
22256            WordBreakToken::Word {
22257                token,
22258                grapheme_len,
22259            } => {
22260                in_whitespace = false;
22261                let current_prefix_len = if is_first_line {
22262                    first_line_prefix_len
22263                } else {
22264                    subsequent_lines_prefix_len
22265                };
22266                if current_line_len + grapheme_len > wrap_column
22267                    && current_line_len != current_prefix_len
22268                {
22269                    wrapped_text.push_str(current_line.trim_end());
22270                    wrapped_text.push('\n');
22271                    is_first_line = false;
22272                    current_line = subsequent_lines_prefix.clone();
22273                    current_line_len = subsequent_lines_prefix_len;
22274                }
22275                current_line.push_str(token);
22276                current_line_len += grapheme_len;
22277            }
22278            WordBreakToken::InlineWhitespace {
22279                mut token,
22280                mut grapheme_len,
22281            } => {
22282                in_whitespace = true;
22283                if have_preceding_whitespace && !preserve_existing_whitespace {
22284                    continue;
22285                }
22286                if !preserve_existing_whitespace {
22287                    token = " ";
22288                    grapheme_len = 1;
22289                }
22290                let current_prefix_len = if is_first_line {
22291                    first_line_prefix_len
22292                } else {
22293                    subsequent_lines_prefix_len
22294                };
22295                if current_line_len + grapheme_len > wrap_column {
22296                    wrapped_text.push_str(current_line.trim_end());
22297                    wrapped_text.push('\n');
22298                    is_first_line = false;
22299                    current_line = subsequent_lines_prefix.clone();
22300                    current_line_len = subsequent_lines_prefix_len;
22301                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22302                    current_line.push_str(token);
22303                    current_line_len += grapheme_len;
22304                }
22305            }
22306            WordBreakToken::Newline => {
22307                in_whitespace = true;
22308                let current_prefix_len = if is_first_line {
22309                    first_line_prefix_len
22310                } else {
22311                    subsequent_lines_prefix_len
22312                };
22313                if preserve_existing_whitespace {
22314                    wrapped_text.push_str(current_line.trim_end());
22315                    wrapped_text.push('\n');
22316                    is_first_line = false;
22317                    current_line = subsequent_lines_prefix.clone();
22318                    current_line_len = subsequent_lines_prefix_len;
22319                } else if have_preceding_whitespace {
22320                    continue;
22321                } else if current_line_len + 1 > wrap_column
22322                    && current_line_len != current_prefix_len
22323                {
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 current_line_len != current_prefix_len {
22330                    current_line.push(' ');
22331                    current_line_len += 1;
22332                }
22333            }
22334        }
22335    }
22336
22337    if !current_line.is_empty() {
22338        wrapped_text.push_str(&current_line);
22339    }
22340    wrapped_text
22341}
22342
22343#[test]
22344fn test_wrap_with_prefix() {
22345    assert_eq!(
22346        wrap_with_prefix(
22347            "# ".to_string(),
22348            "# ".to_string(),
22349            "abcdefg".to_string(),
22350            4,
22351            NonZeroU32::new(4).unwrap(),
22352            false,
22353        ),
22354        "# abcdefg"
22355    );
22356    assert_eq!(
22357        wrap_with_prefix(
22358            "".to_string(),
22359            "".to_string(),
22360            "\thello world".to_string(),
22361            8,
22362            NonZeroU32::new(4).unwrap(),
22363            false,
22364        ),
22365        "hello\nworld"
22366    );
22367    assert_eq!(
22368        wrap_with_prefix(
22369            "// ".to_string(),
22370            "// ".to_string(),
22371            "xx \nyy zz aa bb cc".to_string(),
22372            12,
22373            NonZeroU32::new(4).unwrap(),
22374            false,
22375        ),
22376        "// xx yy zz\n// aa bb cc"
22377    );
22378    assert_eq!(
22379        wrap_with_prefix(
22380            String::new(),
22381            String::new(),
22382            "这是什么 \n 钢笔".to_string(),
22383            3,
22384            NonZeroU32::new(4).unwrap(),
22385            false,
22386        ),
22387        "这是什\n么 钢\n"
22388    );
22389}
22390
22391pub trait CollaborationHub {
22392    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22393    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22394    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22395}
22396
22397impl CollaborationHub for Entity<Project> {
22398    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22399        self.read(cx).collaborators()
22400    }
22401
22402    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22403        self.read(cx).user_store().read(cx).participant_indices()
22404    }
22405
22406    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22407        let this = self.read(cx);
22408        let user_ids = this.collaborators().values().map(|c| c.user_id);
22409        this.user_store().read(cx).participant_names(user_ids, cx)
22410    }
22411}
22412
22413pub trait SemanticsProvider {
22414    fn hover(
22415        &self,
22416        buffer: &Entity<Buffer>,
22417        position: text::Anchor,
22418        cx: &mut App,
22419    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22420
22421    fn inline_values(
22422        &self,
22423        buffer_handle: Entity<Buffer>,
22424        range: Range<text::Anchor>,
22425        cx: &mut App,
22426    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22427
22428    fn inlay_hints(
22429        &self,
22430        buffer_handle: Entity<Buffer>,
22431        range: Range<text::Anchor>,
22432        cx: &mut App,
22433    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22434
22435    fn resolve_inlay_hint(
22436        &self,
22437        hint: InlayHint,
22438        buffer_handle: Entity<Buffer>,
22439        server_id: LanguageServerId,
22440        cx: &mut App,
22441    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22442
22443    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22444
22445    fn document_highlights(
22446        &self,
22447        buffer: &Entity<Buffer>,
22448        position: text::Anchor,
22449        cx: &mut App,
22450    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22451
22452    fn definitions(
22453        &self,
22454        buffer: &Entity<Buffer>,
22455        position: text::Anchor,
22456        kind: GotoDefinitionKind,
22457        cx: &mut App,
22458    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22459
22460    fn range_for_rename(
22461        &self,
22462        buffer: &Entity<Buffer>,
22463        position: text::Anchor,
22464        cx: &mut App,
22465    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22466
22467    fn perform_rename(
22468        &self,
22469        buffer: &Entity<Buffer>,
22470        position: text::Anchor,
22471        new_name: String,
22472        cx: &mut App,
22473    ) -> Option<Task<Result<ProjectTransaction>>>;
22474}
22475
22476pub trait CompletionProvider {
22477    fn completions(
22478        &self,
22479        excerpt_id: ExcerptId,
22480        buffer: &Entity<Buffer>,
22481        buffer_position: text::Anchor,
22482        trigger: CompletionContext,
22483        window: &mut Window,
22484        cx: &mut Context<Editor>,
22485    ) -> Task<Result<Vec<CompletionResponse>>>;
22486
22487    fn resolve_completions(
22488        &self,
22489        _buffer: Entity<Buffer>,
22490        _completion_indices: Vec<usize>,
22491        _completions: Rc<RefCell<Box<[Completion]>>>,
22492        _cx: &mut Context<Editor>,
22493    ) -> Task<Result<bool>> {
22494        Task::ready(Ok(false))
22495    }
22496
22497    fn apply_additional_edits_for_completion(
22498        &self,
22499        _buffer: Entity<Buffer>,
22500        _completions: Rc<RefCell<Box<[Completion]>>>,
22501        _completion_index: usize,
22502        _push_to_history: bool,
22503        _cx: &mut Context<Editor>,
22504    ) -> Task<Result<Option<language::Transaction>>> {
22505        Task::ready(Ok(None))
22506    }
22507
22508    fn is_completion_trigger(
22509        &self,
22510        buffer: &Entity<Buffer>,
22511        position: language::Anchor,
22512        text: &str,
22513        trigger_in_words: bool,
22514        menu_is_open: bool,
22515        cx: &mut Context<Editor>,
22516    ) -> bool;
22517
22518    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22519
22520    fn sort_completions(&self) -> bool {
22521        true
22522    }
22523
22524    fn filter_completions(&self) -> bool {
22525        true
22526    }
22527}
22528
22529pub trait CodeActionProvider {
22530    fn id(&self) -> Arc<str>;
22531
22532    fn code_actions(
22533        &self,
22534        buffer: &Entity<Buffer>,
22535        range: Range<text::Anchor>,
22536        window: &mut Window,
22537        cx: &mut App,
22538    ) -> Task<Result<Vec<CodeAction>>>;
22539
22540    fn apply_code_action(
22541        &self,
22542        buffer_handle: Entity<Buffer>,
22543        action: CodeAction,
22544        excerpt_id: ExcerptId,
22545        push_to_history: bool,
22546        window: &mut Window,
22547        cx: &mut App,
22548    ) -> Task<Result<ProjectTransaction>>;
22549}
22550
22551impl CodeActionProvider for Entity<Project> {
22552    fn id(&self) -> Arc<str> {
22553        "project".into()
22554    }
22555
22556    fn code_actions(
22557        &self,
22558        buffer: &Entity<Buffer>,
22559        range: Range<text::Anchor>,
22560        _window: &mut Window,
22561        cx: &mut App,
22562    ) -> Task<Result<Vec<CodeAction>>> {
22563        self.update(cx, |project, cx| {
22564            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22565            let code_actions = project.code_actions(buffer, range, None, cx);
22566            cx.background_spawn(async move {
22567                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22568                Ok(code_lens_actions
22569                    .context("code lens fetch")?
22570                    .into_iter()
22571                    .flatten()
22572                    .chain(
22573                        code_actions
22574                            .context("code action fetch")?
22575                            .into_iter()
22576                            .flatten(),
22577                    )
22578                    .collect())
22579            })
22580        })
22581    }
22582
22583    fn apply_code_action(
22584        &self,
22585        buffer_handle: Entity<Buffer>,
22586        action: CodeAction,
22587        _excerpt_id: ExcerptId,
22588        push_to_history: bool,
22589        _window: &mut Window,
22590        cx: &mut App,
22591    ) -> Task<Result<ProjectTransaction>> {
22592        self.update(cx, |project, cx| {
22593            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22594        })
22595    }
22596}
22597
22598fn snippet_completions(
22599    project: &Project,
22600    buffer: &Entity<Buffer>,
22601    buffer_position: text::Anchor,
22602    cx: &mut App,
22603) -> Task<Result<CompletionResponse>> {
22604    let languages = buffer.read(cx).languages_at(buffer_position);
22605    let snippet_store = project.snippets().read(cx);
22606
22607    let scopes: Vec<_> = languages
22608        .iter()
22609        .filter_map(|language| {
22610            let language_name = language.lsp_id();
22611            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22612
22613            if snippets.is_empty() {
22614                None
22615            } else {
22616                Some((language.default_scope(), snippets))
22617            }
22618        })
22619        .collect();
22620
22621    if scopes.is_empty() {
22622        return Task::ready(Ok(CompletionResponse {
22623            completions: vec![],
22624            display_options: CompletionDisplayOptions::default(),
22625            is_incomplete: false,
22626        }));
22627    }
22628
22629    let snapshot = buffer.read(cx).text_snapshot();
22630    let chars: String = snapshot
22631        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22632        .collect();
22633    let executor = cx.background_executor().clone();
22634
22635    cx.background_spawn(async move {
22636        let mut is_incomplete = false;
22637        let mut completions: Vec<Completion> = Vec::new();
22638        for (scope, snippets) in scopes.into_iter() {
22639            let classifier =
22640                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22641            let mut last_word = chars
22642                .chars()
22643                .take_while(|c| classifier.is_word(*c))
22644                .collect::<String>();
22645            last_word = last_word.chars().rev().collect();
22646
22647            if last_word.is_empty() {
22648                return Ok(CompletionResponse {
22649                    completions: vec![],
22650                    display_options: CompletionDisplayOptions::default(),
22651                    is_incomplete: true,
22652                });
22653            }
22654
22655            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22656            let to_lsp = |point: &text::Anchor| {
22657                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22658                point_to_lsp(end)
22659            };
22660            let lsp_end = to_lsp(&buffer_position);
22661
22662            let candidates = snippets
22663                .iter()
22664                .enumerate()
22665                .flat_map(|(ix, snippet)| {
22666                    snippet
22667                        .prefix
22668                        .iter()
22669                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22670                })
22671                .collect::<Vec<StringMatchCandidate>>();
22672
22673            const MAX_RESULTS: usize = 100;
22674            let mut matches = fuzzy::match_strings(
22675                &candidates,
22676                &last_word,
22677                last_word.chars().any(|c| c.is_uppercase()),
22678                true,
22679                MAX_RESULTS,
22680                &Default::default(),
22681                executor.clone(),
22682            )
22683            .await;
22684
22685            if matches.len() >= MAX_RESULTS {
22686                is_incomplete = true;
22687            }
22688
22689            // Remove all candidates where the query's start does not match the start of any word in the candidate
22690            if let Some(query_start) = last_word.chars().next() {
22691                matches.retain(|string_match| {
22692                    split_words(&string_match.string).any(|word| {
22693                        // Check that the first codepoint of the word as lowercase matches the first
22694                        // codepoint of the query as lowercase
22695                        word.chars()
22696                            .flat_map(|codepoint| codepoint.to_lowercase())
22697                            .zip(query_start.to_lowercase())
22698                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22699                    })
22700                });
22701            }
22702
22703            let matched_strings = matches
22704                .into_iter()
22705                .map(|m| m.string)
22706                .collect::<HashSet<_>>();
22707
22708            completions.extend(snippets.iter().filter_map(|snippet| {
22709                let matching_prefix = snippet
22710                    .prefix
22711                    .iter()
22712                    .find(|prefix| matched_strings.contains(*prefix))?;
22713                let start = as_offset - last_word.len();
22714                let start = snapshot.anchor_before(start);
22715                let range = start..buffer_position;
22716                let lsp_start = to_lsp(&start);
22717                let lsp_range = lsp::Range {
22718                    start: lsp_start,
22719                    end: lsp_end,
22720                };
22721                Some(Completion {
22722                    replace_range: range,
22723                    new_text: snippet.body.clone(),
22724                    source: CompletionSource::Lsp {
22725                        insert_range: None,
22726                        server_id: LanguageServerId(usize::MAX),
22727                        resolved: true,
22728                        lsp_completion: Box::new(lsp::CompletionItem {
22729                            label: snippet.prefix.first().unwrap().clone(),
22730                            kind: Some(CompletionItemKind::SNIPPET),
22731                            label_details: snippet.description.as_ref().map(|description| {
22732                                lsp::CompletionItemLabelDetails {
22733                                    detail: Some(description.clone()),
22734                                    description: None,
22735                                }
22736                            }),
22737                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22738                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22739                                lsp::InsertReplaceEdit {
22740                                    new_text: snippet.body.clone(),
22741                                    insert: lsp_range,
22742                                    replace: lsp_range,
22743                                },
22744                            )),
22745                            filter_text: Some(snippet.body.clone()),
22746                            sort_text: Some(char::MAX.to_string()),
22747                            ..lsp::CompletionItem::default()
22748                        }),
22749                        lsp_defaults: None,
22750                    },
22751                    label: CodeLabel {
22752                        text: matching_prefix.clone(),
22753                        runs: Vec::new(),
22754                        filter_range: 0..matching_prefix.len(),
22755                    },
22756                    icon_path: None,
22757                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22758                        single_line: snippet.name.clone().into(),
22759                        plain_text: snippet
22760                            .description
22761                            .clone()
22762                            .map(|description| description.into()),
22763                    }),
22764                    insert_text_mode: None,
22765                    confirm: None,
22766                })
22767            }))
22768        }
22769
22770        Ok(CompletionResponse {
22771            completions,
22772            display_options: CompletionDisplayOptions::default(),
22773            is_incomplete,
22774        })
22775    })
22776}
22777
22778impl CompletionProvider for Entity<Project> {
22779    fn completions(
22780        &self,
22781        _excerpt_id: ExcerptId,
22782        buffer: &Entity<Buffer>,
22783        buffer_position: text::Anchor,
22784        options: CompletionContext,
22785        _window: &mut Window,
22786        cx: &mut Context<Editor>,
22787    ) -> Task<Result<Vec<CompletionResponse>>> {
22788        self.update(cx, |project, cx| {
22789            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22790            let project_completions = project.completions(buffer, buffer_position, options, cx);
22791            cx.background_spawn(async move {
22792                let mut responses = project_completions.await?;
22793                let snippets = snippets.await?;
22794                if !snippets.completions.is_empty() {
22795                    responses.push(snippets);
22796                }
22797                Ok(responses)
22798            })
22799        })
22800    }
22801
22802    fn resolve_completions(
22803        &self,
22804        buffer: Entity<Buffer>,
22805        completion_indices: Vec<usize>,
22806        completions: Rc<RefCell<Box<[Completion]>>>,
22807        cx: &mut Context<Editor>,
22808    ) -> Task<Result<bool>> {
22809        self.update(cx, |project, cx| {
22810            project.lsp_store().update(cx, |lsp_store, cx| {
22811                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22812            })
22813        })
22814    }
22815
22816    fn apply_additional_edits_for_completion(
22817        &self,
22818        buffer: Entity<Buffer>,
22819        completions: Rc<RefCell<Box<[Completion]>>>,
22820        completion_index: usize,
22821        push_to_history: bool,
22822        cx: &mut Context<Editor>,
22823    ) -> Task<Result<Option<language::Transaction>>> {
22824        self.update(cx, |project, cx| {
22825            project.lsp_store().update(cx, |lsp_store, cx| {
22826                lsp_store.apply_additional_edits_for_completion(
22827                    buffer,
22828                    completions,
22829                    completion_index,
22830                    push_to_history,
22831                    cx,
22832                )
22833            })
22834        })
22835    }
22836
22837    fn is_completion_trigger(
22838        &self,
22839        buffer: &Entity<Buffer>,
22840        position: language::Anchor,
22841        text: &str,
22842        trigger_in_words: bool,
22843        menu_is_open: bool,
22844        cx: &mut Context<Editor>,
22845    ) -> bool {
22846        let mut chars = text.chars();
22847        let char = if let Some(char) = chars.next() {
22848            char
22849        } else {
22850            return false;
22851        };
22852        if chars.next().is_some() {
22853            return false;
22854        }
22855
22856        let buffer = buffer.read(cx);
22857        let snapshot = buffer.snapshot();
22858        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22859            return false;
22860        }
22861        let classifier = snapshot
22862            .char_classifier_at(position)
22863            .scope_context(Some(CharScopeContext::Completion));
22864        if trigger_in_words && classifier.is_word(char) {
22865            return true;
22866        }
22867
22868        buffer.completion_triggers().contains(text)
22869    }
22870}
22871
22872impl SemanticsProvider for Entity<Project> {
22873    fn hover(
22874        &self,
22875        buffer: &Entity<Buffer>,
22876        position: text::Anchor,
22877        cx: &mut App,
22878    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22879        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22880    }
22881
22882    fn document_highlights(
22883        &self,
22884        buffer: &Entity<Buffer>,
22885        position: text::Anchor,
22886        cx: &mut App,
22887    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22888        Some(self.update(cx, |project, cx| {
22889            project.document_highlights(buffer, position, cx)
22890        }))
22891    }
22892
22893    fn definitions(
22894        &self,
22895        buffer: &Entity<Buffer>,
22896        position: text::Anchor,
22897        kind: GotoDefinitionKind,
22898        cx: &mut App,
22899    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22900        Some(self.update(cx, |project, cx| match kind {
22901            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22902            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22903            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22904            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22905        }))
22906    }
22907
22908    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22909        self.update(cx, |project, cx| {
22910            if project
22911                .active_debug_session(cx)
22912                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22913            {
22914                return true;
22915            }
22916
22917            buffer.update(cx, |buffer, cx| {
22918                project.any_language_server_supports_inlay_hints(buffer, cx)
22919            })
22920        })
22921    }
22922
22923    fn inline_values(
22924        &self,
22925        buffer_handle: Entity<Buffer>,
22926        range: Range<text::Anchor>,
22927        cx: &mut App,
22928    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22929        self.update(cx, |project, cx| {
22930            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22931
22932            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22933        })
22934    }
22935
22936    fn inlay_hints(
22937        &self,
22938        buffer_handle: Entity<Buffer>,
22939        range: Range<text::Anchor>,
22940        cx: &mut App,
22941    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22942        Some(self.update(cx, |project, cx| {
22943            project.inlay_hints(buffer_handle, range, cx)
22944        }))
22945    }
22946
22947    fn resolve_inlay_hint(
22948        &self,
22949        hint: InlayHint,
22950        buffer_handle: Entity<Buffer>,
22951        server_id: LanguageServerId,
22952        cx: &mut App,
22953    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22954        Some(self.update(cx, |project, cx| {
22955            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22956        }))
22957    }
22958
22959    fn range_for_rename(
22960        &self,
22961        buffer: &Entity<Buffer>,
22962        position: text::Anchor,
22963        cx: &mut App,
22964    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22965        Some(self.update(cx, |project, cx| {
22966            let buffer = buffer.clone();
22967            let task = project.prepare_rename(buffer.clone(), position, cx);
22968            cx.spawn(async move |_, cx| {
22969                Ok(match task.await? {
22970                    PrepareRenameResponse::Success(range) => Some(range),
22971                    PrepareRenameResponse::InvalidPosition => None,
22972                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22973                        // Fallback on using TreeSitter info to determine identifier range
22974                        buffer.read_with(cx, |buffer, _| {
22975                            let snapshot = buffer.snapshot();
22976                            let (range, kind) = snapshot.surrounding_word(position, None);
22977                            if kind != Some(CharKind::Word) {
22978                                return None;
22979                            }
22980                            Some(
22981                                snapshot.anchor_before(range.start)
22982                                    ..snapshot.anchor_after(range.end),
22983                            )
22984                        })?
22985                    }
22986                })
22987            })
22988        }))
22989    }
22990
22991    fn perform_rename(
22992        &self,
22993        buffer: &Entity<Buffer>,
22994        position: text::Anchor,
22995        new_name: String,
22996        cx: &mut App,
22997    ) -> Option<Task<Result<ProjectTransaction>>> {
22998        Some(self.update(cx, |project, cx| {
22999            project.perform_rename(buffer.clone(), position, new_name, cx)
23000        }))
23001    }
23002}
23003
23004fn inlay_hint_settings(
23005    location: Anchor,
23006    snapshot: &MultiBufferSnapshot,
23007    cx: &mut Context<Editor>,
23008) -> InlayHintSettings {
23009    let file = snapshot.file_at(location);
23010    let language = snapshot.language_at(location).map(|l| l.name());
23011    language_settings(language, file, cx).inlay_hints
23012}
23013
23014fn consume_contiguous_rows(
23015    contiguous_row_selections: &mut Vec<Selection<Point>>,
23016    selection: &Selection<Point>,
23017    display_map: &DisplaySnapshot,
23018    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23019) -> (MultiBufferRow, MultiBufferRow) {
23020    contiguous_row_selections.push(selection.clone());
23021    let start_row = starting_row(selection, display_map);
23022    let mut end_row = ending_row(selection, display_map);
23023
23024    while let Some(next_selection) = selections.peek() {
23025        if next_selection.start.row <= end_row.0 {
23026            end_row = ending_row(next_selection, display_map);
23027            contiguous_row_selections.push(selections.next().unwrap().clone());
23028        } else {
23029            break;
23030        }
23031    }
23032    (start_row, end_row)
23033}
23034
23035fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23036    if selection.start.column > 0 {
23037        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23038    } else {
23039        MultiBufferRow(selection.start.row)
23040    }
23041}
23042
23043fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23044    if next_selection.end.column > 0 || next_selection.is_empty() {
23045        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23046    } else {
23047        MultiBufferRow(next_selection.end.row)
23048    }
23049}
23050
23051impl EditorSnapshot {
23052    pub fn remote_selections_in_range<'a>(
23053        &'a self,
23054        range: &'a Range<Anchor>,
23055        collaboration_hub: &dyn CollaborationHub,
23056        cx: &'a App,
23057    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23058        let participant_names = collaboration_hub.user_names(cx);
23059        let participant_indices = collaboration_hub.user_participant_indices(cx);
23060        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23061        let collaborators_by_replica_id = collaborators_by_peer_id
23062            .values()
23063            .map(|collaborator| (collaborator.replica_id, collaborator))
23064            .collect::<HashMap<_, _>>();
23065        self.buffer_snapshot
23066            .selections_in_range(range, false)
23067            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23068                if replica_id == AGENT_REPLICA_ID {
23069                    Some(RemoteSelection {
23070                        replica_id,
23071                        selection,
23072                        cursor_shape,
23073                        line_mode,
23074                        collaborator_id: CollaboratorId::Agent,
23075                        user_name: Some("Agent".into()),
23076                        color: cx.theme().players().agent(),
23077                    })
23078                } else {
23079                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23080                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23081                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23082                    Some(RemoteSelection {
23083                        replica_id,
23084                        selection,
23085                        cursor_shape,
23086                        line_mode,
23087                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23088                        user_name,
23089                        color: if let Some(index) = participant_index {
23090                            cx.theme().players().color_for_participant(index.0)
23091                        } else {
23092                            cx.theme().players().absent()
23093                        },
23094                    })
23095                }
23096            })
23097    }
23098
23099    pub fn hunks_for_ranges(
23100        &self,
23101        ranges: impl IntoIterator<Item = Range<Point>>,
23102    ) -> Vec<MultiBufferDiffHunk> {
23103        let mut hunks = Vec::new();
23104        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23105            HashMap::default();
23106        for query_range in ranges {
23107            let query_rows =
23108                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23109            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23110                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23111            ) {
23112                // Include deleted hunks that are adjacent to the query range, because
23113                // otherwise they would be missed.
23114                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23115                if hunk.status().is_deleted() {
23116                    intersects_range |= hunk.row_range.start == query_rows.end;
23117                    intersects_range |= hunk.row_range.end == query_rows.start;
23118                }
23119                if intersects_range {
23120                    if !processed_buffer_rows
23121                        .entry(hunk.buffer_id)
23122                        .or_default()
23123                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23124                    {
23125                        continue;
23126                    }
23127                    hunks.push(hunk);
23128                }
23129            }
23130        }
23131
23132        hunks
23133    }
23134
23135    fn display_diff_hunks_for_rows<'a>(
23136        &'a self,
23137        display_rows: Range<DisplayRow>,
23138        folded_buffers: &'a HashSet<BufferId>,
23139    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23140        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23141        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23142
23143        self.buffer_snapshot
23144            .diff_hunks_in_range(buffer_start..buffer_end)
23145            .filter_map(|hunk| {
23146                if folded_buffers.contains(&hunk.buffer_id) {
23147                    return None;
23148                }
23149
23150                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23151                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23152
23153                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23154                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23155
23156                let display_hunk = if hunk_display_start.column() != 0 {
23157                    DisplayDiffHunk::Folded {
23158                        display_row: hunk_display_start.row(),
23159                    }
23160                } else {
23161                    let mut end_row = hunk_display_end.row();
23162                    if hunk_display_end.column() > 0 {
23163                        end_row.0 += 1;
23164                    }
23165                    let is_created_file = hunk.is_created_file();
23166                    DisplayDiffHunk::Unfolded {
23167                        status: hunk.status(),
23168                        diff_base_byte_range: hunk.diff_base_byte_range,
23169                        display_row_range: hunk_display_start.row()..end_row,
23170                        multi_buffer_range: Anchor::range_in_buffer(
23171                            hunk.excerpt_id,
23172                            hunk.buffer_id,
23173                            hunk.buffer_range,
23174                        ),
23175                        is_created_file,
23176                    }
23177                };
23178
23179                Some(display_hunk)
23180            })
23181    }
23182
23183    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23184        self.display_snapshot.buffer_snapshot.language_at(position)
23185    }
23186
23187    pub fn is_focused(&self) -> bool {
23188        self.is_focused
23189    }
23190
23191    pub fn placeholder_text(&self) -> Option<String> {
23192        self.placeholder_display_snapshot
23193            .as_ref()
23194            .map(|display_map| display_map.text())
23195    }
23196
23197    pub fn scroll_position(&self) -> gpui::Point<f32> {
23198        self.scroll_anchor.scroll_position(&self.display_snapshot)
23199    }
23200
23201    fn gutter_dimensions(
23202        &self,
23203        font_id: FontId,
23204        font_size: Pixels,
23205        max_line_number_width: Pixels,
23206        cx: &App,
23207    ) -> Option<GutterDimensions> {
23208        if !self.show_gutter {
23209            return None;
23210        }
23211
23212        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23213        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23214
23215        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23216            matches!(
23217                ProjectSettings::get_global(cx).git.git_gutter,
23218                GitGutterSetting::TrackedFiles
23219            )
23220        });
23221        let gutter_settings = EditorSettings::get_global(cx).gutter;
23222        let show_line_numbers = self
23223            .show_line_numbers
23224            .unwrap_or(gutter_settings.line_numbers);
23225        let line_gutter_width = if show_line_numbers {
23226            // Avoid flicker-like gutter resizes when the line number gains another digit by
23227            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23228            let min_width_for_number_on_gutter =
23229                ch_advance * gutter_settings.min_line_number_digits as f32;
23230            max_line_number_width.max(min_width_for_number_on_gutter)
23231        } else {
23232            0.0.into()
23233        };
23234
23235        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23236        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23237
23238        let git_blame_entries_width =
23239            self.git_blame_gutter_max_author_length
23240                .map(|max_author_length| {
23241                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23242                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23243
23244                    /// The number of characters to dedicate to gaps and margins.
23245                    const SPACING_WIDTH: usize = 4;
23246
23247                    let max_char_count = max_author_length.min(renderer.max_author_length())
23248                        + ::git::SHORT_SHA_LENGTH
23249                        + MAX_RELATIVE_TIMESTAMP.len()
23250                        + SPACING_WIDTH;
23251
23252                    ch_advance * max_char_count
23253                });
23254
23255        let is_singleton = self.buffer_snapshot.is_singleton();
23256
23257        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23258        left_padding += if !is_singleton {
23259            ch_width * 4.0
23260        } else if show_runnables || show_breakpoints {
23261            ch_width * 3.0
23262        } else if show_git_gutter && show_line_numbers {
23263            ch_width * 2.0
23264        } else if show_git_gutter || show_line_numbers {
23265            ch_width
23266        } else {
23267            px(0.)
23268        };
23269
23270        let shows_folds = is_singleton && gutter_settings.folds;
23271
23272        let right_padding = if shows_folds && show_line_numbers {
23273            ch_width * 4.0
23274        } else if shows_folds || (!is_singleton && show_line_numbers) {
23275            ch_width * 3.0
23276        } else if show_line_numbers {
23277            ch_width
23278        } else {
23279            px(0.)
23280        };
23281
23282        Some(GutterDimensions {
23283            left_padding,
23284            right_padding,
23285            width: line_gutter_width + left_padding + right_padding,
23286            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23287            git_blame_entries_width,
23288        })
23289    }
23290
23291    pub fn render_crease_toggle(
23292        &self,
23293        buffer_row: MultiBufferRow,
23294        row_contains_cursor: bool,
23295        editor: Entity<Editor>,
23296        window: &mut Window,
23297        cx: &mut App,
23298    ) -> Option<AnyElement> {
23299        let folded = self.is_line_folded(buffer_row);
23300        let mut is_foldable = false;
23301
23302        if let Some(crease) = self
23303            .crease_snapshot
23304            .query_row(buffer_row, &self.buffer_snapshot)
23305        {
23306            is_foldable = true;
23307            match crease {
23308                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23309                    if let Some(render_toggle) = render_toggle {
23310                        let toggle_callback =
23311                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23312                                if folded {
23313                                    editor.update(cx, |editor, cx| {
23314                                        editor.fold_at(buffer_row, window, cx)
23315                                    });
23316                                } else {
23317                                    editor.update(cx, |editor, cx| {
23318                                        editor.unfold_at(buffer_row, window, cx)
23319                                    });
23320                                }
23321                            });
23322                        return Some((render_toggle)(
23323                            buffer_row,
23324                            folded,
23325                            toggle_callback,
23326                            window,
23327                            cx,
23328                        ));
23329                    }
23330                }
23331            }
23332        }
23333
23334        is_foldable |= self.starts_indent(buffer_row);
23335
23336        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23337            Some(
23338                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23339                    .toggle_state(folded)
23340                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23341                        if folded {
23342                            this.unfold_at(buffer_row, window, cx);
23343                        } else {
23344                            this.fold_at(buffer_row, window, cx);
23345                        }
23346                    }))
23347                    .into_any_element(),
23348            )
23349        } else {
23350            None
23351        }
23352    }
23353
23354    pub fn render_crease_trailer(
23355        &self,
23356        buffer_row: MultiBufferRow,
23357        window: &mut Window,
23358        cx: &mut App,
23359    ) -> Option<AnyElement> {
23360        let folded = self.is_line_folded(buffer_row);
23361        if let Crease::Inline { render_trailer, .. } = self
23362            .crease_snapshot
23363            .query_row(buffer_row, &self.buffer_snapshot)?
23364        {
23365            let render_trailer = render_trailer.as_ref()?;
23366            Some(render_trailer(buffer_row, folded, window, cx))
23367        } else {
23368            None
23369        }
23370    }
23371}
23372
23373impl Deref for EditorSnapshot {
23374    type Target = DisplaySnapshot;
23375
23376    fn deref(&self) -> &Self::Target {
23377        &self.display_snapshot
23378    }
23379}
23380
23381#[derive(Clone, Debug, PartialEq, Eq)]
23382pub enum EditorEvent {
23383    InputIgnored {
23384        text: Arc<str>,
23385    },
23386    InputHandled {
23387        utf16_range_to_replace: Option<Range<isize>>,
23388        text: Arc<str>,
23389    },
23390    ExcerptsAdded {
23391        buffer: Entity<Buffer>,
23392        predecessor: ExcerptId,
23393        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23394    },
23395    ExcerptsRemoved {
23396        ids: Vec<ExcerptId>,
23397        removed_buffer_ids: Vec<BufferId>,
23398    },
23399    BufferFoldToggled {
23400        ids: Vec<ExcerptId>,
23401        folded: bool,
23402    },
23403    ExcerptsEdited {
23404        ids: Vec<ExcerptId>,
23405    },
23406    ExcerptsExpanded {
23407        ids: Vec<ExcerptId>,
23408    },
23409    BufferEdited,
23410    Edited {
23411        transaction_id: clock::Lamport,
23412    },
23413    Reparsed(BufferId),
23414    Focused,
23415    FocusedIn,
23416    Blurred,
23417    DirtyChanged,
23418    Saved,
23419    TitleChanged,
23420    SelectionsChanged {
23421        local: bool,
23422    },
23423    ScrollPositionChanged {
23424        local: bool,
23425        autoscroll: bool,
23426    },
23427    TransactionUndone {
23428        transaction_id: clock::Lamport,
23429    },
23430    TransactionBegun {
23431        transaction_id: clock::Lamport,
23432    },
23433    CursorShapeChanged,
23434    BreadcrumbsChanged,
23435    PushedToNavHistory {
23436        anchor: Anchor,
23437        is_deactivate: bool,
23438    },
23439}
23440
23441impl EventEmitter<EditorEvent> for Editor {}
23442
23443impl Focusable for Editor {
23444    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23445        self.focus_handle.clone()
23446    }
23447}
23448
23449impl Render for Editor {
23450    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23451        let settings = ThemeSettings::get_global(cx);
23452
23453        let mut text_style = match self.mode {
23454            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23455                color: cx.theme().colors().editor_foreground,
23456                font_family: settings.ui_font.family.clone(),
23457                font_features: settings.ui_font.features.clone(),
23458                font_fallbacks: settings.ui_font.fallbacks.clone(),
23459                font_size: rems(0.875).into(),
23460                font_weight: settings.ui_font.weight,
23461                line_height: relative(settings.buffer_line_height.value()),
23462                ..Default::default()
23463            },
23464            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23465                color: cx.theme().colors().editor_foreground,
23466                font_family: settings.buffer_font.family.clone(),
23467                font_features: settings.buffer_font.features.clone(),
23468                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23469                font_size: settings.buffer_font_size(cx).into(),
23470                font_weight: settings.buffer_font.weight,
23471                line_height: relative(settings.buffer_line_height.value()),
23472                ..Default::default()
23473            },
23474        };
23475        if let Some(text_style_refinement) = &self.text_style_refinement {
23476            text_style.refine(text_style_refinement)
23477        }
23478
23479        let background = match self.mode {
23480            EditorMode::SingleLine => cx.theme().system().transparent,
23481            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23482            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23483            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23484        };
23485
23486        EditorElement::new(
23487            &cx.entity(),
23488            EditorStyle {
23489                background,
23490                border: cx.theme().colors().border,
23491                local_player: cx.theme().players().local(),
23492                text: text_style,
23493                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23494                syntax: cx.theme().syntax().clone(),
23495                status: cx.theme().status().clone(),
23496                inlay_hints_style: make_inlay_hints_style(cx),
23497                edit_prediction_styles: make_suggestion_styles(cx),
23498                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23499                show_underlines: self.diagnostics_enabled(),
23500            },
23501        )
23502    }
23503}
23504
23505impl EntityInputHandler for Editor {
23506    fn text_for_range(
23507        &mut self,
23508        range_utf16: Range<usize>,
23509        adjusted_range: &mut Option<Range<usize>>,
23510        _: &mut Window,
23511        cx: &mut Context<Self>,
23512    ) -> Option<String> {
23513        let snapshot = self.buffer.read(cx).read(cx);
23514        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23515        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23516        if (start.0..end.0) != range_utf16 {
23517            adjusted_range.replace(start.0..end.0);
23518        }
23519        Some(snapshot.text_for_range(start..end).collect())
23520    }
23521
23522    fn selected_text_range(
23523        &mut self,
23524        ignore_disabled_input: bool,
23525        _: &mut Window,
23526        cx: &mut Context<Self>,
23527    ) -> Option<UTF16Selection> {
23528        // Prevent the IME menu from appearing when holding down an alphabetic key
23529        // while input is disabled.
23530        if !ignore_disabled_input && !self.input_enabled {
23531            return None;
23532        }
23533
23534        let selection = self.selections.newest::<OffsetUtf16>(cx);
23535        let range = selection.range();
23536
23537        Some(UTF16Selection {
23538            range: range.start.0..range.end.0,
23539            reversed: selection.reversed,
23540        })
23541    }
23542
23543    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23544        let snapshot = self.buffer.read(cx).read(cx);
23545        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23546        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23547    }
23548
23549    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23550        self.clear_highlights::<InputComposition>(cx);
23551        self.ime_transaction.take();
23552    }
23553
23554    fn replace_text_in_range(
23555        &mut self,
23556        range_utf16: Option<Range<usize>>,
23557        text: &str,
23558        window: &mut Window,
23559        cx: &mut Context<Self>,
23560    ) {
23561        if !self.input_enabled {
23562            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23563            return;
23564        }
23565
23566        self.transact(window, cx, |this, window, cx| {
23567            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23568                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23569                Some(this.selection_replacement_ranges(range_utf16, cx))
23570            } else {
23571                this.marked_text_ranges(cx)
23572            };
23573
23574            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23575                let newest_selection_id = this.selections.newest_anchor().id;
23576                this.selections
23577                    .all::<OffsetUtf16>(cx)
23578                    .iter()
23579                    .zip(ranges_to_replace.iter())
23580                    .find_map(|(selection, range)| {
23581                        if selection.id == newest_selection_id {
23582                            Some(
23583                                (range.start.0 as isize - selection.head().0 as isize)
23584                                    ..(range.end.0 as isize - selection.head().0 as isize),
23585                            )
23586                        } else {
23587                            None
23588                        }
23589                    })
23590            });
23591
23592            cx.emit(EditorEvent::InputHandled {
23593                utf16_range_to_replace: range_to_replace,
23594                text: text.into(),
23595            });
23596
23597            if let Some(new_selected_ranges) = new_selected_ranges {
23598                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23599                    selections.select_ranges(new_selected_ranges)
23600                });
23601                this.backspace(&Default::default(), window, cx);
23602            }
23603
23604            this.handle_input(text, window, cx);
23605        });
23606
23607        if let Some(transaction) = self.ime_transaction {
23608            self.buffer.update(cx, |buffer, cx| {
23609                buffer.group_until_transaction(transaction, cx);
23610            });
23611        }
23612
23613        self.unmark_text(window, cx);
23614    }
23615
23616    fn replace_and_mark_text_in_range(
23617        &mut self,
23618        range_utf16: Option<Range<usize>>,
23619        text: &str,
23620        new_selected_range_utf16: Option<Range<usize>>,
23621        window: &mut Window,
23622        cx: &mut Context<Self>,
23623    ) {
23624        if !self.input_enabled {
23625            return;
23626        }
23627
23628        let transaction = self.transact(window, cx, |this, window, cx| {
23629            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23630                let snapshot = this.buffer.read(cx).read(cx);
23631                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23632                    for marked_range in &mut marked_ranges {
23633                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23634                        marked_range.start.0 += relative_range_utf16.start;
23635                        marked_range.start =
23636                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23637                        marked_range.end =
23638                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23639                    }
23640                }
23641                Some(marked_ranges)
23642            } else if let Some(range_utf16) = range_utf16 {
23643                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23644                Some(this.selection_replacement_ranges(range_utf16, cx))
23645            } else {
23646                None
23647            };
23648
23649            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23650                let newest_selection_id = this.selections.newest_anchor().id;
23651                this.selections
23652                    .all::<OffsetUtf16>(cx)
23653                    .iter()
23654                    .zip(ranges_to_replace.iter())
23655                    .find_map(|(selection, range)| {
23656                        if selection.id == newest_selection_id {
23657                            Some(
23658                                (range.start.0 as isize - selection.head().0 as isize)
23659                                    ..(range.end.0 as isize - selection.head().0 as isize),
23660                            )
23661                        } else {
23662                            None
23663                        }
23664                    })
23665            });
23666
23667            cx.emit(EditorEvent::InputHandled {
23668                utf16_range_to_replace: range_to_replace,
23669                text: text.into(),
23670            });
23671
23672            if let Some(ranges) = ranges_to_replace {
23673                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23674                    s.select_ranges(ranges)
23675                });
23676            }
23677
23678            let marked_ranges = {
23679                let snapshot = this.buffer.read(cx).read(cx);
23680                this.selections
23681                    .disjoint_anchors_arc()
23682                    .iter()
23683                    .map(|selection| {
23684                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23685                    })
23686                    .collect::<Vec<_>>()
23687            };
23688
23689            if text.is_empty() {
23690                this.unmark_text(window, cx);
23691            } else {
23692                this.highlight_text::<InputComposition>(
23693                    marked_ranges.clone(),
23694                    HighlightStyle {
23695                        underline: Some(UnderlineStyle {
23696                            thickness: px(1.),
23697                            color: None,
23698                            wavy: false,
23699                        }),
23700                        ..Default::default()
23701                    },
23702                    cx,
23703                );
23704            }
23705
23706            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23707            let use_autoclose = this.use_autoclose;
23708            let use_auto_surround = this.use_auto_surround;
23709            this.set_use_autoclose(false);
23710            this.set_use_auto_surround(false);
23711            this.handle_input(text, window, cx);
23712            this.set_use_autoclose(use_autoclose);
23713            this.set_use_auto_surround(use_auto_surround);
23714
23715            if let Some(new_selected_range) = new_selected_range_utf16 {
23716                let snapshot = this.buffer.read(cx).read(cx);
23717                let new_selected_ranges = marked_ranges
23718                    .into_iter()
23719                    .map(|marked_range| {
23720                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23721                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23722                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23723                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23724                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23725                    })
23726                    .collect::<Vec<_>>();
23727
23728                drop(snapshot);
23729                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23730                    selections.select_ranges(new_selected_ranges)
23731                });
23732            }
23733        });
23734
23735        self.ime_transaction = self.ime_transaction.or(transaction);
23736        if let Some(transaction) = self.ime_transaction {
23737            self.buffer.update(cx, |buffer, cx| {
23738                buffer.group_until_transaction(transaction, cx);
23739            });
23740        }
23741
23742        if self.text_highlights::<InputComposition>(cx).is_none() {
23743            self.ime_transaction.take();
23744        }
23745    }
23746
23747    fn bounds_for_range(
23748        &mut self,
23749        range_utf16: Range<usize>,
23750        element_bounds: gpui::Bounds<Pixels>,
23751        window: &mut Window,
23752        cx: &mut Context<Self>,
23753    ) -> Option<gpui::Bounds<Pixels>> {
23754        let text_layout_details = self.text_layout_details(window);
23755        let CharacterDimensions {
23756            em_width,
23757            em_advance,
23758            line_height,
23759        } = self.character_dimensions(window);
23760
23761        let snapshot = self.snapshot(window, cx);
23762        let scroll_position = snapshot.scroll_position();
23763        let scroll_left = scroll_position.x * em_advance;
23764
23765        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23766        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23767            + self.gutter_dimensions.full_width();
23768        let y = line_height * (start.row().as_f32() - scroll_position.y);
23769
23770        Some(Bounds {
23771            origin: element_bounds.origin + point(x, y),
23772            size: size(em_width, line_height),
23773        })
23774    }
23775
23776    fn character_index_for_point(
23777        &mut self,
23778        point: gpui::Point<Pixels>,
23779        _window: &mut Window,
23780        _cx: &mut Context<Self>,
23781    ) -> Option<usize> {
23782        let position_map = self.last_position_map.as_ref()?;
23783        if !position_map.text_hitbox.contains(&point) {
23784            return None;
23785        }
23786        let display_point = position_map.point_for_position(point).previous_valid;
23787        let anchor = position_map
23788            .snapshot
23789            .display_point_to_anchor(display_point, Bias::Left);
23790        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23791        Some(utf16_offset.0)
23792    }
23793}
23794
23795trait SelectionExt {
23796    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23797    fn spanned_rows(
23798        &self,
23799        include_end_if_at_line_start: bool,
23800        map: &DisplaySnapshot,
23801    ) -> Range<MultiBufferRow>;
23802}
23803
23804impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23805    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23806        let start = self
23807            .start
23808            .to_point(&map.buffer_snapshot)
23809            .to_display_point(map);
23810        let end = self
23811            .end
23812            .to_point(&map.buffer_snapshot)
23813            .to_display_point(map);
23814        if self.reversed {
23815            end..start
23816        } else {
23817            start..end
23818        }
23819    }
23820
23821    fn spanned_rows(
23822        &self,
23823        include_end_if_at_line_start: bool,
23824        map: &DisplaySnapshot,
23825    ) -> Range<MultiBufferRow> {
23826        let start = self.start.to_point(&map.buffer_snapshot);
23827        let mut end = self.end.to_point(&map.buffer_snapshot);
23828        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23829            end.row -= 1;
23830        }
23831
23832        let buffer_start = map.prev_line_boundary(start).0;
23833        let buffer_end = map.next_line_boundary(end).0;
23834        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23835    }
23836}
23837
23838impl<T: InvalidationRegion> InvalidationStack<T> {
23839    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23840    where
23841        S: Clone + ToOffset,
23842    {
23843        while let Some(region) = self.last() {
23844            let all_selections_inside_invalidation_ranges =
23845                if selections.len() == region.ranges().len() {
23846                    selections
23847                        .iter()
23848                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23849                        .all(|(selection, invalidation_range)| {
23850                            let head = selection.head().to_offset(buffer);
23851                            invalidation_range.start <= head && invalidation_range.end >= head
23852                        })
23853                } else {
23854                    false
23855                };
23856
23857            if all_selections_inside_invalidation_ranges {
23858                break;
23859            } else {
23860                self.pop();
23861            }
23862        }
23863    }
23864}
23865
23866impl<T> Default for InvalidationStack<T> {
23867    fn default() -> Self {
23868        Self(Default::default())
23869    }
23870}
23871
23872impl<T> Deref for InvalidationStack<T> {
23873    type Target = Vec<T>;
23874
23875    fn deref(&self) -> &Self::Target {
23876        &self.0
23877    }
23878}
23879
23880impl<T> DerefMut for InvalidationStack<T> {
23881    fn deref_mut(&mut self) -> &mut Self::Target {
23882        &mut self.0
23883    }
23884}
23885
23886impl InvalidationRegion for SnippetState {
23887    fn ranges(&self) -> &[Range<Anchor>] {
23888        &self.ranges[self.active_index]
23889    }
23890}
23891
23892fn edit_prediction_edit_text(
23893    current_snapshot: &BufferSnapshot,
23894    edits: &[(Range<Anchor>, String)],
23895    edit_preview: &EditPreview,
23896    include_deletions: bool,
23897    cx: &App,
23898) -> HighlightedText {
23899    let edits = edits
23900        .iter()
23901        .map(|(anchor, text)| {
23902            (
23903                anchor.start.text_anchor..anchor.end.text_anchor,
23904                text.clone(),
23905            )
23906        })
23907        .collect::<Vec<_>>();
23908
23909    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23910}
23911
23912fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23913    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23914    // Just show the raw edit text with basic styling
23915    let mut text = String::new();
23916    let mut highlights = Vec::new();
23917
23918    let insertion_highlight_style = HighlightStyle {
23919        color: Some(cx.theme().colors().text),
23920        ..Default::default()
23921    };
23922
23923    for (_, edit_text) in edits {
23924        let start_offset = text.len();
23925        text.push_str(edit_text);
23926        let end_offset = text.len();
23927
23928        if start_offset < end_offset {
23929            highlights.push((start_offset..end_offset, insertion_highlight_style));
23930        }
23931    }
23932
23933    HighlightedText {
23934        text: text.into(),
23935        highlights,
23936    }
23937}
23938
23939pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23940    match severity {
23941        lsp::DiagnosticSeverity::ERROR => colors.error,
23942        lsp::DiagnosticSeverity::WARNING => colors.warning,
23943        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23944        lsp::DiagnosticSeverity::HINT => colors.info,
23945        _ => colors.ignored,
23946    }
23947}
23948
23949pub fn styled_runs_for_code_label<'a>(
23950    label: &'a CodeLabel,
23951    syntax_theme: &'a theme::SyntaxTheme,
23952) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23953    let fade_out = HighlightStyle {
23954        fade_out: Some(0.35),
23955        ..Default::default()
23956    };
23957
23958    let mut prev_end = label.filter_range.end;
23959    label
23960        .runs
23961        .iter()
23962        .enumerate()
23963        .flat_map(move |(ix, (range, highlight_id))| {
23964            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23965                style
23966            } else {
23967                return Default::default();
23968            };
23969            let muted_style = style.highlight(fade_out);
23970
23971            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23972            if range.start >= label.filter_range.end {
23973                if range.start > prev_end {
23974                    runs.push((prev_end..range.start, fade_out));
23975                }
23976                runs.push((range.clone(), muted_style));
23977            } else if range.end <= label.filter_range.end {
23978                runs.push((range.clone(), style));
23979            } else {
23980                runs.push((range.start..label.filter_range.end, style));
23981                runs.push((label.filter_range.end..range.end, muted_style));
23982            }
23983            prev_end = cmp::max(prev_end, range.end);
23984
23985            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23986                runs.push((prev_end..label.text.len(), fade_out));
23987            }
23988
23989            runs
23990        })
23991}
23992
23993pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23994    let mut prev_index = 0;
23995    let mut prev_codepoint: Option<char> = None;
23996    text.char_indices()
23997        .chain([(text.len(), '\0')])
23998        .filter_map(move |(index, codepoint)| {
23999            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24000            let is_boundary = index == text.len()
24001                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24002                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24003            if is_boundary {
24004                let chunk = &text[prev_index..index];
24005                prev_index = index;
24006                Some(chunk)
24007            } else {
24008                None
24009            }
24010        })
24011}
24012
24013pub trait RangeToAnchorExt: Sized {
24014    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24015
24016    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24017        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24018        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24019    }
24020}
24021
24022impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24023    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24024        let start_offset = self.start.to_offset(snapshot);
24025        let end_offset = self.end.to_offset(snapshot);
24026        if start_offset == end_offset {
24027            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24028        } else {
24029            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24030        }
24031    }
24032}
24033
24034pub trait RowExt {
24035    fn as_f32(&self) -> f32;
24036
24037    fn next_row(&self) -> Self;
24038
24039    fn previous_row(&self) -> Self;
24040
24041    fn minus(&self, other: Self) -> u32;
24042}
24043
24044impl RowExt for DisplayRow {
24045    fn as_f32(&self) -> f32 {
24046        self.0 as f32
24047    }
24048
24049    fn next_row(&self) -> Self {
24050        Self(self.0 + 1)
24051    }
24052
24053    fn previous_row(&self) -> Self {
24054        Self(self.0.saturating_sub(1))
24055    }
24056
24057    fn minus(&self, other: Self) -> u32 {
24058        self.0 - other.0
24059    }
24060}
24061
24062impl RowExt for MultiBufferRow {
24063    fn as_f32(&self) -> f32 {
24064        self.0 as f32
24065    }
24066
24067    fn next_row(&self) -> Self {
24068        Self(self.0 + 1)
24069    }
24070
24071    fn previous_row(&self) -> Self {
24072        Self(self.0.saturating_sub(1))
24073    }
24074
24075    fn minus(&self, other: Self) -> u32 {
24076        self.0 - other.0
24077    }
24078}
24079
24080trait RowRangeExt {
24081    type Row;
24082
24083    fn len(&self) -> usize;
24084
24085    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24086}
24087
24088impl RowRangeExt for Range<MultiBufferRow> {
24089    type Row = MultiBufferRow;
24090
24091    fn len(&self) -> usize {
24092        (self.end.0 - self.start.0) as usize
24093    }
24094
24095    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24096        (self.start.0..self.end.0).map(MultiBufferRow)
24097    }
24098}
24099
24100impl RowRangeExt for Range<DisplayRow> {
24101    type Row = DisplayRow;
24102
24103    fn len(&self) -> usize {
24104        (self.end.0 - self.start.0) as usize
24105    }
24106
24107    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24108        (self.start.0..self.end.0).map(DisplayRow)
24109    }
24110}
24111
24112/// If select range has more than one line, we
24113/// just point the cursor to range.start.
24114fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24115    if range.start.row == range.end.row {
24116        range
24117    } else {
24118        range.start..range.start
24119    }
24120}
24121pub struct KillRing(ClipboardItem);
24122impl Global for KillRing {}
24123
24124const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24125
24126enum BreakpointPromptEditAction {
24127    Log,
24128    Condition,
24129    HitCondition,
24130}
24131
24132struct BreakpointPromptEditor {
24133    pub(crate) prompt: Entity<Editor>,
24134    editor: WeakEntity<Editor>,
24135    breakpoint_anchor: Anchor,
24136    breakpoint: Breakpoint,
24137    edit_action: BreakpointPromptEditAction,
24138    block_ids: HashSet<CustomBlockId>,
24139    editor_margins: Arc<Mutex<EditorMargins>>,
24140    _subscriptions: Vec<Subscription>,
24141}
24142
24143impl BreakpointPromptEditor {
24144    const MAX_LINES: u8 = 4;
24145
24146    fn new(
24147        editor: WeakEntity<Editor>,
24148        breakpoint_anchor: Anchor,
24149        breakpoint: Breakpoint,
24150        edit_action: BreakpointPromptEditAction,
24151        window: &mut Window,
24152        cx: &mut Context<Self>,
24153    ) -> Self {
24154        let base_text = match edit_action {
24155            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24156            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24157            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24158        }
24159        .map(|msg| msg.to_string())
24160        .unwrap_or_default();
24161
24162        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24163        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24164
24165        let prompt = cx.new(|cx| {
24166            let mut prompt = Editor::new(
24167                EditorMode::AutoHeight {
24168                    min_lines: 1,
24169                    max_lines: Some(Self::MAX_LINES as usize),
24170                },
24171                buffer,
24172                None,
24173                window,
24174                cx,
24175            );
24176            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24177            prompt.set_show_cursor_when_unfocused(false, cx);
24178            prompt.set_placeholder_text(
24179                match edit_action {
24180                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24181                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24182                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24183                },
24184                window,
24185                cx,
24186            );
24187
24188            prompt
24189        });
24190
24191        Self {
24192            prompt,
24193            editor,
24194            breakpoint_anchor,
24195            breakpoint,
24196            edit_action,
24197            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24198            block_ids: Default::default(),
24199            _subscriptions: vec![],
24200        }
24201    }
24202
24203    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24204        self.block_ids.extend(block_ids)
24205    }
24206
24207    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24208        if let Some(editor) = self.editor.upgrade() {
24209            let message = self
24210                .prompt
24211                .read(cx)
24212                .buffer
24213                .read(cx)
24214                .as_singleton()
24215                .expect("A multi buffer in breakpoint prompt isn't possible")
24216                .read(cx)
24217                .as_rope()
24218                .to_string();
24219
24220            editor.update(cx, |editor, cx| {
24221                editor.edit_breakpoint_at_anchor(
24222                    self.breakpoint_anchor,
24223                    self.breakpoint.clone(),
24224                    match self.edit_action {
24225                        BreakpointPromptEditAction::Log => {
24226                            BreakpointEditAction::EditLogMessage(message.into())
24227                        }
24228                        BreakpointPromptEditAction::Condition => {
24229                            BreakpointEditAction::EditCondition(message.into())
24230                        }
24231                        BreakpointPromptEditAction::HitCondition => {
24232                            BreakpointEditAction::EditHitCondition(message.into())
24233                        }
24234                    },
24235                    cx,
24236                );
24237
24238                editor.remove_blocks(self.block_ids.clone(), None, cx);
24239                cx.focus_self(window);
24240            });
24241        }
24242    }
24243
24244    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24245        self.editor
24246            .update(cx, |editor, cx| {
24247                editor.remove_blocks(self.block_ids.clone(), None, cx);
24248                window.focus(&editor.focus_handle);
24249            })
24250            .log_err();
24251    }
24252
24253    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24254        let settings = ThemeSettings::get_global(cx);
24255        let text_style = TextStyle {
24256            color: if self.prompt.read(cx).read_only(cx) {
24257                cx.theme().colors().text_disabled
24258            } else {
24259                cx.theme().colors().text
24260            },
24261            font_family: settings.buffer_font.family.clone(),
24262            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24263            font_size: settings.buffer_font_size(cx).into(),
24264            font_weight: settings.buffer_font.weight,
24265            line_height: relative(settings.buffer_line_height.value()),
24266            ..Default::default()
24267        };
24268        EditorElement::new(
24269            &self.prompt,
24270            EditorStyle {
24271                background: cx.theme().colors().editor_background,
24272                local_player: cx.theme().players().local(),
24273                text: text_style,
24274                ..Default::default()
24275            },
24276        )
24277    }
24278}
24279
24280impl Render for BreakpointPromptEditor {
24281    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24282        let editor_margins = *self.editor_margins.lock();
24283        let gutter_dimensions = editor_margins.gutter;
24284        h_flex()
24285            .key_context("Editor")
24286            .bg(cx.theme().colors().editor_background)
24287            .border_y_1()
24288            .border_color(cx.theme().status().info_border)
24289            .size_full()
24290            .py(window.line_height() / 2.5)
24291            .on_action(cx.listener(Self::confirm))
24292            .on_action(cx.listener(Self::cancel))
24293            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24294            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24295    }
24296}
24297
24298impl Focusable for BreakpointPromptEditor {
24299    fn focus_handle(&self, cx: &App) -> FocusHandle {
24300        self.prompt.focus_handle(cx)
24301    }
24302}
24303
24304fn all_edits_insertions_or_deletions(
24305    edits: &Vec<(Range<Anchor>, String)>,
24306    snapshot: &MultiBufferSnapshot,
24307) -> bool {
24308    let mut all_insertions = true;
24309    let mut all_deletions = true;
24310
24311    for (range, new_text) in edits.iter() {
24312        let range_is_empty = range.to_offset(snapshot).is_empty();
24313        let text_is_empty = new_text.is_empty();
24314
24315        if range_is_empty != text_is_empty {
24316            if range_is_empty {
24317                all_deletions = false;
24318            } else {
24319                all_insertions = false;
24320            }
24321        } else {
24322            return false;
24323        }
24324
24325        if !all_insertions && !all_deletions {
24326            return false;
24327        }
24328    }
24329    all_insertions || all_deletions
24330}
24331
24332struct MissingEditPredictionKeybindingTooltip;
24333
24334impl Render for MissingEditPredictionKeybindingTooltip {
24335    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24336        ui::tooltip_container(window, cx, |container, _, cx| {
24337            container
24338                .flex_shrink_0()
24339                .max_w_80()
24340                .min_h(rems_from_px(124.))
24341                .justify_between()
24342                .child(
24343                    v_flex()
24344                        .flex_1()
24345                        .text_ui_sm(cx)
24346                        .child(Label::new("Conflict with Accept Keybinding"))
24347                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24348                )
24349                .child(
24350                    h_flex()
24351                        .pb_1()
24352                        .gap_1()
24353                        .items_end()
24354                        .w_full()
24355                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24356                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24357                        }))
24358                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24359                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24360                        })),
24361                )
24362        })
24363    }
24364}
24365
24366#[derive(Debug, Clone, Copy, PartialEq)]
24367pub struct LineHighlight {
24368    pub background: Background,
24369    pub border: Option<gpui::Hsla>,
24370    pub include_gutter: bool,
24371    pub type_id: Option<TypeId>,
24372}
24373
24374struct LineManipulationResult {
24375    pub new_text: String,
24376    pub line_count_before: usize,
24377    pub line_count_after: usize,
24378}
24379
24380fn render_diff_hunk_controls(
24381    row: u32,
24382    status: &DiffHunkStatus,
24383    hunk_range: Range<Anchor>,
24384    is_created_file: bool,
24385    line_height: Pixels,
24386    editor: &Entity<Editor>,
24387    _window: &mut Window,
24388    cx: &mut App,
24389) -> AnyElement {
24390    h_flex()
24391        .h(line_height)
24392        .mr_1()
24393        .gap_1()
24394        .px_0p5()
24395        .pb_1()
24396        .border_x_1()
24397        .border_b_1()
24398        .border_color(cx.theme().colors().border_variant)
24399        .rounded_b_lg()
24400        .bg(cx.theme().colors().editor_background)
24401        .gap_1()
24402        .block_mouse_except_scroll()
24403        .shadow_md()
24404        .child(if status.has_secondary_hunk() {
24405            Button::new(("stage", row as u64), "Stage")
24406                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24407                .tooltip({
24408                    let focus_handle = editor.focus_handle(cx);
24409                    move |window, cx| {
24410                        Tooltip::for_action_in(
24411                            "Stage Hunk",
24412                            &::git::ToggleStaged,
24413                            &focus_handle,
24414                            window,
24415                            cx,
24416                        )
24417                    }
24418                })
24419                .on_click({
24420                    let editor = editor.clone();
24421                    move |_event, _window, cx| {
24422                        editor.update(cx, |editor, cx| {
24423                            editor.stage_or_unstage_diff_hunks(
24424                                true,
24425                                vec![hunk_range.start..hunk_range.start],
24426                                cx,
24427                            );
24428                        });
24429                    }
24430                })
24431        } else {
24432            Button::new(("unstage", row as u64), "Unstage")
24433                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24434                .tooltip({
24435                    let focus_handle = editor.focus_handle(cx);
24436                    move |window, cx| {
24437                        Tooltip::for_action_in(
24438                            "Unstage Hunk",
24439                            &::git::ToggleStaged,
24440                            &focus_handle,
24441                            window,
24442                            cx,
24443                        )
24444                    }
24445                })
24446                .on_click({
24447                    let editor = editor.clone();
24448                    move |_event, _window, cx| {
24449                        editor.update(cx, |editor, cx| {
24450                            editor.stage_or_unstage_diff_hunks(
24451                                false,
24452                                vec![hunk_range.start..hunk_range.start],
24453                                cx,
24454                            );
24455                        });
24456                    }
24457                })
24458        })
24459        .child(
24460            Button::new(("restore", row as u64), "Restore")
24461                .tooltip({
24462                    let focus_handle = editor.focus_handle(cx);
24463                    move |window, cx| {
24464                        Tooltip::for_action_in(
24465                            "Restore Hunk",
24466                            &::git::Restore,
24467                            &focus_handle,
24468                            window,
24469                            cx,
24470                        )
24471                    }
24472                })
24473                .on_click({
24474                    let editor = editor.clone();
24475                    move |_event, window, cx| {
24476                        editor.update(cx, |editor, cx| {
24477                            let snapshot = editor.snapshot(window, cx);
24478                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24479                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24480                        });
24481                    }
24482                })
24483                .disabled(is_created_file),
24484        )
24485        .when(
24486            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24487            |el| {
24488                el.child(
24489                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24490                        .shape(IconButtonShape::Square)
24491                        .icon_size(IconSize::Small)
24492                        // .disabled(!has_multiple_hunks)
24493                        .tooltip({
24494                            let focus_handle = editor.focus_handle(cx);
24495                            move |window, cx| {
24496                                Tooltip::for_action_in(
24497                                    "Next Hunk",
24498                                    &GoToHunk,
24499                                    &focus_handle,
24500                                    window,
24501                                    cx,
24502                                )
24503                            }
24504                        })
24505                        .on_click({
24506                            let editor = editor.clone();
24507                            move |_event, window, cx| {
24508                                editor.update(cx, |editor, cx| {
24509                                    let snapshot = editor.snapshot(window, cx);
24510                                    let position =
24511                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24512                                    editor.go_to_hunk_before_or_after_position(
24513                                        &snapshot,
24514                                        position,
24515                                        Direction::Next,
24516                                        window,
24517                                        cx,
24518                                    );
24519                                    editor.expand_selected_diff_hunks(cx);
24520                                });
24521                            }
24522                        }),
24523                )
24524                .child(
24525                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24526                        .shape(IconButtonShape::Square)
24527                        .icon_size(IconSize::Small)
24528                        // .disabled(!has_multiple_hunks)
24529                        .tooltip({
24530                            let focus_handle = editor.focus_handle(cx);
24531                            move |window, cx| {
24532                                Tooltip::for_action_in(
24533                                    "Previous Hunk",
24534                                    &GoToPreviousHunk,
24535                                    &focus_handle,
24536                                    window,
24537                                    cx,
24538                                )
24539                            }
24540                        })
24541                        .on_click({
24542                            let editor = editor.clone();
24543                            move |_event, window, cx| {
24544                                editor.update(cx, |editor, cx| {
24545                                    let snapshot = editor.snapshot(window, cx);
24546                                    let point =
24547                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24548                                    editor.go_to_hunk_before_or_after_position(
24549                                        &snapshot,
24550                                        point,
24551                                        Direction::Prev,
24552                                        window,
24553                                        cx,
24554                                    );
24555                                    editor.expand_selected_diff_hunks(cx);
24556                                });
24557                            }
24558                        }),
24559                )
24560            },
24561        )
24562        .into_any_element()
24563}
24564
24565pub fn multibuffer_context_lines(cx: &App) -> u32 {
24566    EditorSettings::try_get(cx)
24567        .map(|settings| settings.excerpt_context_lines)
24568        .unwrap_or(2)
24569        .min(32)
24570}