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, parse_zed_link};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    Move {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645}
  646
  647struct EditPredictionState {
  648    inlay_ids: Vec<InlayId>,
  649    completion: EditPrediction,
  650    completion_id: Option<SharedString>,
  651    invalidation_range: Range<Anchor>,
  652}
  653
  654enum EditPredictionSettings {
  655    Disabled,
  656    Enabled {
  657        show_in_menu: bool,
  658        preview_requires_modifier: bool,
  659    },
  660}
  661
  662enum EditPredictionHighlight {}
  663
  664#[derive(Debug, Clone)]
  665struct InlineDiagnostic {
  666    message: SharedString,
  667    group_id: usize,
  668    is_primary: bool,
  669    start: Point,
  670    severity: lsp::DiagnosticSeverity,
  671}
  672
  673pub enum MenuEditPredictionsPolicy {
  674    Never,
  675    ByProvider,
  676}
  677
  678pub enum EditPredictionPreview {
  679    /// Modifier is not pressed
  680    Inactive { released_too_fast: bool },
  681    /// Modifier pressed
  682    Active {
  683        since: Instant,
  684        previous_scroll_position: Option<ScrollAnchor>,
  685    },
  686}
  687
  688impl EditPredictionPreview {
  689    pub fn released_too_fast(&self) -> bool {
  690        match self {
  691            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  692            EditPredictionPreview::Active { .. } => false,
  693        }
  694    }
  695
  696    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  697        if let EditPredictionPreview::Active {
  698            previous_scroll_position,
  699            ..
  700        } = self
  701        {
  702            *previous_scroll_position = scroll_position;
  703        }
  704    }
  705}
  706
  707pub struct ContextMenuOptions {
  708    pub min_entries_visible: usize,
  709    pub max_entries_visible: usize,
  710    pub placement: Option<ContextMenuPlacement>,
  711}
  712
  713#[derive(Debug, Clone, PartialEq, Eq)]
  714pub enum ContextMenuPlacement {
  715    Above,
  716    Below,
  717}
  718
  719#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  720struct EditorActionId(usize);
  721
  722impl EditorActionId {
  723    pub fn post_inc(&mut self) -> Self {
  724        let answer = self.0;
  725
  726        *self = Self(answer + 1);
  727
  728        Self(answer)
  729    }
  730}
  731
  732// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  733// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  734
  735type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  736type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  737
  738#[derive(Default)]
  739struct ScrollbarMarkerState {
  740    scrollbar_size: Size<Pixels>,
  741    dirty: bool,
  742    markers: Arc<[PaintQuad]>,
  743    pending_refresh: Option<Task<Result<()>>>,
  744}
  745
  746impl ScrollbarMarkerState {
  747    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  748        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  749    }
  750}
  751
  752#[derive(Clone, Copy, PartialEq, Eq)]
  753pub enum MinimapVisibility {
  754    Disabled,
  755    Enabled {
  756        /// The configuration currently present in the users settings.
  757        setting_configuration: bool,
  758        /// Whether to override the currently set visibility from the users setting.
  759        toggle_override: bool,
  760    },
  761}
  762
  763impl MinimapVisibility {
  764    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  765        if mode.is_full() {
  766            Self::Enabled {
  767                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  768                toggle_override: false,
  769            }
  770        } else {
  771            Self::Disabled
  772        }
  773    }
  774
  775    fn hidden(&self) -> Self {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => Self::Enabled {
  781                setting_configuration,
  782                toggle_override: setting_configuration,
  783            },
  784            Self::Disabled => Self::Disabled,
  785        }
  786    }
  787
  788    fn disabled(&self) -> bool {
  789        matches!(*self, Self::Disabled)
  790    }
  791
  792    fn settings_visibility(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                ..
  797            } => setting_configuration,
  798            _ => false,
  799        }
  800    }
  801
  802    fn visible(&self) -> bool {
  803        match *self {
  804            Self::Enabled {
  805                setting_configuration,
  806                toggle_override,
  807            } => setting_configuration ^ toggle_override,
  808            _ => false,
  809        }
  810    }
  811
  812    fn toggle_visibility(&self) -> Self {
  813        match *self {
  814            Self::Enabled {
  815                toggle_override,
  816                setting_configuration,
  817            } => Self::Enabled {
  818                setting_configuration,
  819                toggle_override: !toggle_override,
  820            },
  821            Self::Disabled => Self::Disabled,
  822        }
  823    }
  824}
  825
  826#[derive(Clone, Debug)]
  827struct RunnableTasks {
  828    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  829    offset: multi_buffer::Anchor,
  830    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  831    column: u32,
  832    // Values of all named captures, including those starting with '_'
  833    extra_variables: HashMap<String, String>,
  834    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  835    context_range: Range<BufferOffset>,
  836}
  837
  838impl RunnableTasks {
  839    fn resolve<'a>(
  840        &'a self,
  841        cx: &'a task::TaskContext,
  842    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  843        self.templates.iter().filter_map(|(kind, template)| {
  844            template
  845                .resolve_task(&kind.to_id_base(), cx)
  846                .map(|task| (kind.clone(), task))
  847        })
  848    }
  849}
  850
  851#[derive(Clone)]
  852pub struct ResolvedTasks {
  853    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  854    position: Anchor,
  855}
  856
  857#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  858struct BufferOffset(usize);
  859
  860/// Addons allow storing per-editor state in other crates (e.g. Vim)
  861pub trait Addon: 'static {
  862    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  863
  864    fn render_buffer_header_controls(
  865        &self,
  866        _: &ExcerptInfo,
  867        _: &Window,
  868        _: &App,
  869    ) -> Option<AnyElement> {
  870        None
  871    }
  872
  873    fn to_any(&self) -> &dyn std::any::Any;
  874
  875    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  876        None
  877    }
  878}
  879
  880struct ChangeLocation {
  881    current: Option<Vec<Anchor>>,
  882    original: Vec<Anchor>,
  883}
  884impl ChangeLocation {
  885    fn locations(&self) -> &[Anchor] {
  886        self.current.as_ref().unwrap_or(&self.original)
  887    }
  888}
  889
  890/// A set of caret positions, registered when the editor was edited.
  891pub struct ChangeList {
  892    changes: Vec<ChangeLocation>,
  893    /// Currently "selected" change.
  894    position: Option<usize>,
  895}
  896
  897impl ChangeList {
  898    pub fn new() -> Self {
  899        Self {
  900            changes: Vec::new(),
  901            position: None,
  902        }
  903    }
  904
  905    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  906    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  907    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  908        if self.changes.is_empty() {
  909            return None;
  910        }
  911
  912        let prev = self.position.unwrap_or(self.changes.len());
  913        let next = if direction == Direction::Prev {
  914            prev.saturating_sub(count)
  915        } else {
  916            (prev + count).min(self.changes.len() - 1)
  917        };
  918        self.position = Some(next);
  919        self.changes.get(next).map(|change| change.locations())
  920    }
  921
  922    /// Adds a new change to the list, resetting the change list position.
  923    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  924        self.position.take();
  925        if let Some(last) = self.changes.last_mut()
  926            && group
  927        {
  928            last.current = Some(new_positions)
  929        } else {
  930            self.changes.push(ChangeLocation {
  931                original: new_positions,
  932                current: None,
  933            });
  934        }
  935    }
  936
  937    pub fn last(&self) -> Option<&[Anchor]> {
  938        self.changes.last().map(|change| change.locations())
  939    }
  940
  941    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  942        self.changes.last().map(|change| change.original.as_slice())
  943    }
  944
  945    pub fn invert_last_group(&mut self) {
  946        if let Some(last) = self.changes.last_mut()
  947            && let Some(current) = last.current.as_mut()
  948        {
  949            mem::swap(&mut last.original, current);
  950        }
  951    }
  952}
  953
  954#[derive(Clone)]
  955struct InlineBlamePopoverState {
  956    scroll_handle: ScrollHandle,
  957    commit_message: Option<ParsedCommitMessage>,
  958    markdown: Entity<Markdown>,
  959}
  960
  961struct InlineBlamePopover {
  962    position: gpui::Point<Pixels>,
  963    hide_task: Option<Task<()>>,
  964    popover_bounds: Option<Bounds<Pixels>>,
  965    popover_state: InlineBlamePopoverState,
  966    keyboard_grace: bool,
  967}
  968
  969enum SelectionDragState {
  970    /// State when no drag related activity is detected.
  971    None,
  972    /// State when the mouse is down on a selection that is about to be dragged.
  973    ReadyToDrag {
  974        selection: Selection<Anchor>,
  975        click_position: gpui::Point<Pixels>,
  976        mouse_down_time: Instant,
  977    },
  978    /// State when the mouse is dragging the selection in the editor.
  979    Dragging {
  980        selection: Selection<Anchor>,
  981        drop_cursor: Selection<Anchor>,
  982        hide_drop_cursor: bool,
  983    },
  984}
  985
  986enum ColumnarSelectionState {
  987    FromMouse {
  988        selection_tail: Anchor,
  989        display_point: Option<DisplayPoint>,
  990    },
  991    FromSelection {
  992        selection_tail: Anchor,
  993    },
  994}
  995
  996/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  997/// a breakpoint on them.
  998#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  999struct PhantomBreakpointIndicator {
 1000    display_row: DisplayRow,
 1001    /// There's a small debounce between hovering over the line and showing the indicator.
 1002    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1003    is_active: bool,
 1004    collides_with_existing_breakpoint: bool,
 1005}
 1006
 1007/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1008///
 1009/// See the [module level documentation](self) for more information.
 1010pub struct Editor {
 1011    focus_handle: FocusHandle,
 1012    last_focused_descendant: Option<WeakFocusHandle>,
 1013    /// The text buffer being edited
 1014    buffer: Entity<MultiBuffer>,
 1015    /// Map of how text in the buffer should be displayed.
 1016    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1017    pub display_map: Entity<DisplayMap>,
 1018    placeholder_display_map: Option<Entity<DisplayMap>>,
 1019    pub selections: SelectionsCollection,
 1020    pub scroll_manager: ScrollManager,
 1021    /// When inline assist editors are linked, they all render cursors because
 1022    /// typing enters text into each of them, even the ones that aren't focused.
 1023    pub(crate) show_cursor_when_unfocused: bool,
 1024    columnar_selection_state: Option<ColumnarSelectionState>,
 1025    add_selections_state: Option<AddSelectionsState>,
 1026    select_next_state: Option<SelectNextState>,
 1027    select_prev_state: Option<SelectNextState>,
 1028    selection_history: SelectionHistory,
 1029    defer_selection_effects: bool,
 1030    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1031    autoclose_regions: Vec<AutocloseRegion>,
 1032    snippet_stack: InvalidationStack<SnippetState>,
 1033    select_syntax_node_history: SelectSyntaxNodeHistory,
 1034    ime_transaction: Option<TransactionId>,
 1035    pub diagnostics_max_severity: DiagnosticSeverity,
 1036    active_diagnostics: ActiveDiagnostic,
 1037    show_inline_diagnostics: bool,
 1038    inline_diagnostics_update: Task<()>,
 1039    inline_diagnostics_enabled: bool,
 1040    diagnostics_enabled: bool,
 1041    word_completions_enabled: bool,
 1042    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1043    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1044    hard_wrap: Option<usize>,
 1045    project: Option<Entity<Project>>,
 1046    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1047    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1048    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1049    blink_manager: Entity<BlinkManager>,
 1050    show_cursor_names: bool,
 1051    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1052    pub show_local_selections: bool,
 1053    mode: EditorMode,
 1054    show_breadcrumbs: bool,
 1055    show_gutter: bool,
 1056    show_scrollbars: ScrollbarAxes,
 1057    minimap_visibility: MinimapVisibility,
 1058    offset_content: bool,
 1059    disable_expand_excerpt_buttons: bool,
 1060    show_line_numbers: Option<bool>,
 1061    use_relative_line_numbers: Option<bool>,
 1062    show_git_diff_gutter: Option<bool>,
 1063    show_code_actions: Option<bool>,
 1064    show_runnables: Option<bool>,
 1065    show_breakpoints: Option<bool>,
 1066    show_wrap_guides: Option<bool>,
 1067    show_indent_guides: Option<bool>,
 1068    highlight_order: usize,
 1069    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1070    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1071    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1072    scrollbar_marker_state: ScrollbarMarkerState,
 1073    active_indent_guides_state: ActiveIndentGuidesState,
 1074    nav_history: Option<ItemNavHistory>,
 1075    context_menu: RefCell<Option<CodeContextMenu>>,
 1076    context_menu_options: Option<ContextMenuOptions>,
 1077    mouse_context_menu: Option<MouseContextMenu>,
 1078    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1079    inline_blame_popover: Option<InlineBlamePopover>,
 1080    inline_blame_popover_show_task: Option<Task<()>>,
 1081    signature_help_state: SignatureHelpState,
 1082    auto_signature_help: Option<bool>,
 1083    find_all_references_task_sources: Vec<Anchor>,
 1084    next_completion_id: CompletionId,
 1085    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1086    code_actions_task: Option<Task<Result<()>>>,
 1087    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1088    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1089    document_highlights_task: Option<Task<()>>,
 1090    linked_editing_range_task: Option<Task<Option<()>>>,
 1091    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1092    pending_rename: Option<RenameState>,
 1093    searchable: bool,
 1094    cursor_shape: CursorShape,
 1095    current_line_highlight: Option<CurrentLineHighlight>,
 1096    collapse_matches: bool,
 1097    autoindent_mode: Option<AutoindentMode>,
 1098    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1099    input_enabled: bool,
 1100    use_modal_editing: bool,
 1101    read_only: bool,
 1102    leader_id: Option<CollaboratorId>,
 1103    remote_id: Option<ViewId>,
 1104    pub hover_state: HoverState,
 1105    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1106    gutter_hovered: bool,
 1107    hovered_link_state: Option<HoveredLinkState>,
 1108    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1109    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1110    active_edit_prediction: Option<EditPredictionState>,
 1111    /// Used to prevent flickering as the user types while the menu is open
 1112    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1113    edit_prediction_settings: EditPredictionSettings,
 1114    edit_predictions_hidden_for_vim_mode: bool,
 1115    show_edit_predictions_override: Option<bool>,
 1116    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1117    edit_prediction_preview: EditPredictionPreview,
 1118    edit_prediction_indent_conflict: bool,
 1119    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1120    inlay_hint_cache: InlayHintCache,
 1121    next_inlay_id: u32,
 1122    next_color_inlay_id: u32,
 1123    _subscriptions: Vec<Subscription>,
 1124    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1125    gutter_dimensions: GutterDimensions,
 1126    style: Option<EditorStyle>,
 1127    text_style_refinement: Option<TextStyleRefinement>,
 1128    next_editor_action_id: EditorActionId,
 1129    editor_actions: Rc<
 1130        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1131    >,
 1132    use_autoclose: bool,
 1133    use_auto_surround: bool,
 1134    auto_replace_emoji_shortcode: bool,
 1135    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1136    show_git_blame_gutter: bool,
 1137    show_git_blame_inline: bool,
 1138    show_git_blame_inline_delay_task: Option<Task<()>>,
 1139    git_blame_inline_enabled: bool,
 1140    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1141    serialize_dirty_buffers: bool,
 1142    show_selection_menu: Option<bool>,
 1143    blame: Option<Entity<GitBlame>>,
 1144    blame_subscription: Option<Subscription>,
 1145    custom_context_menu: Option<
 1146        Box<
 1147            dyn 'static
 1148                + Fn(
 1149                    &mut Self,
 1150                    DisplayPoint,
 1151                    &mut Window,
 1152                    &mut Context<Self>,
 1153                ) -> Option<Entity<ui::ContextMenu>>,
 1154        >,
 1155    >,
 1156    last_bounds: Option<Bounds<Pixels>>,
 1157    last_position_map: Option<Rc<PositionMap>>,
 1158    expect_bounds_change: Option<Bounds<Pixels>>,
 1159    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1160    tasks_update_task: Option<Task<()>>,
 1161    breakpoint_store: Option<Entity<BreakpointStore>>,
 1162    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1163    hovered_diff_hunk_row: Option<DisplayRow>,
 1164    pull_diagnostics_task: Task<()>,
 1165    in_project_search: bool,
 1166    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1167    breadcrumb_header: Option<String>,
 1168    focused_block: Option<FocusedBlock>,
 1169    next_scroll_position: NextScrollCursorCenterTopBottom,
 1170    addons: HashMap<TypeId, Box<dyn Addon>>,
 1171    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1172    load_diff_task: Option<Shared<Task<()>>>,
 1173    /// Whether we are temporarily displaying a diff other than git's
 1174    temporary_diff_override: bool,
 1175    selection_mark_mode: bool,
 1176    toggle_fold_multiple_buffers: Task<()>,
 1177    _scroll_cursor_center_top_bottom_task: Task<()>,
 1178    serialize_selections: Task<()>,
 1179    serialize_folds: Task<()>,
 1180    mouse_cursor_hidden: bool,
 1181    minimap: Option<Entity<Self>>,
 1182    hide_mouse_mode: HideMouseMode,
 1183    pub change_list: ChangeList,
 1184    inline_value_cache: InlineValueCache,
 1185    selection_drag_state: SelectionDragState,
 1186    colors: Option<LspColorData>,
 1187    folding_newlines: Task<()>,
 1188    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1189}
 1190
 1191#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1192enum NextScrollCursorCenterTopBottom {
 1193    #[default]
 1194    Center,
 1195    Top,
 1196    Bottom,
 1197}
 1198
 1199impl NextScrollCursorCenterTopBottom {
 1200    fn next(&self) -> Self {
 1201        match self {
 1202            Self::Center => Self::Top,
 1203            Self::Top => Self::Bottom,
 1204            Self::Bottom => Self::Center,
 1205        }
 1206    }
 1207}
 1208
 1209#[derive(Clone)]
 1210pub struct EditorSnapshot {
 1211    pub mode: EditorMode,
 1212    show_gutter: bool,
 1213    show_line_numbers: Option<bool>,
 1214    show_git_diff_gutter: Option<bool>,
 1215    show_code_actions: Option<bool>,
 1216    show_runnables: Option<bool>,
 1217    show_breakpoints: Option<bool>,
 1218    git_blame_gutter_max_author_length: Option<usize>,
 1219    pub display_snapshot: DisplaySnapshot,
 1220    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1221    is_focused: bool,
 1222    scroll_anchor: ScrollAnchor,
 1223    ongoing_scroll: OngoingScroll,
 1224    current_line_highlight: CurrentLineHighlight,
 1225    gutter_hovered: bool,
 1226}
 1227
 1228#[derive(Default, Debug, Clone, Copy)]
 1229pub struct GutterDimensions {
 1230    pub left_padding: Pixels,
 1231    pub right_padding: Pixels,
 1232    pub width: Pixels,
 1233    pub margin: Pixels,
 1234    pub git_blame_entries_width: Option<Pixels>,
 1235}
 1236
 1237impl GutterDimensions {
 1238    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1239        Self {
 1240            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1241            ..Default::default()
 1242        }
 1243    }
 1244
 1245    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1246        -cx.text_system().descent(font_id, font_size)
 1247    }
 1248    /// The full width of the space taken up by the gutter.
 1249    pub fn full_width(&self) -> Pixels {
 1250        self.margin + self.width
 1251    }
 1252
 1253    /// The width of the space reserved for the fold indicators,
 1254    /// use alongside 'justify_end' and `gutter_width` to
 1255    /// right align content with the line numbers
 1256    pub fn fold_area_width(&self) -> Pixels {
 1257        self.margin + self.right_padding
 1258    }
 1259}
 1260
 1261struct CharacterDimensions {
 1262    em_width: Pixels,
 1263    em_advance: Pixels,
 1264    line_height: Pixels,
 1265}
 1266
 1267#[derive(Debug)]
 1268pub struct RemoteSelection {
 1269    pub replica_id: ReplicaId,
 1270    pub selection: Selection<Anchor>,
 1271    pub cursor_shape: CursorShape,
 1272    pub collaborator_id: CollaboratorId,
 1273    pub line_mode: bool,
 1274    pub user_name: Option<SharedString>,
 1275    pub color: PlayerColor,
 1276}
 1277
 1278#[derive(Clone, Debug)]
 1279struct SelectionHistoryEntry {
 1280    selections: Arc<[Selection<Anchor>]>,
 1281    select_next_state: Option<SelectNextState>,
 1282    select_prev_state: Option<SelectNextState>,
 1283    add_selections_state: Option<AddSelectionsState>,
 1284}
 1285
 1286#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1287enum SelectionHistoryMode {
 1288    Normal,
 1289    Undoing,
 1290    Redoing,
 1291    Skipping,
 1292}
 1293
 1294#[derive(Clone, PartialEq, Eq, Hash)]
 1295struct HoveredCursor {
 1296    replica_id: u16,
 1297    selection_id: usize,
 1298}
 1299
 1300impl Default for SelectionHistoryMode {
 1301    fn default() -> Self {
 1302        Self::Normal
 1303    }
 1304}
 1305
 1306#[derive(Debug)]
 1307/// SelectionEffects controls the side-effects of updating the selection.
 1308///
 1309/// The default behaviour does "what you mostly want":
 1310/// - it pushes to the nav history if the cursor moved by >10 lines
 1311/// - it re-triggers completion requests
 1312/// - it scrolls to fit
 1313///
 1314/// You might want to modify these behaviours. For example when doing a "jump"
 1315/// like go to definition, we always want to add to nav history; but when scrolling
 1316/// in vim mode we never do.
 1317///
 1318/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1319/// move.
 1320#[derive(Clone)]
 1321pub struct SelectionEffects {
 1322    nav_history: Option<bool>,
 1323    completions: bool,
 1324    scroll: Option<Autoscroll>,
 1325}
 1326
 1327impl Default for SelectionEffects {
 1328    fn default() -> Self {
 1329        Self {
 1330            nav_history: None,
 1331            completions: true,
 1332            scroll: Some(Autoscroll::fit()),
 1333        }
 1334    }
 1335}
 1336impl SelectionEffects {
 1337    pub fn scroll(scroll: Autoscroll) -> Self {
 1338        Self {
 1339            scroll: Some(scroll),
 1340            ..Default::default()
 1341        }
 1342    }
 1343
 1344    pub fn no_scroll() -> Self {
 1345        Self {
 1346            scroll: None,
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn completions(self, completions: bool) -> Self {
 1352        Self {
 1353            completions,
 1354            ..self
 1355        }
 1356    }
 1357
 1358    pub fn nav_history(self, nav_history: bool) -> Self {
 1359        Self {
 1360            nav_history: Some(nav_history),
 1361            ..self
 1362        }
 1363    }
 1364}
 1365
 1366struct DeferredSelectionEffectsState {
 1367    changed: bool,
 1368    effects: SelectionEffects,
 1369    old_cursor_position: Anchor,
 1370    history_entry: SelectionHistoryEntry,
 1371}
 1372
 1373#[derive(Default)]
 1374struct SelectionHistory {
 1375    #[allow(clippy::type_complexity)]
 1376    selections_by_transaction:
 1377        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1378    mode: SelectionHistoryMode,
 1379    undo_stack: VecDeque<SelectionHistoryEntry>,
 1380    redo_stack: VecDeque<SelectionHistoryEntry>,
 1381}
 1382
 1383impl SelectionHistory {
 1384    #[track_caller]
 1385    fn insert_transaction(
 1386        &mut self,
 1387        transaction_id: TransactionId,
 1388        selections: Arc<[Selection<Anchor>]>,
 1389    ) {
 1390        if selections.is_empty() {
 1391            log::error!(
 1392                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1393                std::panic::Location::caller()
 1394            );
 1395            return;
 1396        }
 1397        self.selections_by_transaction
 1398            .insert(transaction_id, (selections, None));
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction(
 1403        &self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get(&transaction_id)
 1407    }
 1408
 1409    #[allow(clippy::type_complexity)]
 1410    fn transaction_mut(
 1411        &mut self,
 1412        transaction_id: TransactionId,
 1413    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1414        self.selections_by_transaction.get_mut(&transaction_id)
 1415    }
 1416
 1417    fn push(&mut self, entry: SelectionHistoryEntry) {
 1418        if !entry.selections.is_empty() {
 1419            match self.mode {
 1420                SelectionHistoryMode::Normal => {
 1421                    self.push_undo(entry);
 1422                    self.redo_stack.clear();
 1423                }
 1424                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1425                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1426                SelectionHistoryMode::Skipping => {}
 1427            }
 1428        }
 1429    }
 1430
 1431    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1432        if self
 1433            .undo_stack
 1434            .back()
 1435            .is_none_or(|e| e.selections != entry.selections)
 1436        {
 1437            self.undo_stack.push_back(entry);
 1438            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1439                self.undo_stack.pop_front();
 1440            }
 1441        }
 1442    }
 1443
 1444    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1445        if self
 1446            .redo_stack
 1447            .back()
 1448            .is_none_or(|e| e.selections != entry.selections)
 1449        {
 1450            self.redo_stack.push_back(entry);
 1451            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1452                self.redo_stack.pop_front();
 1453            }
 1454        }
 1455    }
 1456}
 1457
 1458#[derive(Clone, Copy)]
 1459pub struct RowHighlightOptions {
 1460    pub autoscroll: bool,
 1461    pub include_gutter: bool,
 1462}
 1463
 1464impl Default for RowHighlightOptions {
 1465    fn default() -> Self {
 1466        Self {
 1467            autoscroll: Default::default(),
 1468            include_gutter: true,
 1469        }
 1470    }
 1471}
 1472
 1473struct RowHighlight {
 1474    index: usize,
 1475    range: Range<Anchor>,
 1476    color: Hsla,
 1477    options: RowHighlightOptions,
 1478    type_id: TypeId,
 1479}
 1480
 1481#[derive(Clone, Debug)]
 1482struct AddSelectionsState {
 1483    groups: Vec<AddSelectionsGroup>,
 1484}
 1485
 1486#[derive(Clone, Debug)]
 1487struct AddSelectionsGroup {
 1488    above: bool,
 1489    stack: Vec<usize>,
 1490}
 1491
 1492#[derive(Clone)]
 1493struct SelectNextState {
 1494    query: AhoCorasick,
 1495    wordwise: bool,
 1496    done: bool,
 1497}
 1498
 1499impl std::fmt::Debug for SelectNextState {
 1500    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1501        f.debug_struct(std::any::type_name::<Self>())
 1502            .field("wordwise", &self.wordwise)
 1503            .field("done", &self.done)
 1504            .finish()
 1505    }
 1506}
 1507
 1508#[derive(Debug)]
 1509struct AutocloseRegion {
 1510    selection_id: usize,
 1511    range: Range<Anchor>,
 1512    pair: BracketPair,
 1513}
 1514
 1515#[derive(Debug)]
 1516struct SnippetState {
 1517    ranges: Vec<Vec<Range<Anchor>>>,
 1518    active_index: usize,
 1519    choices: Vec<Option<Vec<String>>>,
 1520}
 1521
 1522#[doc(hidden)]
 1523pub struct RenameState {
 1524    pub range: Range<Anchor>,
 1525    pub old_name: Arc<str>,
 1526    pub editor: Entity<Editor>,
 1527    block_id: CustomBlockId,
 1528}
 1529
 1530struct InvalidationStack<T>(Vec<T>);
 1531
 1532struct RegisteredEditPredictionProvider {
 1533    provider: Arc<dyn EditPredictionProviderHandle>,
 1534    _subscription: Subscription,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538pub struct ActiveDiagnosticGroup {
 1539    pub active_range: Range<Anchor>,
 1540    pub active_message: String,
 1541    pub group_id: usize,
 1542    pub blocks: HashSet<CustomBlockId>,
 1543}
 1544
 1545#[derive(Debug, PartialEq, Eq)]
 1546
 1547pub(crate) enum ActiveDiagnostic {
 1548    None,
 1549    All,
 1550    Group(ActiveDiagnosticGroup),
 1551}
 1552
 1553#[derive(Serialize, Deserialize, Clone, Debug)]
 1554pub struct ClipboardSelection {
 1555    /// The number of bytes in this selection.
 1556    pub len: usize,
 1557    /// Whether this was a full-line selection.
 1558    pub is_entire_line: bool,
 1559    /// The indentation of the first line when this content was originally copied.
 1560    pub first_line_indent: u32,
 1561}
 1562
 1563// selections, scroll behavior, was newest selection reversed
 1564type SelectSyntaxNodeHistoryState = (
 1565    Box<[Selection<usize>]>,
 1566    SelectSyntaxNodeScrollBehavior,
 1567    bool,
 1568);
 1569
 1570#[derive(Default)]
 1571struct SelectSyntaxNodeHistory {
 1572    stack: Vec<SelectSyntaxNodeHistoryState>,
 1573    // disable temporarily to allow changing selections without losing the stack
 1574    pub disable_clearing: bool,
 1575}
 1576
 1577impl SelectSyntaxNodeHistory {
 1578    pub fn try_clear(&mut self) {
 1579        if !self.disable_clearing {
 1580            self.stack.clear();
 1581        }
 1582    }
 1583
 1584    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1585        self.stack.push(selection);
 1586    }
 1587
 1588    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1589        self.stack.pop()
 1590    }
 1591}
 1592
 1593enum SelectSyntaxNodeScrollBehavior {
 1594    CursorTop,
 1595    FitSelection,
 1596    CursorBottom,
 1597}
 1598
 1599#[derive(Debug)]
 1600pub(crate) struct NavigationData {
 1601    cursor_anchor: Anchor,
 1602    cursor_position: Point,
 1603    scroll_anchor: ScrollAnchor,
 1604    scroll_top_row: u32,
 1605}
 1606
 1607#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1608pub enum GotoDefinitionKind {
 1609    Symbol,
 1610    Declaration,
 1611    Type,
 1612    Implementation,
 1613}
 1614
 1615#[derive(Debug, Clone)]
 1616enum InlayHintRefreshReason {
 1617    ModifiersChanged(bool),
 1618    Toggle(bool),
 1619    SettingsChange(InlayHintSettings),
 1620    NewLinesShown,
 1621    BufferEdited(HashSet<Arc<Language>>),
 1622    RefreshRequested,
 1623    ExcerptsRemoved(Vec<ExcerptId>),
 1624}
 1625
 1626impl InlayHintRefreshReason {
 1627    fn description(&self) -> &'static str {
 1628        match self {
 1629            Self::ModifiersChanged(_) => "modifiers changed",
 1630            Self::Toggle(_) => "toggle",
 1631            Self::SettingsChange(_) => "settings change",
 1632            Self::NewLinesShown => "new lines shown",
 1633            Self::BufferEdited(_) => "buffer edited",
 1634            Self::RefreshRequested => "refresh requested",
 1635            Self::ExcerptsRemoved(_) => "excerpts removed",
 1636        }
 1637    }
 1638}
 1639
 1640pub enum FormatTarget {
 1641    Buffers(HashSet<Entity<Buffer>>),
 1642    Ranges(Vec<Range<MultiBufferPoint>>),
 1643}
 1644
 1645pub(crate) struct FocusedBlock {
 1646    id: BlockId,
 1647    focus_handle: WeakFocusHandle,
 1648}
 1649
 1650#[derive(Clone)]
 1651enum JumpData {
 1652    MultiBufferRow {
 1653        row: MultiBufferRow,
 1654        line_offset_from_top: u32,
 1655    },
 1656    MultiBufferPoint {
 1657        excerpt_id: ExcerptId,
 1658        position: Point,
 1659        anchor: text::Anchor,
 1660        line_offset_from_top: u32,
 1661    },
 1662}
 1663
 1664pub enum MultibufferSelectionMode {
 1665    First,
 1666    All,
 1667}
 1668
 1669#[derive(Clone, Copy, Debug, Default)]
 1670pub struct RewrapOptions {
 1671    pub override_language_settings: bool,
 1672    pub preserve_existing_whitespace: bool,
 1673}
 1674
 1675impl Editor {
 1676    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1677        let buffer = cx.new(|cx| Buffer::local("", cx));
 1678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1679        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1680    }
 1681
 1682    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(EditorMode::full(), buffer, None, window, cx)
 1686    }
 1687
 1688    pub fn auto_height(
 1689        min_lines: usize,
 1690        max_lines: usize,
 1691        window: &mut Window,
 1692        cx: &mut Context<Self>,
 1693    ) -> Self {
 1694        let buffer = cx.new(|cx| Buffer::local("", cx));
 1695        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1696        Self::new(
 1697            EditorMode::AutoHeight {
 1698                min_lines,
 1699                max_lines: Some(max_lines),
 1700            },
 1701            buffer,
 1702            None,
 1703            window,
 1704            cx,
 1705        )
 1706    }
 1707
 1708    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1709    /// The editor grows as tall as needed to fit its content.
 1710    pub fn auto_height_unbounded(
 1711        min_lines: usize,
 1712        window: &mut Window,
 1713        cx: &mut Context<Self>,
 1714    ) -> Self {
 1715        let buffer = cx.new(|cx| Buffer::local("", cx));
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(
 1718            EditorMode::AutoHeight {
 1719                min_lines,
 1720                max_lines: None,
 1721            },
 1722            buffer,
 1723            None,
 1724            window,
 1725            cx,
 1726        )
 1727    }
 1728
 1729    pub fn for_buffer(
 1730        buffer: Entity<Buffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn for_multibuffer(
 1740        buffer: Entity<MultiBuffer>,
 1741        project: Option<Entity<Project>>,
 1742        window: &mut Window,
 1743        cx: &mut Context<Self>,
 1744    ) -> Self {
 1745        Self::new(EditorMode::full(), buffer, project, window, cx)
 1746    }
 1747
 1748    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1749        let mut clone = Self::new(
 1750            self.mode.clone(),
 1751            self.buffer.clone(),
 1752            self.project.clone(),
 1753            window,
 1754            cx,
 1755        );
 1756        self.display_map.update(cx, |display_map, cx| {
 1757            let snapshot = display_map.snapshot(cx);
 1758            clone.display_map.update(cx, |display_map, cx| {
 1759                display_map.set_state(&snapshot, cx);
 1760            });
 1761        });
 1762        clone.folds_did_change(cx);
 1763        clone.selections.clone_state(&self.selections);
 1764        clone.scroll_manager.clone_state(&self.scroll_manager);
 1765        clone.searchable = self.searchable;
 1766        clone.read_only = self.read_only;
 1767        clone
 1768    }
 1769
 1770    pub fn new(
 1771        mode: EditorMode,
 1772        buffer: Entity<MultiBuffer>,
 1773        project: Option<Entity<Project>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        Editor::new_internal(mode, buffer, project, None, window, cx)
 1778    }
 1779
 1780    fn new_internal(
 1781        mode: EditorMode,
 1782        buffer: Entity<MultiBuffer>,
 1783        project: Option<Entity<Project>>,
 1784        display_map: Option<Entity<DisplayMap>>,
 1785        window: &mut Window,
 1786        cx: &mut Context<Self>,
 1787    ) -> Self {
 1788        debug_assert!(
 1789            display_map.is_none() || mode.is_minimap(),
 1790            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1791        );
 1792
 1793        let full_mode = mode.is_full();
 1794        let is_minimap = mode.is_minimap();
 1795        let diagnostics_max_severity = if full_mode {
 1796            EditorSettings::get_global(cx)
 1797                .diagnostics_max_severity
 1798                .unwrap_or(DiagnosticSeverity::Hint)
 1799        } else {
 1800            DiagnosticSeverity::Off
 1801        };
 1802        let style = window.text_style();
 1803        let font_size = style.font_size.to_pixels(window.rem_size());
 1804        let editor = cx.entity().downgrade();
 1805        let fold_placeholder = FoldPlaceholder {
 1806            constrain_width: false,
 1807            render: Arc::new(move |fold_id, fold_range, cx| {
 1808                let editor = editor.clone();
 1809                div()
 1810                    .id(fold_id)
 1811                    .bg(cx.theme().colors().ghost_element_background)
 1812                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1813                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1814                    .rounded_xs()
 1815                    .size_full()
 1816                    .cursor_pointer()
 1817                    .child("")
 1818                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1819                    .on_click(move |_, _window, cx| {
 1820                        editor
 1821                            .update(cx, |editor, cx| {
 1822                                editor.unfold_ranges(
 1823                                    &[fold_range.start..fold_range.end],
 1824                                    true,
 1825                                    false,
 1826                                    cx,
 1827                                );
 1828                                cx.stop_propagation();
 1829                            })
 1830                            .ok();
 1831                    })
 1832                    .into_any()
 1833            }),
 1834            merge_adjacent: true,
 1835            ..FoldPlaceholder::default()
 1836        };
 1837        let display_map = display_map.unwrap_or_else(|| {
 1838            cx.new(|cx| {
 1839                DisplayMap::new(
 1840                    buffer.clone(),
 1841                    style.font(),
 1842                    font_size,
 1843                    None,
 1844                    FILE_HEADER_HEIGHT,
 1845                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1846                    fold_placeholder,
 1847                    diagnostics_max_severity,
 1848                    cx,
 1849                )
 1850            })
 1851        });
 1852
 1853        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1854
 1855        let blink_manager = cx.new(|cx| {
 1856            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1857            if is_minimap {
 1858                blink_manager.disable(cx);
 1859            }
 1860            blink_manager
 1861        });
 1862
 1863        let soft_wrap_mode_override =
 1864            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1865
 1866        let mut project_subscriptions = Vec::new();
 1867        if full_mode && let Some(project) = project.as_ref() {
 1868            project_subscriptions.push(cx.subscribe_in(
 1869                project,
 1870                window,
 1871                |editor, _, event, window, cx| match event {
 1872                    project::Event::RefreshCodeLens => {
 1873                        // we always query lens with actions, without storing them, always refreshing them
 1874                    }
 1875                    project::Event::RefreshInlayHints => {
 1876                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1877                    }
 1878                    project::Event::LanguageServerAdded(..)
 1879                    | project::Event::LanguageServerRemoved(..) => {
 1880                        if editor.tasks_update_task.is_none() {
 1881                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1882                        }
 1883                    }
 1884                    project::Event::SnippetEdit(id, snippet_edits) => {
 1885                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1886                            let focus_handle = editor.focus_handle(cx);
 1887                            if focus_handle.is_focused(window) {
 1888                                let snapshot = buffer.read(cx).snapshot();
 1889                                for (range, snippet) in snippet_edits {
 1890                                    let editor_range =
 1891                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1892                                    editor
 1893                                        .insert_snippet(
 1894                                            &[editor_range],
 1895                                            snippet.clone(),
 1896                                            window,
 1897                                            cx,
 1898                                        )
 1899                                        .ok();
 1900                                }
 1901                            }
 1902                        }
 1903                    }
 1904                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1905                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1906                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1907                        }
 1908                    }
 1909
 1910                    project::Event::EntryRenamed(transaction) => {
 1911                        let Some(workspace) = editor.workspace() else {
 1912                            return;
 1913                        };
 1914                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1915                        else {
 1916                            return;
 1917                        };
 1918                        if active_editor.entity_id() == cx.entity_id() {
 1919                            let edited_buffers_already_open = {
 1920                                let other_editors: Vec<Entity<Editor>> = workspace
 1921                                    .read(cx)
 1922                                    .panes()
 1923                                    .iter()
 1924                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1925                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1926                                    .collect();
 1927
 1928                                transaction.0.keys().all(|buffer| {
 1929                                    other_editors.iter().any(|editor| {
 1930                                        let multi_buffer = editor.read(cx).buffer();
 1931                                        multi_buffer.read(cx).is_singleton()
 1932                                            && multi_buffer.read(cx).as_singleton().map_or(
 1933                                                false,
 1934                                                |singleton| {
 1935                                                    singleton.entity_id() == buffer.entity_id()
 1936                                                },
 1937                                            )
 1938                                    })
 1939                                })
 1940                            };
 1941
 1942                            if !edited_buffers_already_open {
 1943                                let workspace = workspace.downgrade();
 1944                                let transaction = transaction.clone();
 1945                                cx.defer_in(window, move |_, window, cx| {
 1946                                    cx.spawn_in(window, async move |editor, cx| {
 1947                                        Self::open_project_transaction(
 1948                                            &editor,
 1949                                            workspace,
 1950                                            transaction,
 1951                                            "Rename".to_string(),
 1952                                            cx,
 1953                                        )
 1954                                        .await
 1955                                        .ok()
 1956                                    })
 1957                                    .detach();
 1958                                });
 1959                            }
 1960                        }
 1961                    }
 1962
 1963                    _ => {}
 1964                },
 1965            ));
 1966            if let Some(task_inventory) = project
 1967                .read(cx)
 1968                .task_store()
 1969                .read(cx)
 1970                .task_inventory()
 1971                .cloned()
 1972            {
 1973                project_subscriptions.push(cx.observe_in(
 1974                    &task_inventory,
 1975                    window,
 1976                    |editor, _, window, cx| {
 1977                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1978                    },
 1979                ));
 1980            };
 1981
 1982            project_subscriptions.push(cx.subscribe_in(
 1983                &project.read(cx).breakpoint_store(),
 1984                window,
 1985                |editor, _, event, window, cx| match event {
 1986                    BreakpointStoreEvent::ClearDebugLines => {
 1987                        editor.clear_row_highlights::<ActiveDebugLine>();
 1988                        editor.refresh_inline_values(cx);
 1989                    }
 1990                    BreakpointStoreEvent::SetDebugLine => {
 1991                        if editor.go_to_active_debug_line(window, cx) {
 1992                            cx.stop_propagation();
 1993                        }
 1994
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    _ => {}
 1998                },
 1999            ));
 2000            let git_store = project.read(cx).git_store().clone();
 2001            let project = project.clone();
 2002            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2003                if let GitStoreEvent::RepositoryUpdated(
 2004                    _,
 2005                    RepositoryEvent::Updated {
 2006                        new_instance: true, ..
 2007                    },
 2008                    _,
 2009                ) = event
 2010                {
 2011                    this.load_diff_task = Some(
 2012                        update_uncommitted_diff_for_buffer(
 2013                            cx.entity(),
 2014                            &project,
 2015                            this.buffer.read(cx).all_buffers(),
 2016                            this.buffer.clone(),
 2017                            cx,
 2018                        )
 2019                        .shared(),
 2020                    );
 2021                }
 2022            }));
 2023        }
 2024
 2025        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2026
 2027        let inlay_hint_settings =
 2028            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2029        let focus_handle = cx.focus_handle();
 2030        if !is_minimap {
 2031            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2032                .detach();
 2033            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2034                .detach();
 2035            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2036                .detach();
 2037            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2038                .detach();
 2039            cx.observe_pending_input(window, Self::observe_pending_input)
 2040                .detach();
 2041        }
 2042
 2043        let show_indent_guides =
 2044            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2045                Some(false)
 2046            } else {
 2047                None
 2048            };
 2049
 2050        let breakpoint_store = match (&mode, project.as_ref()) {
 2051            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2052            _ => None,
 2053        };
 2054
 2055        let mut code_action_providers = Vec::new();
 2056        let mut load_uncommitted_diff = None;
 2057        if let Some(project) = project.clone() {
 2058            load_uncommitted_diff = Some(
 2059                update_uncommitted_diff_for_buffer(
 2060                    cx.entity(),
 2061                    &project,
 2062                    buffer.read(cx).all_buffers(),
 2063                    buffer.clone(),
 2064                    cx,
 2065                )
 2066                .shared(),
 2067            );
 2068            code_action_providers.push(Rc::new(project) as Rc<_>);
 2069        }
 2070
 2071        let mut editor = Self {
 2072            focus_handle,
 2073            show_cursor_when_unfocused: false,
 2074            last_focused_descendant: None,
 2075            buffer: buffer.clone(),
 2076            display_map: display_map.clone(),
 2077            placeholder_display_map: None,
 2078            selections,
 2079            scroll_manager: ScrollManager::new(cx),
 2080            columnar_selection_state: None,
 2081            add_selections_state: None,
 2082            select_next_state: None,
 2083            select_prev_state: None,
 2084            selection_history: SelectionHistory::default(),
 2085            defer_selection_effects: false,
 2086            deferred_selection_effects_state: None,
 2087            autoclose_regions: Vec::new(),
 2088            snippet_stack: InvalidationStack::default(),
 2089            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2090            ime_transaction: None,
 2091            active_diagnostics: ActiveDiagnostic::None,
 2092            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2093            inline_diagnostics_update: Task::ready(()),
 2094            inline_diagnostics: Vec::new(),
 2095            soft_wrap_mode_override,
 2096            diagnostics_max_severity,
 2097            hard_wrap: None,
 2098            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2099            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2100            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2101            project,
 2102            blink_manager: blink_manager.clone(),
 2103            show_local_selections: true,
 2104            show_scrollbars: ScrollbarAxes {
 2105                horizontal: full_mode,
 2106                vertical: full_mode,
 2107            },
 2108            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2109            offset_content: !matches!(mode, EditorMode::SingleLine),
 2110            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2111            show_gutter: full_mode,
 2112            show_line_numbers: (!full_mode).then_some(false),
 2113            use_relative_line_numbers: None,
 2114            disable_expand_excerpt_buttons: !full_mode,
 2115            show_git_diff_gutter: None,
 2116            show_code_actions: None,
 2117            show_runnables: None,
 2118            show_breakpoints: None,
 2119            show_wrap_guides: None,
 2120            show_indent_guides,
 2121            highlight_order: 0,
 2122            highlighted_rows: HashMap::default(),
 2123            background_highlights: HashMap::default(),
 2124            gutter_highlights: HashMap::default(),
 2125            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2126            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2127            nav_history: None,
 2128            context_menu: RefCell::new(None),
 2129            context_menu_options: None,
 2130            mouse_context_menu: None,
 2131            completion_tasks: Vec::new(),
 2132            inline_blame_popover: None,
 2133            inline_blame_popover_show_task: None,
 2134            signature_help_state: SignatureHelpState::default(),
 2135            auto_signature_help: None,
 2136            find_all_references_task_sources: Vec::new(),
 2137            next_completion_id: 0,
 2138            next_inlay_id: 0,
 2139            code_action_providers,
 2140            available_code_actions: None,
 2141            code_actions_task: None,
 2142            quick_selection_highlight_task: None,
 2143            debounced_selection_highlight_task: None,
 2144            document_highlights_task: None,
 2145            linked_editing_range_task: None,
 2146            pending_rename: None,
 2147            searchable: !is_minimap,
 2148            cursor_shape: EditorSettings::get_global(cx)
 2149                .cursor_shape
 2150                .unwrap_or_default(),
 2151            current_line_highlight: None,
 2152            autoindent_mode: Some(AutoindentMode::EachLine),
 2153            collapse_matches: false,
 2154            workspace: None,
 2155            input_enabled: !is_minimap,
 2156            use_modal_editing: full_mode,
 2157            read_only: is_minimap,
 2158            use_autoclose: true,
 2159            use_auto_surround: true,
 2160            auto_replace_emoji_shortcode: false,
 2161            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2162            leader_id: None,
 2163            remote_id: None,
 2164            hover_state: HoverState::default(),
 2165            pending_mouse_down: None,
 2166            hovered_link_state: None,
 2167            edit_prediction_provider: None,
 2168            active_edit_prediction: None,
 2169            stale_edit_prediction_in_menu: None,
 2170            edit_prediction_preview: EditPredictionPreview::Inactive {
 2171                released_too_fast: false,
 2172            },
 2173            inline_diagnostics_enabled: full_mode,
 2174            diagnostics_enabled: full_mode,
 2175            word_completions_enabled: full_mode,
 2176            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2177            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2178            gutter_hovered: false,
 2179            pixel_position_of_newest_cursor: None,
 2180            last_bounds: None,
 2181            last_position_map: None,
 2182            expect_bounds_change: None,
 2183            gutter_dimensions: GutterDimensions::default(),
 2184            style: None,
 2185            show_cursor_names: false,
 2186            hovered_cursors: HashMap::default(),
 2187            next_editor_action_id: EditorActionId::default(),
 2188            editor_actions: Rc::default(),
 2189            edit_predictions_hidden_for_vim_mode: false,
 2190            show_edit_predictions_override: None,
 2191            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2192            edit_prediction_settings: EditPredictionSettings::Disabled,
 2193            edit_prediction_indent_conflict: false,
 2194            edit_prediction_requires_modifier_in_indent_conflict: true,
 2195            custom_context_menu: None,
 2196            show_git_blame_gutter: false,
 2197            show_git_blame_inline: false,
 2198            show_selection_menu: None,
 2199            show_git_blame_inline_delay_task: None,
 2200            git_blame_inline_enabled: full_mode
 2201                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2202            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2203            serialize_dirty_buffers: !is_minimap
 2204                && ProjectSettings::get_global(cx)
 2205                    .session
 2206                    .restore_unsaved_buffers,
 2207            blame: None,
 2208            blame_subscription: None,
 2209            tasks: BTreeMap::default(),
 2210
 2211            breakpoint_store,
 2212            gutter_breakpoint_indicator: (None, None),
 2213            hovered_diff_hunk_row: None,
 2214            _subscriptions: (!is_minimap)
 2215                .then(|| {
 2216                    vec![
 2217                        cx.observe(&buffer, Self::on_buffer_changed),
 2218                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2219                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2220                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2221                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2222                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2223                        cx.observe_window_activation(window, |editor, window, cx| {
 2224                            let active = window.is_window_active();
 2225                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2226                                if active {
 2227                                    blink_manager.enable(cx);
 2228                                } else {
 2229                                    blink_manager.disable(cx);
 2230                                }
 2231                            });
 2232                            if active {
 2233                                editor.show_mouse_cursor(cx);
 2234                            }
 2235                        }),
 2236                    ]
 2237                })
 2238                .unwrap_or_default(),
 2239            tasks_update_task: None,
 2240            pull_diagnostics_task: Task::ready(()),
 2241            colors: None,
 2242            next_color_inlay_id: 0,
 2243            linked_edit_ranges: Default::default(),
 2244            in_project_search: false,
 2245            previous_search_ranges: None,
 2246            breadcrumb_header: None,
 2247            focused_block: None,
 2248            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2249            addons: HashMap::default(),
 2250            registered_buffers: HashMap::default(),
 2251            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2252            selection_mark_mode: false,
 2253            toggle_fold_multiple_buffers: Task::ready(()),
 2254            serialize_selections: Task::ready(()),
 2255            serialize_folds: Task::ready(()),
 2256            text_style_refinement: None,
 2257            load_diff_task: load_uncommitted_diff,
 2258            temporary_diff_override: false,
 2259            mouse_cursor_hidden: false,
 2260            minimap: None,
 2261            hide_mouse_mode: EditorSettings::get_global(cx)
 2262                .hide_mouse
 2263                .unwrap_or_default(),
 2264            change_list: ChangeList::new(),
 2265            mode,
 2266            selection_drag_state: SelectionDragState::None,
 2267            folding_newlines: Task::ready(()),
 2268            lookup_key: None,
 2269        };
 2270
 2271        if is_minimap {
 2272            return editor;
 2273        }
 2274
 2275        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2276            editor
 2277                ._subscriptions
 2278                .push(cx.observe(breakpoints, |_, _, cx| {
 2279                    cx.notify();
 2280                }));
 2281        }
 2282        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2283        editor._subscriptions.extend(project_subscriptions);
 2284
 2285        editor._subscriptions.push(cx.subscribe_in(
 2286            &cx.entity(),
 2287            window,
 2288            |editor, _, e: &EditorEvent, window, cx| match e {
 2289                EditorEvent::ScrollPositionChanged { local, .. } => {
 2290                    if *local {
 2291                        let new_anchor = editor.scroll_manager.anchor();
 2292                        let snapshot = editor.snapshot(window, cx);
 2293                        editor.update_restoration_data(cx, move |data| {
 2294                            data.scroll_position = (
 2295                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2296                                new_anchor.offset,
 2297                            );
 2298                        });
 2299                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2300                        editor.inline_blame_popover.take();
 2301                    }
 2302                }
 2303                EditorEvent::Edited { .. } => {
 2304                    if !vim_enabled(cx) {
 2305                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2306                        let pop_state = editor
 2307                            .change_list
 2308                            .last()
 2309                            .map(|previous| {
 2310                                previous.len() == selections.len()
 2311                                    && previous.iter().enumerate().all(|(ix, p)| {
 2312                                        p.to_display_point(&map).row()
 2313                                            == selections[ix].head().row()
 2314                                    })
 2315                            })
 2316                            .unwrap_or(false);
 2317                        let new_positions = selections
 2318                            .into_iter()
 2319                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2320                            .collect();
 2321                        editor
 2322                            .change_list
 2323                            .push_to_change_list(pop_state, new_positions);
 2324                    }
 2325                }
 2326                _ => (),
 2327            },
 2328        ));
 2329
 2330        if let Some(dap_store) = editor
 2331            .project
 2332            .as_ref()
 2333            .map(|project| project.read(cx).dap_store())
 2334        {
 2335            let weak_editor = cx.weak_entity();
 2336
 2337            editor
 2338                ._subscriptions
 2339                .push(
 2340                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2341                        let session_entity = cx.entity();
 2342                        weak_editor
 2343                            .update(cx, |editor, cx| {
 2344                                editor._subscriptions.push(
 2345                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2346                                );
 2347                            })
 2348                            .ok();
 2349                    }),
 2350                );
 2351
 2352            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2353                editor
 2354                    ._subscriptions
 2355                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2356            }
 2357        }
 2358
 2359        // skip adding the initial selection to selection history
 2360        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2361        editor.end_selection(window, cx);
 2362        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2363
 2364        editor.scroll_manager.show_scrollbars(window, cx);
 2365        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2366
 2367        if full_mode {
 2368            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2369            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2370
 2371            if editor.git_blame_inline_enabled {
 2372                editor.start_git_blame_inline(false, window, cx);
 2373            }
 2374
 2375            editor.go_to_active_debug_line(window, cx);
 2376
 2377            if let Some(buffer) = buffer.read(cx).as_singleton()
 2378                && let Some(project) = editor.project()
 2379            {
 2380                let handle = project.update(cx, |project, cx| {
 2381                    project.register_buffer_with_language_servers(&buffer, cx)
 2382                });
 2383                editor
 2384                    .registered_buffers
 2385                    .insert(buffer.read(cx).remote_id(), handle);
 2386            }
 2387
 2388            editor.minimap =
 2389                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2390            editor.colors = Some(LspColorData::new(cx));
 2391            editor.update_lsp_data(false, None, window, cx);
 2392        }
 2393
 2394        if editor.mode.is_full() {
 2395            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2396        }
 2397
 2398        editor
 2399    }
 2400
 2401    pub fn deploy_mouse_context_menu(
 2402        &mut self,
 2403        position: gpui::Point<Pixels>,
 2404        context_menu: Entity<ContextMenu>,
 2405        window: &mut Window,
 2406        cx: &mut Context<Self>,
 2407    ) {
 2408        self.mouse_context_menu = Some(MouseContextMenu::new(
 2409            self,
 2410            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2411            context_menu,
 2412            window,
 2413            cx,
 2414        ));
 2415    }
 2416
 2417    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2418        self.mouse_context_menu
 2419            .as_ref()
 2420            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2421    }
 2422
 2423    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2424        if self
 2425            .selections
 2426            .pending_anchor()
 2427            .is_some_and(|pending_selection| {
 2428                let snapshot = self.buffer().read(cx).snapshot(cx);
 2429                pending_selection.range().includes(range, &snapshot)
 2430            })
 2431        {
 2432            return true;
 2433        }
 2434
 2435        self.selections
 2436            .disjoint_in_range::<usize>(range.clone(), cx)
 2437            .into_iter()
 2438            .any(|selection| {
 2439                // This is needed to cover a corner case, if we just check for an existing
 2440                // selection in the fold range, having a cursor at the start of the fold
 2441                // marks it as selected. Non-empty selections don't cause this.
 2442                let length = selection.end - selection.start;
 2443                length > 0
 2444            })
 2445    }
 2446
 2447    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2448        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2449    }
 2450
 2451    fn key_context_internal(
 2452        &self,
 2453        has_active_edit_prediction: bool,
 2454        window: &Window,
 2455        cx: &App,
 2456    ) -> KeyContext {
 2457        let mut key_context = KeyContext::new_with_defaults();
 2458        key_context.add("Editor");
 2459        let mode = match self.mode {
 2460            EditorMode::SingleLine => "single_line",
 2461            EditorMode::AutoHeight { .. } => "auto_height",
 2462            EditorMode::Minimap { .. } => "minimap",
 2463            EditorMode::Full { .. } => "full",
 2464        };
 2465
 2466        if EditorSettings::jupyter_enabled(cx) {
 2467            key_context.add("jupyter");
 2468        }
 2469
 2470        key_context.set("mode", mode);
 2471        if self.pending_rename.is_some() {
 2472            key_context.add("renaming");
 2473        }
 2474
 2475        match self.context_menu.borrow().as_ref() {
 2476            Some(CodeContextMenu::Completions(menu)) => {
 2477                if menu.visible() {
 2478                    key_context.add("menu");
 2479                    key_context.add("showing_completions");
 2480                }
 2481            }
 2482            Some(CodeContextMenu::CodeActions(menu)) => {
 2483                if menu.visible() {
 2484                    key_context.add("menu");
 2485                    key_context.add("showing_code_actions")
 2486                }
 2487            }
 2488            None => {}
 2489        }
 2490
 2491        if self.signature_help_state.has_multiple_signatures() {
 2492            key_context.add("showing_signature_help");
 2493        }
 2494
 2495        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2496        if !self.focus_handle(cx).contains_focused(window, cx)
 2497            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2498        {
 2499            for addon in self.addons.values() {
 2500                addon.extend_key_context(&mut key_context, cx)
 2501            }
 2502        }
 2503
 2504        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2505            if let Some(extension) = singleton_buffer
 2506                .read(cx)
 2507                .file()
 2508                .and_then(|file| file.path().extension())
 2509            {
 2510                key_context.set("extension", extension.to_string());
 2511            }
 2512        } else {
 2513            key_context.add("multibuffer");
 2514        }
 2515
 2516        if has_active_edit_prediction {
 2517            if self.edit_prediction_in_conflict() {
 2518                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2519            } else {
 2520                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2521                key_context.add("copilot_suggestion");
 2522            }
 2523        }
 2524
 2525        if self.selection_mark_mode {
 2526            key_context.add("selection_mode");
 2527        }
 2528
 2529        key_context
 2530    }
 2531
 2532    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2533        self.last_bounds.as_ref()
 2534    }
 2535
 2536    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2537        if self.mouse_cursor_hidden {
 2538            self.mouse_cursor_hidden = false;
 2539            cx.notify();
 2540        }
 2541    }
 2542
 2543    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2544        let hide_mouse_cursor = match origin {
 2545            HideMouseCursorOrigin::TypingAction => {
 2546                matches!(
 2547                    self.hide_mouse_mode,
 2548                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2549                )
 2550            }
 2551            HideMouseCursorOrigin::MovementAction => {
 2552                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2553            }
 2554        };
 2555        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2556            self.mouse_cursor_hidden = hide_mouse_cursor;
 2557            cx.notify();
 2558        }
 2559    }
 2560
 2561    pub fn edit_prediction_in_conflict(&self) -> bool {
 2562        if !self.show_edit_predictions_in_menu() {
 2563            return false;
 2564        }
 2565
 2566        let showing_completions = self
 2567            .context_menu
 2568            .borrow()
 2569            .as_ref()
 2570            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2571
 2572        showing_completions
 2573            || self.edit_prediction_requires_modifier()
 2574            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2575            // bindings to insert tab characters.
 2576            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2577    }
 2578
 2579    pub fn accept_edit_prediction_keybind(
 2580        &self,
 2581        accept_partial: bool,
 2582        window: &Window,
 2583        cx: &App,
 2584    ) -> AcceptEditPredictionBinding {
 2585        let key_context = self.key_context_internal(true, window, cx);
 2586        let in_conflict = self.edit_prediction_in_conflict();
 2587
 2588        let bindings = if accept_partial {
 2589            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2590        } else {
 2591            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2592        };
 2593
 2594        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2595        // just the first one.
 2596        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2597            !in_conflict
 2598                || binding
 2599                    .keystrokes()
 2600                    .first()
 2601                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2602        }))
 2603    }
 2604
 2605    pub fn new_file(
 2606        workspace: &mut Workspace,
 2607        _: &workspace::NewFile,
 2608        window: &mut Window,
 2609        cx: &mut Context<Workspace>,
 2610    ) {
 2611        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2612            "Failed to create buffer",
 2613            window,
 2614            cx,
 2615            |e, _, _| match e.error_code() {
 2616                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2617                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2618                e.error_tag("required").unwrap_or("the latest version")
 2619            )),
 2620                _ => None,
 2621            },
 2622        );
 2623    }
 2624
 2625    pub fn new_in_workspace(
 2626        workspace: &mut Workspace,
 2627        window: &mut Window,
 2628        cx: &mut Context<Workspace>,
 2629    ) -> Task<Result<Entity<Editor>>> {
 2630        let project = workspace.project().clone();
 2631        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2632
 2633        cx.spawn_in(window, async move |workspace, cx| {
 2634            let buffer = create.await?;
 2635            workspace.update_in(cx, |workspace, window, cx| {
 2636                let editor =
 2637                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2638                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2639                editor
 2640            })
 2641        })
 2642    }
 2643
 2644    fn new_file_vertical(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitVertical,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_horizontal(
 2654        workspace: &mut Workspace,
 2655        _: &workspace::NewFileSplitHorizontal,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2660    }
 2661
 2662    fn new_file_in_direction(
 2663        workspace: &mut Workspace,
 2664        direction: SplitDirection,
 2665        window: &mut Window,
 2666        cx: &mut Context<Workspace>,
 2667    ) {
 2668        let project = workspace.project().clone();
 2669        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2670
 2671        cx.spawn_in(window, async move |workspace, cx| {
 2672            let buffer = create.await?;
 2673            workspace.update_in(cx, move |workspace, window, cx| {
 2674                workspace.split_item(
 2675                    direction,
 2676                    Box::new(
 2677                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2678                    ),
 2679                    window,
 2680                    cx,
 2681                )
 2682            })?;
 2683            anyhow::Ok(())
 2684        })
 2685        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2686            match e.error_code() {
 2687                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2688                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2689                e.error_tag("required").unwrap_or("the latest version")
 2690            )),
 2691                _ => None,
 2692            }
 2693        });
 2694    }
 2695
 2696    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2697        self.leader_id
 2698    }
 2699
 2700    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2701        &self.buffer
 2702    }
 2703
 2704    pub fn project(&self) -> Option<&Entity<Project>> {
 2705        self.project.as_ref()
 2706    }
 2707
 2708    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2709        self.workspace.as_ref()?.0.upgrade()
 2710    }
 2711
 2712    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2713        self.buffer().read(cx).title(cx)
 2714    }
 2715
 2716    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2717        let git_blame_gutter_max_author_length = self
 2718            .render_git_blame_gutter(cx)
 2719            .then(|| {
 2720                if let Some(blame) = self.blame.as_ref() {
 2721                    let max_author_length =
 2722                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2723                    Some(max_author_length)
 2724                } else {
 2725                    None
 2726                }
 2727            })
 2728            .flatten();
 2729
 2730        EditorSnapshot {
 2731            mode: self.mode.clone(),
 2732            show_gutter: self.show_gutter,
 2733            show_line_numbers: self.show_line_numbers,
 2734            show_git_diff_gutter: self.show_git_diff_gutter,
 2735            show_code_actions: self.show_code_actions,
 2736            show_runnables: self.show_runnables,
 2737            show_breakpoints: self.show_breakpoints,
 2738            git_blame_gutter_max_author_length,
 2739            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2740            placeholder_display_snapshot: self
 2741                .placeholder_display_map
 2742                .as_ref()
 2743                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2744            scroll_anchor: self.scroll_manager.anchor(),
 2745            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2746            is_focused: self.focus_handle.is_focused(window),
 2747            current_line_highlight: self
 2748                .current_line_highlight
 2749                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2750            gutter_hovered: self.gutter_hovered,
 2751        }
 2752    }
 2753
 2754    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2755        self.buffer.read(cx).language_at(point, cx)
 2756    }
 2757
 2758    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2759        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2760    }
 2761
 2762    pub fn active_excerpt(
 2763        &self,
 2764        cx: &App,
 2765    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2766        self.buffer
 2767            .read(cx)
 2768            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2769    }
 2770
 2771    pub fn mode(&self) -> &EditorMode {
 2772        &self.mode
 2773    }
 2774
 2775    pub fn set_mode(&mut self, mode: EditorMode) {
 2776        self.mode = mode;
 2777    }
 2778
 2779    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2780        self.collaboration_hub.as_deref()
 2781    }
 2782
 2783    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2784        self.collaboration_hub = Some(hub);
 2785    }
 2786
 2787    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2788        self.in_project_search = in_project_search;
 2789    }
 2790
 2791    pub fn set_custom_context_menu(
 2792        &mut self,
 2793        f: impl 'static
 2794        + Fn(
 2795            &mut Self,
 2796            DisplayPoint,
 2797            &mut Window,
 2798            &mut Context<Self>,
 2799        ) -> Option<Entity<ui::ContextMenu>>,
 2800    ) {
 2801        self.custom_context_menu = Some(Box::new(f))
 2802    }
 2803
 2804    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2805        self.completion_provider = provider;
 2806    }
 2807
 2808    #[cfg(any(test, feature = "test-support"))]
 2809    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2810        self.completion_provider.clone()
 2811    }
 2812
 2813    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2814        self.semantics_provider.clone()
 2815    }
 2816
 2817    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2818        self.semantics_provider = provider;
 2819    }
 2820
 2821    pub fn set_edit_prediction_provider<T>(
 2822        &mut self,
 2823        provider: Option<Entity<T>>,
 2824        window: &mut Window,
 2825        cx: &mut Context<Self>,
 2826    ) where
 2827        T: EditPredictionProvider,
 2828    {
 2829        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2830            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2831                if this.focus_handle.is_focused(window) {
 2832                    this.update_visible_edit_prediction(window, cx);
 2833                }
 2834            }),
 2835            provider: Arc::new(provider),
 2836        });
 2837        self.update_edit_prediction_settings(cx);
 2838        self.refresh_edit_prediction(false, false, window, cx);
 2839    }
 2840
 2841    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2842        self.placeholder_display_map
 2843            .as_ref()
 2844            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2845    }
 2846
 2847    pub fn set_placeholder_text(
 2848        &mut self,
 2849        placeholder_text: &str,
 2850        window: &mut Window,
 2851        cx: &mut Context<Self>,
 2852    ) {
 2853        let multibuffer = cx
 2854            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2855
 2856        let style = window.text_style();
 2857
 2858        self.placeholder_display_map = Some(cx.new(|cx| {
 2859            DisplayMap::new(
 2860                multibuffer,
 2861                style.font(),
 2862                style.font_size.to_pixels(window.rem_size()),
 2863                None,
 2864                FILE_HEADER_HEIGHT,
 2865                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2866                Default::default(),
 2867                DiagnosticSeverity::Off,
 2868                cx,
 2869            )
 2870        }));
 2871        cx.notify();
 2872    }
 2873
 2874    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2875        self.cursor_shape = cursor_shape;
 2876
 2877        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2878        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2879
 2880        cx.notify();
 2881    }
 2882
 2883    pub fn set_current_line_highlight(
 2884        &mut self,
 2885        current_line_highlight: Option<CurrentLineHighlight>,
 2886    ) {
 2887        self.current_line_highlight = current_line_highlight;
 2888    }
 2889
 2890    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2891        self.collapse_matches = collapse_matches;
 2892    }
 2893
 2894    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2895        let buffers = self.buffer.read(cx).all_buffers();
 2896        let Some(project) = self.project.as_ref() else {
 2897            return;
 2898        };
 2899        project.update(cx, |project, cx| {
 2900            for buffer in buffers {
 2901                self.registered_buffers
 2902                    .entry(buffer.read(cx).remote_id())
 2903                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2904            }
 2905        })
 2906    }
 2907
 2908    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2909        if self.collapse_matches {
 2910            return range.start..range.start;
 2911        }
 2912        range.clone()
 2913    }
 2914
 2915    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2916        if self.display_map.read(cx).clip_at_line_ends != clip {
 2917            self.display_map
 2918                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2919        }
 2920    }
 2921
 2922    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2923        self.input_enabled = input_enabled;
 2924    }
 2925
 2926    pub fn set_edit_predictions_hidden_for_vim_mode(
 2927        &mut self,
 2928        hidden: bool,
 2929        window: &mut Window,
 2930        cx: &mut Context<Self>,
 2931    ) {
 2932        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2933            self.edit_predictions_hidden_for_vim_mode = hidden;
 2934            if hidden {
 2935                self.update_visible_edit_prediction(window, cx);
 2936            } else {
 2937                self.refresh_edit_prediction(true, false, window, cx);
 2938            }
 2939        }
 2940    }
 2941
 2942    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2943        self.menu_edit_predictions_policy = value;
 2944    }
 2945
 2946    pub fn set_autoindent(&mut self, autoindent: bool) {
 2947        if autoindent {
 2948            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2949        } else {
 2950            self.autoindent_mode = None;
 2951        }
 2952    }
 2953
 2954    pub fn read_only(&self, cx: &App) -> bool {
 2955        self.read_only || self.buffer.read(cx).read_only()
 2956    }
 2957
 2958    pub fn set_read_only(&mut self, read_only: bool) {
 2959        self.read_only = read_only;
 2960    }
 2961
 2962    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2963        self.use_autoclose = autoclose;
 2964    }
 2965
 2966    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2967        self.use_auto_surround = auto_surround;
 2968    }
 2969
 2970    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2971        self.auto_replace_emoji_shortcode = auto_replace;
 2972    }
 2973
 2974    pub fn toggle_edit_predictions(
 2975        &mut self,
 2976        _: &ToggleEditPrediction,
 2977        window: &mut Window,
 2978        cx: &mut Context<Self>,
 2979    ) {
 2980        if self.show_edit_predictions_override.is_some() {
 2981            self.set_show_edit_predictions(None, window, cx);
 2982        } else {
 2983            let show_edit_predictions = !self.edit_predictions_enabled();
 2984            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2985        }
 2986    }
 2987
 2988    pub fn set_show_edit_predictions(
 2989        &mut self,
 2990        show_edit_predictions: Option<bool>,
 2991        window: &mut Window,
 2992        cx: &mut Context<Self>,
 2993    ) {
 2994        self.show_edit_predictions_override = show_edit_predictions;
 2995        self.update_edit_prediction_settings(cx);
 2996
 2997        if let Some(false) = show_edit_predictions {
 2998            self.discard_edit_prediction(false, cx);
 2999        } else {
 3000            self.refresh_edit_prediction(false, true, window, cx);
 3001        }
 3002    }
 3003
 3004    fn edit_predictions_disabled_in_scope(
 3005        &self,
 3006        buffer: &Entity<Buffer>,
 3007        buffer_position: language::Anchor,
 3008        cx: &App,
 3009    ) -> bool {
 3010        let snapshot = buffer.read(cx).snapshot();
 3011        let settings = snapshot.settings_at(buffer_position, cx);
 3012
 3013        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3014            return false;
 3015        };
 3016
 3017        scope.override_name().is_some_and(|scope_name| {
 3018            settings
 3019                .edit_predictions_disabled_in
 3020                .iter()
 3021                .any(|s| s == scope_name)
 3022        })
 3023    }
 3024
 3025    pub fn set_use_modal_editing(&mut self, to: bool) {
 3026        self.use_modal_editing = to;
 3027    }
 3028
 3029    pub fn use_modal_editing(&self) -> bool {
 3030        self.use_modal_editing
 3031    }
 3032
 3033    fn selections_did_change(
 3034        &mut self,
 3035        local: bool,
 3036        old_cursor_position: &Anchor,
 3037        effects: SelectionEffects,
 3038        window: &mut Window,
 3039        cx: &mut Context<Self>,
 3040    ) {
 3041        window.invalidate_character_coordinates();
 3042
 3043        // Copy selections to primary selection buffer
 3044        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3045        if local {
 3046            let selections = self.selections.all::<usize>(cx);
 3047            let buffer_handle = self.buffer.read(cx).read(cx);
 3048
 3049            let mut text = String::new();
 3050            for (index, selection) in selections.iter().enumerate() {
 3051                let text_for_selection = buffer_handle
 3052                    .text_for_range(selection.start..selection.end)
 3053                    .collect::<String>();
 3054
 3055                text.push_str(&text_for_selection);
 3056                if index != selections.len() - 1 {
 3057                    text.push('\n');
 3058                }
 3059            }
 3060
 3061            if !text.is_empty() {
 3062                cx.write_to_primary(ClipboardItem::new_string(text));
 3063            }
 3064        }
 3065
 3066        let selection_anchors = self.selections.disjoint_anchors_arc();
 3067
 3068        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3069            self.buffer.update(cx, |buffer, cx| {
 3070                buffer.set_active_selections(
 3071                    &selection_anchors,
 3072                    self.selections.line_mode(),
 3073                    self.cursor_shape,
 3074                    cx,
 3075                )
 3076            });
 3077        }
 3078        let display_map = self
 3079            .display_map
 3080            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3081        let buffer = &display_map.buffer_snapshot;
 3082        if self.selections.count() == 1 {
 3083            self.add_selections_state = None;
 3084        }
 3085        self.select_next_state = None;
 3086        self.select_prev_state = None;
 3087        self.select_syntax_node_history.try_clear();
 3088        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3089        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3090        self.take_rename(false, window, cx);
 3091
 3092        let newest_selection = self.selections.newest_anchor();
 3093        let new_cursor_position = newest_selection.head();
 3094        let selection_start = newest_selection.start;
 3095
 3096        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3097            self.push_to_nav_history(
 3098                *old_cursor_position,
 3099                Some(new_cursor_position.to_point(buffer)),
 3100                false,
 3101                effects.nav_history == Some(true),
 3102                cx,
 3103            );
 3104        }
 3105
 3106        if local {
 3107            if let Some(buffer_id) = new_cursor_position.buffer_id
 3108                && !self.registered_buffers.contains_key(&buffer_id)
 3109                && let Some(project) = self.project.as_ref()
 3110            {
 3111                project.update(cx, |project, cx| {
 3112                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3113                        return;
 3114                    };
 3115                    self.registered_buffers.insert(
 3116                        buffer_id,
 3117                        project.register_buffer_with_language_servers(&buffer, cx),
 3118                    );
 3119                })
 3120            }
 3121
 3122            let mut context_menu = self.context_menu.borrow_mut();
 3123            let completion_menu = match context_menu.as_ref() {
 3124                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3125                Some(CodeContextMenu::CodeActions(_)) => {
 3126                    *context_menu = None;
 3127                    None
 3128                }
 3129                None => None,
 3130            };
 3131            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3132            drop(context_menu);
 3133
 3134            if effects.completions
 3135                && let Some(completion_position) = completion_position
 3136            {
 3137                let start_offset = selection_start.to_offset(buffer);
 3138                let position_matches = start_offset == completion_position.to_offset(buffer);
 3139                let continue_showing = if position_matches {
 3140                    if self.snippet_stack.is_empty() {
 3141                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3142                            == Some(CharKind::Word)
 3143                    } else {
 3144                        // Snippet choices can be shown even when the cursor is in whitespace.
 3145                        // Dismissing the menu with actions like backspace is handled by
 3146                        // invalidation regions.
 3147                        true
 3148                    }
 3149                } else {
 3150                    false
 3151                };
 3152
 3153                if continue_showing {
 3154                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3155                } else {
 3156                    self.hide_context_menu(window, cx);
 3157                }
 3158            }
 3159
 3160            hide_hover(self, cx);
 3161
 3162            if old_cursor_position.to_display_point(&display_map).row()
 3163                != new_cursor_position.to_display_point(&display_map).row()
 3164            {
 3165                self.available_code_actions.take();
 3166            }
 3167            self.refresh_code_actions(window, cx);
 3168            self.refresh_document_highlights(cx);
 3169            self.refresh_selected_text_highlights(false, window, cx);
 3170            refresh_matching_bracket_highlights(self, window, cx);
 3171            self.update_visible_edit_prediction(window, cx);
 3172            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3173            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3174            self.inline_blame_popover.take();
 3175            if self.git_blame_inline_enabled {
 3176                self.start_inline_blame_timer(window, cx);
 3177            }
 3178        }
 3179
 3180        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3181        cx.emit(EditorEvent::SelectionsChanged { local });
 3182
 3183        let selections = &self.selections.disjoint_anchors_arc();
 3184        if selections.len() == 1 {
 3185            cx.emit(SearchEvent::ActiveMatchChanged)
 3186        }
 3187        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3188            let inmemory_selections = selections
 3189                .iter()
 3190                .map(|s| {
 3191                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3192                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3193                })
 3194                .collect();
 3195            self.update_restoration_data(cx, |data| {
 3196                data.selections = inmemory_selections;
 3197            });
 3198
 3199            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3200                && let Some(workspace_id) =
 3201                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3202            {
 3203                let snapshot = self.buffer().read(cx).snapshot(cx);
 3204                let selections = selections.clone();
 3205                let background_executor = cx.background_executor().clone();
 3206                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3207                self.serialize_selections = cx.background_spawn(async move {
 3208                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3209                            let db_selections = selections
 3210                                .iter()
 3211                                .map(|selection| {
 3212                                    (
 3213                                        selection.start.to_offset(&snapshot),
 3214                                        selection.end.to_offset(&snapshot),
 3215                                    )
 3216                                })
 3217                                .collect();
 3218
 3219                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3220                                .await
 3221                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3222                                .log_err();
 3223                        });
 3224            }
 3225        }
 3226
 3227        cx.notify();
 3228    }
 3229
 3230    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3231        use text::ToOffset as _;
 3232        use text::ToPoint as _;
 3233
 3234        if self.mode.is_minimap()
 3235            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3236        {
 3237            return;
 3238        }
 3239
 3240        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3241            return;
 3242        };
 3243
 3244        let snapshot = singleton.read(cx).snapshot();
 3245        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3246            let display_snapshot = display_map.snapshot(cx);
 3247
 3248            display_snapshot
 3249                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3250                .map(|fold| {
 3251                    fold.range.start.text_anchor.to_point(&snapshot)
 3252                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3253                })
 3254                .collect()
 3255        });
 3256        self.update_restoration_data(cx, |data| {
 3257            data.folds = inmemory_folds;
 3258        });
 3259
 3260        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3261            return;
 3262        };
 3263        let background_executor = cx.background_executor().clone();
 3264        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3265        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3266            display_map
 3267                .snapshot(cx)
 3268                .folds_in_range(0..snapshot.len())
 3269                .map(|fold| {
 3270                    (
 3271                        fold.range.start.text_anchor.to_offset(&snapshot),
 3272                        fold.range.end.text_anchor.to_offset(&snapshot),
 3273                    )
 3274                })
 3275                .collect()
 3276        });
 3277        self.serialize_folds = cx.background_spawn(async move {
 3278            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3279            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3280                .await
 3281                .with_context(|| {
 3282                    format!(
 3283                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3284                    )
 3285                })
 3286                .log_err();
 3287        });
 3288    }
 3289
 3290    pub fn sync_selections(
 3291        &mut self,
 3292        other: Entity<Editor>,
 3293        cx: &mut Context<Self>,
 3294    ) -> gpui::Subscription {
 3295        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3296        if !other_selections.is_empty() {
 3297            self.selections.change_with(cx, |selections| {
 3298                selections.select_anchors(other_selections);
 3299            });
 3300        }
 3301
 3302        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3303            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3304                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3305                if other_selections.is_empty() {
 3306                    return;
 3307                }
 3308                this.selections.change_with(cx, |selections| {
 3309                    selections.select_anchors(other_selections);
 3310                });
 3311            }
 3312        });
 3313
 3314        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3315            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3316                let these_selections = this.selections.disjoint_anchors().to_vec();
 3317                if these_selections.is_empty() {
 3318                    return;
 3319                }
 3320                other.update(cx, |other_editor, cx| {
 3321                    other_editor.selections.change_with(cx, |selections| {
 3322                        selections.select_anchors(these_selections);
 3323                    })
 3324                });
 3325            }
 3326        });
 3327
 3328        Subscription::join(other_subscription, this_subscription)
 3329    }
 3330
 3331    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3332    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3333    /// effects of selection change occur at the end of the transaction.
 3334    pub fn change_selections<R>(
 3335        &mut self,
 3336        effects: SelectionEffects,
 3337        window: &mut Window,
 3338        cx: &mut Context<Self>,
 3339        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3340    ) -> R {
 3341        if let Some(state) = &mut self.deferred_selection_effects_state {
 3342            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3343            state.effects.completions = effects.completions;
 3344            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3345            let (changed, result) = self.selections.change_with(cx, change);
 3346            state.changed |= changed;
 3347            return result;
 3348        }
 3349        let mut state = DeferredSelectionEffectsState {
 3350            changed: false,
 3351            effects,
 3352            old_cursor_position: self.selections.newest_anchor().head(),
 3353            history_entry: SelectionHistoryEntry {
 3354                selections: self.selections.disjoint_anchors_arc(),
 3355                select_next_state: self.select_next_state.clone(),
 3356                select_prev_state: self.select_prev_state.clone(),
 3357                add_selections_state: self.add_selections_state.clone(),
 3358            },
 3359        };
 3360        let (changed, result) = self.selections.change_with(cx, change);
 3361        state.changed = state.changed || changed;
 3362        if self.defer_selection_effects {
 3363            self.deferred_selection_effects_state = Some(state);
 3364        } else {
 3365            self.apply_selection_effects(state, window, cx);
 3366        }
 3367        result
 3368    }
 3369
 3370    /// Defers the effects of selection change, so that the effects of multiple calls to
 3371    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3372    /// to selection history and the state of popovers based on selection position aren't
 3373    /// erroneously updated.
 3374    pub fn with_selection_effects_deferred<R>(
 3375        &mut self,
 3376        window: &mut Window,
 3377        cx: &mut Context<Self>,
 3378        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3379    ) -> R {
 3380        let already_deferred = self.defer_selection_effects;
 3381        self.defer_selection_effects = true;
 3382        let result = update(self, window, cx);
 3383        if !already_deferred {
 3384            self.defer_selection_effects = false;
 3385            if let Some(state) = self.deferred_selection_effects_state.take() {
 3386                self.apply_selection_effects(state, window, cx);
 3387            }
 3388        }
 3389        result
 3390    }
 3391
 3392    fn apply_selection_effects(
 3393        &mut self,
 3394        state: DeferredSelectionEffectsState,
 3395        window: &mut Window,
 3396        cx: &mut Context<Self>,
 3397    ) {
 3398        if state.changed {
 3399            self.selection_history.push(state.history_entry);
 3400
 3401            if let Some(autoscroll) = state.effects.scroll {
 3402                self.request_autoscroll(autoscroll, cx);
 3403            }
 3404
 3405            let old_cursor_position = &state.old_cursor_position;
 3406
 3407            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3408
 3409            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3410                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3411            }
 3412        }
 3413    }
 3414
 3415    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3416    where
 3417        I: IntoIterator<Item = (Range<S>, T)>,
 3418        S: ToOffset,
 3419        T: Into<Arc<str>>,
 3420    {
 3421        if self.read_only(cx) {
 3422            return;
 3423        }
 3424
 3425        self.buffer
 3426            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3427    }
 3428
 3429    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3430    where
 3431        I: IntoIterator<Item = (Range<S>, T)>,
 3432        S: ToOffset,
 3433        T: Into<Arc<str>>,
 3434    {
 3435        if self.read_only(cx) {
 3436            return;
 3437        }
 3438
 3439        self.buffer.update(cx, |buffer, cx| {
 3440            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3441        });
 3442    }
 3443
 3444    pub fn edit_with_block_indent<I, S, T>(
 3445        &mut self,
 3446        edits: I,
 3447        original_indent_columns: Vec<Option<u32>>,
 3448        cx: &mut Context<Self>,
 3449    ) where
 3450        I: IntoIterator<Item = (Range<S>, T)>,
 3451        S: ToOffset,
 3452        T: Into<Arc<str>>,
 3453    {
 3454        if self.read_only(cx) {
 3455            return;
 3456        }
 3457
 3458        self.buffer.update(cx, |buffer, cx| {
 3459            buffer.edit(
 3460                edits,
 3461                Some(AutoindentMode::Block {
 3462                    original_indent_columns,
 3463                }),
 3464                cx,
 3465            )
 3466        });
 3467    }
 3468
 3469    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3470        self.hide_context_menu(window, cx);
 3471
 3472        match phase {
 3473            SelectPhase::Begin {
 3474                position,
 3475                add,
 3476                click_count,
 3477            } => self.begin_selection(position, add, click_count, window, cx),
 3478            SelectPhase::BeginColumnar {
 3479                position,
 3480                goal_column,
 3481                reset,
 3482                mode,
 3483            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3484            SelectPhase::Extend {
 3485                position,
 3486                click_count,
 3487            } => self.extend_selection(position, click_count, window, cx),
 3488            SelectPhase::Update {
 3489                position,
 3490                goal_column,
 3491                scroll_delta,
 3492            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3493            SelectPhase::End => self.end_selection(window, cx),
 3494        }
 3495    }
 3496
 3497    fn extend_selection(
 3498        &mut self,
 3499        position: DisplayPoint,
 3500        click_count: usize,
 3501        window: &mut Window,
 3502        cx: &mut Context<Self>,
 3503    ) {
 3504        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3505        let tail = self.selections.newest::<usize>(cx).tail();
 3506        self.begin_selection(position, false, click_count, window, cx);
 3507
 3508        let position = position.to_offset(&display_map, Bias::Left);
 3509        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3510
 3511        let mut pending_selection = self
 3512            .selections
 3513            .pending_anchor()
 3514            .cloned()
 3515            .expect("extend_selection not called with pending selection");
 3516        if position >= tail {
 3517            pending_selection.start = tail_anchor;
 3518        } else {
 3519            pending_selection.end = tail_anchor;
 3520            pending_selection.reversed = true;
 3521        }
 3522
 3523        let mut pending_mode = self.selections.pending_mode().unwrap();
 3524        match &mut pending_mode {
 3525            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3526            _ => {}
 3527        }
 3528
 3529        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3530            SelectionEffects::scroll(Autoscroll::fit())
 3531        } else {
 3532            SelectionEffects::no_scroll()
 3533        };
 3534
 3535        self.change_selections(effects, window, cx, |s| {
 3536            s.set_pending(pending_selection.clone(), pending_mode)
 3537        });
 3538    }
 3539
 3540    fn begin_selection(
 3541        &mut self,
 3542        position: DisplayPoint,
 3543        add: bool,
 3544        click_count: usize,
 3545        window: &mut Window,
 3546        cx: &mut Context<Self>,
 3547    ) {
 3548        if !self.focus_handle.is_focused(window) {
 3549            self.last_focused_descendant = None;
 3550            window.focus(&self.focus_handle);
 3551        }
 3552
 3553        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3554        let buffer = &display_map.buffer_snapshot;
 3555        let position = display_map.clip_point(position, Bias::Left);
 3556
 3557        let start;
 3558        let end;
 3559        let mode;
 3560        let mut auto_scroll;
 3561        match click_count {
 3562            1 => {
 3563                start = buffer.anchor_before(position.to_point(&display_map));
 3564                end = start;
 3565                mode = SelectMode::Character;
 3566                auto_scroll = true;
 3567            }
 3568            2 => {
 3569                let position = display_map
 3570                    .clip_point(position, Bias::Left)
 3571                    .to_offset(&display_map, Bias::Left);
 3572                let (range, _) = buffer.surrounding_word(position, None);
 3573                start = buffer.anchor_before(range.start);
 3574                end = buffer.anchor_before(range.end);
 3575                mode = SelectMode::Word(start..end);
 3576                auto_scroll = true;
 3577            }
 3578            3 => {
 3579                let position = display_map
 3580                    .clip_point(position, Bias::Left)
 3581                    .to_point(&display_map);
 3582                let line_start = display_map.prev_line_boundary(position).0;
 3583                let next_line_start = buffer.clip_point(
 3584                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3585                    Bias::Left,
 3586                );
 3587                start = buffer.anchor_before(line_start);
 3588                end = buffer.anchor_before(next_line_start);
 3589                mode = SelectMode::Line(start..end);
 3590                auto_scroll = true;
 3591            }
 3592            _ => {
 3593                start = buffer.anchor_before(0);
 3594                end = buffer.anchor_before(buffer.len());
 3595                mode = SelectMode::All;
 3596                auto_scroll = false;
 3597            }
 3598        }
 3599        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3600
 3601        let point_to_delete: Option<usize> = {
 3602            let selected_points: Vec<Selection<Point>> =
 3603                self.selections.disjoint_in_range(start..end, cx);
 3604
 3605            if !add || click_count > 1 {
 3606                None
 3607            } else if !selected_points.is_empty() {
 3608                Some(selected_points[0].id)
 3609            } else {
 3610                let clicked_point_already_selected =
 3611                    self.selections.disjoint_anchors().iter().find(|selection| {
 3612                        selection.start.to_point(buffer) == start.to_point(buffer)
 3613                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3614                    });
 3615
 3616                clicked_point_already_selected.map(|selection| selection.id)
 3617            }
 3618        };
 3619
 3620        let selections_count = self.selections.count();
 3621        let effects = if auto_scroll {
 3622            SelectionEffects::default()
 3623        } else {
 3624            SelectionEffects::no_scroll()
 3625        };
 3626
 3627        self.change_selections(effects, window, cx, |s| {
 3628            if let Some(point_to_delete) = point_to_delete {
 3629                s.delete(point_to_delete);
 3630
 3631                if selections_count == 1 {
 3632                    s.set_pending_anchor_range(start..end, mode);
 3633                }
 3634            } else {
 3635                if !add {
 3636                    s.clear_disjoint();
 3637                }
 3638
 3639                s.set_pending_anchor_range(start..end, mode);
 3640            }
 3641        });
 3642    }
 3643
 3644    fn begin_columnar_selection(
 3645        &mut self,
 3646        position: DisplayPoint,
 3647        goal_column: u32,
 3648        reset: bool,
 3649        mode: ColumnarMode,
 3650        window: &mut Window,
 3651        cx: &mut Context<Self>,
 3652    ) {
 3653        if !self.focus_handle.is_focused(window) {
 3654            self.last_focused_descendant = None;
 3655            window.focus(&self.focus_handle);
 3656        }
 3657
 3658        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3659
 3660        if reset {
 3661            let pointer_position = display_map
 3662                .buffer_snapshot
 3663                .anchor_before(position.to_point(&display_map));
 3664
 3665            self.change_selections(
 3666                SelectionEffects::scroll(Autoscroll::newest()),
 3667                window,
 3668                cx,
 3669                |s| {
 3670                    s.clear_disjoint();
 3671                    s.set_pending_anchor_range(
 3672                        pointer_position..pointer_position,
 3673                        SelectMode::Character,
 3674                    );
 3675                },
 3676            );
 3677        };
 3678
 3679        let tail = self.selections.newest::<Point>(cx).tail();
 3680        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3681        self.columnar_selection_state = match mode {
 3682            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3683                selection_tail: selection_anchor,
 3684                display_point: if reset {
 3685                    if position.column() != goal_column {
 3686                        Some(DisplayPoint::new(position.row(), goal_column))
 3687                    } else {
 3688                        None
 3689                    }
 3690                } else {
 3691                    None
 3692                },
 3693            }),
 3694            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3695                selection_tail: selection_anchor,
 3696            }),
 3697        };
 3698
 3699        if !reset {
 3700            self.select_columns(position, goal_column, &display_map, window, cx);
 3701        }
 3702    }
 3703
 3704    fn update_selection(
 3705        &mut self,
 3706        position: DisplayPoint,
 3707        goal_column: u32,
 3708        scroll_delta: gpui::Point<f32>,
 3709        window: &mut Window,
 3710        cx: &mut Context<Self>,
 3711    ) {
 3712        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3713
 3714        if self.columnar_selection_state.is_some() {
 3715            self.select_columns(position, goal_column, &display_map, window, cx);
 3716        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3717            let buffer = &display_map.buffer_snapshot;
 3718            let head;
 3719            let tail;
 3720            let mode = self.selections.pending_mode().unwrap();
 3721            match &mode {
 3722                SelectMode::Character => {
 3723                    head = position.to_point(&display_map);
 3724                    tail = pending.tail().to_point(buffer);
 3725                }
 3726                SelectMode::Word(original_range) => {
 3727                    let offset = display_map
 3728                        .clip_point(position, Bias::Left)
 3729                        .to_offset(&display_map, Bias::Left);
 3730                    let original_range = original_range.to_offset(buffer);
 3731
 3732                    let head_offset = if buffer.is_inside_word(offset, None)
 3733                        || original_range.contains(&offset)
 3734                    {
 3735                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3736                        if word_range.start < original_range.start {
 3737                            word_range.start
 3738                        } else {
 3739                            word_range.end
 3740                        }
 3741                    } else {
 3742                        offset
 3743                    };
 3744
 3745                    head = head_offset.to_point(buffer);
 3746                    if head_offset <= original_range.start {
 3747                        tail = original_range.end.to_point(buffer);
 3748                    } else {
 3749                        tail = original_range.start.to_point(buffer);
 3750                    }
 3751                }
 3752                SelectMode::Line(original_range) => {
 3753                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3754
 3755                    let position = display_map
 3756                        .clip_point(position, Bias::Left)
 3757                        .to_point(&display_map);
 3758                    let line_start = display_map.prev_line_boundary(position).0;
 3759                    let next_line_start = buffer.clip_point(
 3760                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3761                        Bias::Left,
 3762                    );
 3763
 3764                    if line_start < original_range.start {
 3765                        head = line_start
 3766                    } else {
 3767                        head = next_line_start
 3768                    }
 3769
 3770                    if head <= original_range.start {
 3771                        tail = original_range.end;
 3772                    } else {
 3773                        tail = original_range.start;
 3774                    }
 3775                }
 3776                SelectMode::All => {
 3777                    return;
 3778                }
 3779            };
 3780
 3781            if head < tail {
 3782                pending.start = buffer.anchor_before(head);
 3783                pending.end = buffer.anchor_before(tail);
 3784                pending.reversed = true;
 3785            } else {
 3786                pending.start = buffer.anchor_before(tail);
 3787                pending.end = buffer.anchor_before(head);
 3788                pending.reversed = false;
 3789            }
 3790
 3791            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3792                s.set_pending(pending.clone(), mode);
 3793            });
 3794        } else {
 3795            log::error!("update_selection dispatched with no pending selection");
 3796            return;
 3797        }
 3798
 3799        self.apply_scroll_delta(scroll_delta, window, cx);
 3800        cx.notify();
 3801    }
 3802
 3803    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3804        self.columnar_selection_state.take();
 3805        if self.selections.pending_anchor().is_some() {
 3806            let selections = self.selections.all::<usize>(cx);
 3807            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3808                s.select(selections);
 3809                s.clear_pending();
 3810            });
 3811        }
 3812    }
 3813
 3814    fn select_columns(
 3815        &mut self,
 3816        head: DisplayPoint,
 3817        goal_column: u32,
 3818        display_map: &DisplaySnapshot,
 3819        window: &mut Window,
 3820        cx: &mut Context<Self>,
 3821    ) {
 3822        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3823            return;
 3824        };
 3825
 3826        let tail = match columnar_state {
 3827            ColumnarSelectionState::FromMouse {
 3828                selection_tail,
 3829                display_point,
 3830            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3831            ColumnarSelectionState::FromSelection { selection_tail } => {
 3832                selection_tail.to_display_point(display_map)
 3833            }
 3834        };
 3835
 3836        let start_row = cmp::min(tail.row(), head.row());
 3837        let end_row = cmp::max(tail.row(), head.row());
 3838        let start_column = cmp::min(tail.column(), goal_column);
 3839        let end_column = cmp::max(tail.column(), goal_column);
 3840        let reversed = start_column < tail.column();
 3841
 3842        let selection_ranges = (start_row.0..=end_row.0)
 3843            .map(DisplayRow)
 3844            .filter_map(|row| {
 3845                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3846                    || start_column <= display_map.line_len(row))
 3847                    && !display_map.is_block_line(row)
 3848                {
 3849                    let start = display_map
 3850                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3851                        .to_point(display_map);
 3852                    let end = display_map
 3853                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3854                        .to_point(display_map);
 3855                    if reversed {
 3856                        Some(end..start)
 3857                    } else {
 3858                        Some(start..end)
 3859                    }
 3860                } else {
 3861                    None
 3862                }
 3863            })
 3864            .collect::<Vec<_>>();
 3865
 3866        let ranges = match columnar_state {
 3867            ColumnarSelectionState::FromMouse { .. } => {
 3868                let mut non_empty_ranges = selection_ranges
 3869                    .iter()
 3870                    .filter(|selection_range| selection_range.start != selection_range.end)
 3871                    .peekable();
 3872                if non_empty_ranges.peek().is_some() {
 3873                    non_empty_ranges.cloned().collect()
 3874                } else {
 3875                    selection_ranges
 3876                }
 3877            }
 3878            _ => selection_ranges,
 3879        };
 3880
 3881        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3882            s.select_ranges(ranges);
 3883        });
 3884        cx.notify();
 3885    }
 3886
 3887    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3888        self.selections
 3889            .all_adjusted(cx)
 3890            .iter()
 3891            .any(|selection| !selection.is_empty())
 3892    }
 3893
 3894    pub fn has_pending_nonempty_selection(&self) -> bool {
 3895        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3896            Some(Selection { start, end, .. }) => start != end,
 3897            None => false,
 3898        };
 3899
 3900        pending_nonempty_selection
 3901            || (self.columnar_selection_state.is_some()
 3902                && self.selections.disjoint_anchors().len() > 1)
 3903    }
 3904
 3905    pub fn has_pending_selection(&self) -> bool {
 3906        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3907    }
 3908
 3909    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3910        self.selection_mark_mode = false;
 3911        self.selection_drag_state = SelectionDragState::None;
 3912
 3913        if self.clear_expanded_diff_hunks(cx) {
 3914            cx.notify();
 3915            return;
 3916        }
 3917        if self.dismiss_menus_and_popups(true, window, cx) {
 3918            return;
 3919        }
 3920
 3921        if self.mode.is_full()
 3922            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3923        {
 3924            return;
 3925        }
 3926
 3927        cx.propagate();
 3928    }
 3929
 3930    pub fn dismiss_menus_and_popups(
 3931        &mut self,
 3932        is_user_requested: bool,
 3933        window: &mut Window,
 3934        cx: &mut Context<Self>,
 3935    ) -> bool {
 3936        if self.take_rename(false, window, cx).is_some() {
 3937            return true;
 3938        }
 3939
 3940        if hide_hover(self, cx) {
 3941            return true;
 3942        }
 3943
 3944        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3945            return true;
 3946        }
 3947
 3948        if self.hide_context_menu(window, cx).is_some() {
 3949            return true;
 3950        }
 3951
 3952        if self.mouse_context_menu.take().is_some() {
 3953            return true;
 3954        }
 3955
 3956        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3957            return true;
 3958        }
 3959
 3960        if self.snippet_stack.pop().is_some() {
 3961            return true;
 3962        }
 3963
 3964        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3965            self.dismiss_diagnostics(cx);
 3966            return true;
 3967        }
 3968
 3969        false
 3970    }
 3971
 3972    fn linked_editing_ranges_for(
 3973        &self,
 3974        selection: Range<text::Anchor>,
 3975        cx: &App,
 3976    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3977        if self.linked_edit_ranges.is_empty() {
 3978            return None;
 3979        }
 3980        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3981            selection.end.buffer_id.and_then(|end_buffer_id| {
 3982                if selection.start.buffer_id != Some(end_buffer_id) {
 3983                    return None;
 3984                }
 3985                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3986                let snapshot = buffer.read(cx).snapshot();
 3987                self.linked_edit_ranges
 3988                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3989                    .map(|ranges| (ranges, snapshot, buffer))
 3990            })?;
 3991        use text::ToOffset as TO;
 3992        // find offset from the start of current range to current cursor position
 3993        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3994
 3995        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3996        let start_difference = start_offset - start_byte_offset;
 3997        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3998        let end_difference = end_offset - start_byte_offset;
 3999        // Current range has associated linked ranges.
 4000        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4001        for range in linked_ranges.iter() {
 4002            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4003            let end_offset = start_offset + end_difference;
 4004            let start_offset = start_offset + start_difference;
 4005            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4006                continue;
 4007            }
 4008            if self.selections.disjoint_anchor_ranges().any(|s| {
 4009                if s.start.buffer_id != selection.start.buffer_id
 4010                    || s.end.buffer_id != selection.end.buffer_id
 4011                {
 4012                    return false;
 4013                }
 4014                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4015                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4016            }) {
 4017                continue;
 4018            }
 4019            let start = buffer_snapshot.anchor_after(start_offset);
 4020            let end = buffer_snapshot.anchor_after(end_offset);
 4021            linked_edits
 4022                .entry(buffer.clone())
 4023                .or_default()
 4024                .push(start..end);
 4025        }
 4026        Some(linked_edits)
 4027    }
 4028
 4029    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4030        let text: Arc<str> = text.into();
 4031
 4032        if self.read_only(cx) {
 4033            return;
 4034        }
 4035
 4036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4037
 4038        let selections = self.selections.all_adjusted(cx);
 4039        let mut bracket_inserted = false;
 4040        let mut edits = Vec::new();
 4041        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4042        let mut new_selections = Vec::with_capacity(selections.len());
 4043        let mut new_autoclose_regions = Vec::new();
 4044        let snapshot = self.buffer.read(cx).read(cx);
 4045        let mut clear_linked_edit_ranges = false;
 4046
 4047        for (selection, autoclose_region) in
 4048            self.selections_with_autoclose_regions(selections, &snapshot)
 4049        {
 4050            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4051                // Determine if the inserted text matches the opening or closing
 4052                // bracket of any of this language's bracket pairs.
 4053                let mut bracket_pair = None;
 4054                let mut is_bracket_pair_start = false;
 4055                let mut is_bracket_pair_end = false;
 4056                if !text.is_empty() {
 4057                    let mut bracket_pair_matching_end = None;
 4058                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4059                    //  and they are removing the character that triggered IME popup.
 4060                    for (pair, enabled) in scope.brackets() {
 4061                        if !pair.close && !pair.surround {
 4062                            continue;
 4063                        }
 4064
 4065                        if enabled && pair.start.ends_with(text.as_ref()) {
 4066                            let prefix_len = pair.start.len() - text.len();
 4067                            let preceding_text_matches_prefix = prefix_len == 0
 4068                                || (selection.start.column >= (prefix_len as u32)
 4069                                    && snapshot.contains_str_at(
 4070                                        Point::new(
 4071                                            selection.start.row,
 4072                                            selection.start.column - (prefix_len as u32),
 4073                                        ),
 4074                                        &pair.start[..prefix_len],
 4075                                    ));
 4076                            if preceding_text_matches_prefix {
 4077                                bracket_pair = Some(pair.clone());
 4078                                is_bracket_pair_start = true;
 4079                                break;
 4080                            }
 4081                        }
 4082                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4083                        {
 4084                            // take first bracket pair matching end, but don't break in case a later bracket
 4085                            // pair matches start
 4086                            bracket_pair_matching_end = Some(pair.clone());
 4087                        }
 4088                    }
 4089                    if let Some(end) = bracket_pair_matching_end
 4090                        && bracket_pair.is_none()
 4091                    {
 4092                        bracket_pair = Some(end);
 4093                        is_bracket_pair_end = true;
 4094                    }
 4095                }
 4096
 4097                if let Some(bracket_pair) = bracket_pair {
 4098                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4099                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4100                    let auto_surround =
 4101                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4102                    if selection.is_empty() {
 4103                        if is_bracket_pair_start {
 4104                            // If the inserted text is a suffix of an opening bracket and the
 4105                            // selection is preceded by the rest of the opening bracket, then
 4106                            // insert the closing bracket.
 4107                            let following_text_allows_autoclose = snapshot
 4108                                .chars_at(selection.start)
 4109                                .next()
 4110                                .is_none_or(|c| scope.should_autoclose_before(c));
 4111
 4112                            let preceding_text_allows_autoclose = selection.start.column == 0
 4113                                || snapshot
 4114                                    .reversed_chars_at(selection.start)
 4115                                    .next()
 4116                                    .is_none_or(|c| {
 4117                                        bracket_pair.start != bracket_pair.end
 4118                                            || !snapshot
 4119                                                .char_classifier_at(selection.start)
 4120                                                .is_word(c)
 4121                                    });
 4122
 4123                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4124                                && bracket_pair.start.len() == 1
 4125                            {
 4126                                let target = bracket_pair.start.chars().next().unwrap();
 4127                                let current_line_count = snapshot
 4128                                    .reversed_chars_at(selection.start)
 4129                                    .take_while(|&c| c != '\n')
 4130                                    .filter(|&c| c == target)
 4131                                    .count();
 4132                                current_line_count % 2 == 1
 4133                            } else {
 4134                                false
 4135                            };
 4136
 4137                            if autoclose
 4138                                && bracket_pair.close
 4139                                && following_text_allows_autoclose
 4140                                && preceding_text_allows_autoclose
 4141                                && !is_closing_quote
 4142                            {
 4143                                let anchor = snapshot.anchor_before(selection.end);
 4144                                new_selections.push((selection.map(|_| anchor), text.len()));
 4145                                new_autoclose_regions.push((
 4146                                    anchor,
 4147                                    text.len(),
 4148                                    selection.id,
 4149                                    bracket_pair.clone(),
 4150                                ));
 4151                                edits.push((
 4152                                    selection.range(),
 4153                                    format!("{}{}", text, bracket_pair.end).into(),
 4154                                ));
 4155                                bracket_inserted = true;
 4156                                continue;
 4157                            }
 4158                        }
 4159
 4160                        if let Some(region) = autoclose_region {
 4161                            // If the selection is followed by an auto-inserted closing bracket,
 4162                            // then don't insert that closing bracket again; just move the selection
 4163                            // past the closing bracket.
 4164                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4165                                && text.as_ref() == region.pair.end.as_str()
 4166                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4167                            if should_skip {
 4168                                let anchor = snapshot.anchor_after(selection.end);
 4169                                new_selections
 4170                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4171                                continue;
 4172                            }
 4173                        }
 4174
 4175                        let always_treat_brackets_as_autoclosed = snapshot
 4176                            .language_settings_at(selection.start, cx)
 4177                            .always_treat_brackets_as_autoclosed;
 4178                        if always_treat_brackets_as_autoclosed
 4179                            && is_bracket_pair_end
 4180                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4181                        {
 4182                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4183                            // and the inserted text is a closing bracket and the selection is followed
 4184                            // by the closing bracket then move the selection past the closing bracket.
 4185                            let anchor = snapshot.anchor_after(selection.end);
 4186                            new_selections.push((selection.map(|_| anchor), text.len()));
 4187                            continue;
 4188                        }
 4189                    }
 4190                    // If an opening bracket is 1 character long and is typed while
 4191                    // text is selected, then surround that text with the bracket pair.
 4192                    else if auto_surround
 4193                        && bracket_pair.surround
 4194                        && is_bracket_pair_start
 4195                        && bracket_pair.start.chars().count() == 1
 4196                    {
 4197                        edits.push((selection.start..selection.start, text.clone()));
 4198                        edits.push((
 4199                            selection.end..selection.end,
 4200                            bracket_pair.end.as_str().into(),
 4201                        ));
 4202                        bracket_inserted = true;
 4203                        new_selections.push((
 4204                            Selection {
 4205                                id: selection.id,
 4206                                start: snapshot.anchor_after(selection.start),
 4207                                end: snapshot.anchor_before(selection.end),
 4208                                reversed: selection.reversed,
 4209                                goal: selection.goal,
 4210                            },
 4211                            0,
 4212                        ));
 4213                        continue;
 4214                    }
 4215                }
 4216            }
 4217
 4218            if self.auto_replace_emoji_shortcode
 4219                && selection.is_empty()
 4220                && text.as_ref().ends_with(':')
 4221                && let Some(possible_emoji_short_code) =
 4222                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4223                && !possible_emoji_short_code.is_empty()
 4224                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4225            {
 4226                let emoji_shortcode_start = Point::new(
 4227                    selection.start.row,
 4228                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4229                );
 4230
 4231                // Remove shortcode from buffer
 4232                edits.push((
 4233                    emoji_shortcode_start..selection.start,
 4234                    "".to_string().into(),
 4235                ));
 4236                new_selections.push((
 4237                    Selection {
 4238                        id: selection.id,
 4239                        start: snapshot.anchor_after(emoji_shortcode_start),
 4240                        end: snapshot.anchor_before(selection.start),
 4241                        reversed: selection.reversed,
 4242                        goal: selection.goal,
 4243                    },
 4244                    0,
 4245                ));
 4246
 4247                // Insert emoji
 4248                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4249                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4250                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4251
 4252                continue;
 4253            }
 4254
 4255            // If not handling any auto-close operation, then just replace the selected
 4256            // text with the given input and move the selection to the end of the
 4257            // newly inserted text.
 4258            let anchor = snapshot.anchor_after(selection.end);
 4259            if !self.linked_edit_ranges.is_empty() {
 4260                let start_anchor = snapshot.anchor_before(selection.start);
 4261
 4262                let is_word_char = text.chars().next().is_none_or(|char| {
 4263                    let classifier = snapshot
 4264                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4265                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4266                    classifier.is_word(char)
 4267                });
 4268
 4269                if is_word_char {
 4270                    if let Some(ranges) = self
 4271                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4272                    {
 4273                        for (buffer, edits) in ranges {
 4274                            linked_edits
 4275                                .entry(buffer.clone())
 4276                                .or_default()
 4277                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4278                        }
 4279                    }
 4280                } else {
 4281                    clear_linked_edit_ranges = true;
 4282                }
 4283            }
 4284
 4285            new_selections.push((selection.map(|_| anchor), 0));
 4286            edits.push((selection.start..selection.end, text.clone()));
 4287        }
 4288
 4289        drop(snapshot);
 4290
 4291        self.transact(window, cx, |this, window, cx| {
 4292            if clear_linked_edit_ranges {
 4293                this.linked_edit_ranges.clear();
 4294            }
 4295            let initial_buffer_versions =
 4296                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4297
 4298            this.buffer.update(cx, |buffer, cx| {
 4299                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4300            });
 4301            for (buffer, edits) in linked_edits {
 4302                buffer.update(cx, |buffer, cx| {
 4303                    let snapshot = buffer.snapshot();
 4304                    let edits = edits
 4305                        .into_iter()
 4306                        .map(|(range, text)| {
 4307                            use text::ToPoint as TP;
 4308                            let end_point = TP::to_point(&range.end, &snapshot);
 4309                            let start_point = TP::to_point(&range.start, &snapshot);
 4310                            (start_point..end_point, text)
 4311                        })
 4312                        .sorted_by_key(|(range, _)| range.start);
 4313                    buffer.edit(edits, None, cx);
 4314                })
 4315            }
 4316            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4317            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4318            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4319            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4320                .zip(new_selection_deltas)
 4321                .map(|(selection, delta)| Selection {
 4322                    id: selection.id,
 4323                    start: selection.start + delta,
 4324                    end: selection.end + delta,
 4325                    reversed: selection.reversed,
 4326                    goal: SelectionGoal::None,
 4327                })
 4328                .collect::<Vec<_>>();
 4329
 4330            let mut i = 0;
 4331            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4332                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4333                let start = map.buffer_snapshot.anchor_before(position);
 4334                let end = map.buffer_snapshot.anchor_after(position);
 4335                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4336                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4337                        Ordering::Less => i += 1,
 4338                        Ordering::Greater => break,
 4339                        Ordering::Equal => {
 4340                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4341                                Ordering::Less => i += 1,
 4342                                Ordering::Equal => break,
 4343                                Ordering::Greater => break,
 4344                            }
 4345                        }
 4346                    }
 4347                }
 4348                this.autoclose_regions.insert(
 4349                    i,
 4350                    AutocloseRegion {
 4351                        selection_id,
 4352                        range: start..end,
 4353                        pair,
 4354                    },
 4355                );
 4356            }
 4357
 4358            let had_active_edit_prediction = this.has_active_edit_prediction();
 4359            this.change_selections(
 4360                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4361                window,
 4362                cx,
 4363                |s| s.select(new_selections),
 4364            );
 4365
 4366            if !bracket_inserted
 4367                && let Some(on_type_format_task) =
 4368                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4369            {
 4370                on_type_format_task.detach_and_log_err(cx);
 4371            }
 4372
 4373            let editor_settings = EditorSettings::get_global(cx);
 4374            if bracket_inserted
 4375                && (editor_settings.auto_signature_help
 4376                    || editor_settings.show_signature_help_after_edits)
 4377            {
 4378                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4379            }
 4380
 4381            let trigger_in_words =
 4382                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4383            if this.hard_wrap.is_some() {
 4384                let latest: Range<Point> = this.selections.newest(cx).range();
 4385                if latest.is_empty()
 4386                    && this
 4387                        .buffer()
 4388                        .read(cx)
 4389                        .snapshot(cx)
 4390                        .line_len(MultiBufferRow(latest.start.row))
 4391                        == latest.start.column
 4392                {
 4393                    this.rewrap_impl(
 4394                        RewrapOptions {
 4395                            override_language_settings: true,
 4396                            preserve_existing_whitespace: true,
 4397                        },
 4398                        cx,
 4399                    )
 4400                }
 4401            }
 4402            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4403            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4404            this.refresh_edit_prediction(true, false, window, cx);
 4405            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4406        });
 4407    }
 4408
 4409    fn find_possible_emoji_shortcode_at_position(
 4410        snapshot: &MultiBufferSnapshot,
 4411        position: Point,
 4412    ) -> Option<String> {
 4413        let mut chars = Vec::new();
 4414        let mut found_colon = false;
 4415        for char in snapshot.reversed_chars_at(position).take(100) {
 4416            // Found a possible emoji shortcode in the middle of the buffer
 4417            if found_colon {
 4418                if char.is_whitespace() {
 4419                    chars.reverse();
 4420                    return Some(chars.iter().collect());
 4421                }
 4422                // If the previous character is not a whitespace, we are in the middle of a word
 4423                // and we only want to complete the shortcode if the word is made up of other emojis
 4424                let mut containing_word = String::new();
 4425                for ch in snapshot
 4426                    .reversed_chars_at(position)
 4427                    .skip(chars.len() + 1)
 4428                    .take(100)
 4429                {
 4430                    if ch.is_whitespace() {
 4431                        break;
 4432                    }
 4433                    containing_word.push(ch);
 4434                }
 4435                let containing_word = containing_word.chars().rev().collect::<String>();
 4436                if util::word_consists_of_emojis(containing_word.as_str()) {
 4437                    chars.reverse();
 4438                    return Some(chars.iter().collect());
 4439                }
 4440            }
 4441
 4442            if char.is_whitespace() || !char.is_ascii() {
 4443                return None;
 4444            }
 4445            if char == ':' {
 4446                found_colon = true;
 4447            } else {
 4448                chars.push(char);
 4449            }
 4450        }
 4451        // Found a possible emoji shortcode at the beginning of the buffer
 4452        chars.reverse();
 4453        Some(chars.iter().collect())
 4454    }
 4455
 4456    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4458        self.transact(window, cx, |this, window, cx| {
 4459            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4460                let selections = this.selections.all::<usize>(cx);
 4461                let multi_buffer = this.buffer.read(cx);
 4462                let buffer = multi_buffer.snapshot(cx);
 4463                selections
 4464                    .iter()
 4465                    .map(|selection| {
 4466                        let start_point = selection.start.to_point(&buffer);
 4467                        let mut existing_indent =
 4468                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4469                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4470                        let start = selection.start;
 4471                        let end = selection.end;
 4472                        let selection_is_empty = start == end;
 4473                        let language_scope = buffer.language_scope_at(start);
 4474                        let (
 4475                            comment_delimiter,
 4476                            doc_delimiter,
 4477                            insert_extra_newline,
 4478                            indent_on_newline,
 4479                            indent_on_extra_newline,
 4480                        ) = if let Some(language) = &language_scope {
 4481                            let mut insert_extra_newline =
 4482                                insert_extra_newline_brackets(&buffer, start..end, language)
 4483                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4484
 4485                            // Comment extension on newline is allowed only for cursor selections
 4486                            let comment_delimiter = maybe!({
 4487                                if !selection_is_empty {
 4488                                    return None;
 4489                                }
 4490
 4491                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4492                                    return None;
 4493                                }
 4494
 4495                                let delimiters = language.line_comment_prefixes();
 4496                                let max_len_of_delimiter =
 4497                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4498                                let (snapshot, range) =
 4499                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4500
 4501                                let num_of_whitespaces = snapshot
 4502                                    .chars_for_range(range.clone())
 4503                                    .take_while(|c| c.is_whitespace())
 4504                                    .count();
 4505                                let comment_candidate = snapshot
 4506                                    .chars_for_range(range.clone())
 4507                                    .skip(num_of_whitespaces)
 4508                                    .take(max_len_of_delimiter)
 4509                                    .collect::<String>();
 4510                                let (delimiter, trimmed_len) = delimiters
 4511                                    .iter()
 4512                                    .filter_map(|delimiter| {
 4513                                        let prefix = delimiter.trim_end();
 4514                                        if comment_candidate.starts_with(prefix) {
 4515                                            Some((delimiter, prefix.len()))
 4516                                        } else {
 4517                                            None
 4518                                        }
 4519                                    })
 4520                                    .max_by_key(|(_, len)| *len)?;
 4521
 4522                                if let Some(BlockCommentConfig {
 4523                                    start: block_start, ..
 4524                                }) = language.block_comment()
 4525                                {
 4526                                    let block_start_trimmed = block_start.trim_end();
 4527                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4528                                        let line_content = snapshot
 4529                                            .chars_for_range(range)
 4530                                            .skip(num_of_whitespaces)
 4531                                            .take(block_start_trimmed.len())
 4532                                            .collect::<String>();
 4533
 4534                                        if line_content.starts_with(block_start_trimmed) {
 4535                                            return None;
 4536                                        }
 4537                                    }
 4538                                }
 4539
 4540                                let cursor_is_placed_after_comment_marker =
 4541                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4542                                if cursor_is_placed_after_comment_marker {
 4543                                    Some(delimiter.clone())
 4544                                } else {
 4545                                    None
 4546                                }
 4547                            });
 4548
 4549                            let mut indent_on_newline = IndentSize::spaces(0);
 4550                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4551
 4552                            let doc_delimiter = maybe!({
 4553                                if !selection_is_empty {
 4554                                    return None;
 4555                                }
 4556
 4557                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4558                                    return None;
 4559                                }
 4560
 4561                                let BlockCommentConfig {
 4562                                    start: start_tag,
 4563                                    end: end_tag,
 4564                                    prefix: delimiter,
 4565                                    tab_size: len,
 4566                                } = language.documentation_comment()?;
 4567                                let is_within_block_comment = buffer
 4568                                    .language_scope_at(start_point)
 4569                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4570                                if !is_within_block_comment {
 4571                                    return None;
 4572                                }
 4573
 4574                                let (snapshot, range) =
 4575                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4576
 4577                                let num_of_whitespaces = snapshot
 4578                                    .chars_for_range(range.clone())
 4579                                    .take_while(|c| c.is_whitespace())
 4580                                    .count();
 4581
 4582                                // 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.
 4583                                let column = start_point.column;
 4584                                let cursor_is_after_start_tag = {
 4585                                    let start_tag_len = start_tag.len();
 4586                                    let start_tag_line = snapshot
 4587                                        .chars_for_range(range.clone())
 4588                                        .skip(num_of_whitespaces)
 4589                                        .take(start_tag_len)
 4590                                        .collect::<String>();
 4591                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4592                                        num_of_whitespaces + start_tag_len <= column as usize
 4593                                    } else {
 4594                                        false
 4595                                    }
 4596                                };
 4597
 4598                                let cursor_is_after_delimiter = {
 4599                                    let delimiter_trim = delimiter.trim_end();
 4600                                    let delimiter_line = snapshot
 4601                                        .chars_for_range(range.clone())
 4602                                        .skip(num_of_whitespaces)
 4603                                        .take(delimiter_trim.len())
 4604                                        .collect::<String>();
 4605                                    if delimiter_line.starts_with(delimiter_trim) {
 4606                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4607                                    } else {
 4608                                        false
 4609                                    }
 4610                                };
 4611
 4612                                let cursor_is_before_end_tag_if_exists = {
 4613                                    let mut char_position = 0u32;
 4614                                    let mut end_tag_offset = None;
 4615
 4616                                    'outer: for chunk in snapshot.text_for_range(range) {
 4617                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4618                                            let chars_before_match =
 4619                                                chunk[..byte_pos].chars().count() as u32;
 4620                                            end_tag_offset =
 4621                                                Some(char_position + chars_before_match);
 4622                                            break 'outer;
 4623                                        }
 4624                                        char_position += chunk.chars().count() as u32;
 4625                                    }
 4626
 4627                                    if let Some(end_tag_offset) = end_tag_offset {
 4628                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4629                                        if cursor_is_after_start_tag {
 4630                                            if cursor_is_before_end_tag {
 4631                                                insert_extra_newline = true;
 4632                                            }
 4633                                            let cursor_is_at_start_of_end_tag =
 4634                                                column == end_tag_offset;
 4635                                            if cursor_is_at_start_of_end_tag {
 4636                                                indent_on_extra_newline.len = *len;
 4637                                            }
 4638                                        }
 4639                                        cursor_is_before_end_tag
 4640                                    } else {
 4641                                        true
 4642                                    }
 4643                                };
 4644
 4645                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4646                                    && cursor_is_before_end_tag_if_exists
 4647                                {
 4648                                    if cursor_is_after_start_tag {
 4649                                        indent_on_newline.len = *len;
 4650                                    }
 4651                                    Some(delimiter.clone())
 4652                                } else {
 4653                                    None
 4654                                }
 4655                            });
 4656
 4657                            (
 4658                                comment_delimiter,
 4659                                doc_delimiter,
 4660                                insert_extra_newline,
 4661                                indent_on_newline,
 4662                                indent_on_extra_newline,
 4663                            )
 4664                        } else {
 4665                            (
 4666                                None,
 4667                                None,
 4668                                false,
 4669                                IndentSize::default(),
 4670                                IndentSize::default(),
 4671                            )
 4672                        };
 4673
 4674                        let prevent_auto_indent = doc_delimiter.is_some();
 4675                        let delimiter = comment_delimiter.or(doc_delimiter);
 4676
 4677                        let capacity_for_delimiter =
 4678                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4679                        let mut new_text = String::with_capacity(
 4680                            1 + capacity_for_delimiter
 4681                                + existing_indent.len as usize
 4682                                + indent_on_newline.len as usize
 4683                                + indent_on_extra_newline.len as usize,
 4684                        );
 4685                        new_text.push('\n');
 4686                        new_text.extend(existing_indent.chars());
 4687                        new_text.extend(indent_on_newline.chars());
 4688
 4689                        if let Some(delimiter) = &delimiter {
 4690                            new_text.push_str(delimiter);
 4691                        }
 4692
 4693                        if insert_extra_newline {
 4694                            new_text.push('\n');
 4695                            new_text.extend(existing_indent.chars());
 4696                            new_text.extend(indent_on_extra_newline.chars());
 4697                        }
 4698
 4699                        let anchor = buffer.anchor_after(end);
 4700                        let new_selection = selection.map(|_| anchor);
 4701                        (
 4702                            ((start..end, new_text), prevent_auto_indent),
 4703                            (insert_extra_newline, new_selection),
 4704                        )
 4705                    })
 4706                    .unzip()
 4707            };
 4708
 4709            let mut auto_indent_edits = Vec::new();
 4710            let mut edits = Vec::new();
 4711            for (edit, prevent_auto_indent) in edits_with_flags {
 4712                if prevent_auto_indent {
 4713                    edits.push(edit);
 4714                } else {
 4715                    auto_indent_edits.push(edit);
 4716                }
 4717            }
 4718            if !edits.is_empty() {
 4719                this.edit(edits, cx);
 4720            }
 4721            if !auto_indent_edits.is_empty() {
 4722                this.edit_with_autoindent(auto_indent_edits, cx);
 4723            }
 4724
 4725            let buffer = this.buffer.read(cx).snapshot(cx);
 4726            let new_selections = selection_info
 4727                .into_iter()
 4728                .map(|(extra_newline_inserted, new_selection)| {
 4729                    let mut cursor = new_selection.end.to_point(&buffer);
 4730                    if extra_newline_inserted {
 4731                        cursor.row -= 1;
 4732                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4733                    }
 4734                    new_selection.map(|_| cursor)
 4735                })
 4736                .collect();
 4737
 4738            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4739            this.refresh_edit_prediction(true, false, window, cx);
 4740        });
 4741    }
 4742
 4743    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4745
 4746        let buffer = self.buffer.read(cx);
 4747        let snapshot = buffer.snapshot(cx);
 4748
 4749        let mut edits = Vec::new();
 4750        let mut rows = Vec::new();
 4751
 4752        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4753            let cursor = selection.head();
 4754            let row = cursor.row;
 4755
 4756            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4757
 4758            let newline = "\n".to_string();
 4759            edits.push((start_of_line..start_of_line, newline));
 4760
 4761            rows.push(row + rows_inserted as u32);
 4762        }
 4763
 4764        self.transact(window, cx, |editor, window, cx| {
 4765            editor.edit(edits, cx);
 4766
 4767            editor.change_selections(Default::default(), window, cx, |s| {
 4768                let mut index = 0;
 4769                s.move_cursors_with(|map, _, _| {
 4770                    let row = rows[index];
 4771                    index += 1;
 4772
 4773                    let point = Point::new(row, 0);
 4774                    let boundary = map.next_line_boundary(point).1;
 4775                    let clipped = map.clip_point(boundary, Bias::Left);
 4776
 4777                    (clipped, SelectionGoal::None)
 4778                });
 4779            });
 4780
 4781            let mut indent_edits = Vec::new();
 4782            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4783            for row in rows {
 4784                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4785                for (row, indent) in indents {
 4786                    if indent.len == 0 {
 4787                        continue;
 4788                    }
 4789
 4790                    let text = match indent.kind {
 4791                        IndentKind::Space => " ".repeat(indent.len as usize),
 4792                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4793                    };
 4794                    let point = Point::new(row.0, 0);
 4795                    indent_edits.push((point..point, text));
 4796                }
 4797            }
 4798            editor.edit(indent_edits, cx);
 4799        });
 4800    }
 4801
 4802    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4803        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4804
 4805        let buffer = self.buffer.read(cx);
 4806        let snapshot = buffer.snapshot(cx);
 4807
 4808        let mut edits = Vec::new();
 4809        let mut rows = Vec::new();
 4810        let mut rows_inserted = 0;
 4811
 4812        for selection in self.selections.all_adjusted(cx) {
 4813            let cursor = selection.head();
 4814            let row = cursor.row;
 4815
 4816            let point = Point::new(row + 1, 0);
 4817            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4818
 4819            let newline = "\n".to_string();
 4820            edits.push((start_of_line..start_of_line, newline));
 4821
 4822            rows_inserted += 1;
 4823            rows.push(row + rows_inserted);
 4824        }
 4825
 4826        self.transact(window, cx, |editor, window, cx| {
 4827            editor.edit(edits, cx);
 4828
 4829            editor.change_selections(Default::default(), window, cx, |s| {
 4830                let mut index = 0;
 4831                s.move_cursors_with(|map, _, _| {
 4832                    let row = rows[index];
 4833                    index += 1;
 4834
 4835                    let point = Point::new(row, 0);
 4836                    let boundary = map.next_line_boundary(point).1;
 4837                    let clipped = map.clip_point(boundary, Bias::Left);
 4838
 4839                    (clipped, SelectionGoal::None)
 4840                });
 4841            });
 4842
 4843            let mut indent_edits = Vec::new();
 4844            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4845            for row in rows {
 4846                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4847                for (row, indent) in indents {
 4848                    if indent.len == 0 {
 4849                        continue;
 4850                    }
 4851
 4852                    let text = match indent.kind {
 4853                        IndentKind::Space => " ".repeat(indent.len as usize),
 4854                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4855                    };
 4856                    let point = Point::new(row.0, 0);
 4857                    indent_edits.push((point..point, text));
 4858                }
 4859            }
 4860            editor.edit(indent_edits, cx);
 4861        });
 4862    }
 4863
 4864    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4865        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4866            original_indent_columns: Vec::new(),
 4867        });
 4868        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4869    }
 4870
 4871    fn insert_with_autoindent_mode(
 4872        &mut self,
 4873        text: &str,
 4874        autoindent_mode: Option<AutoindentMode>,
 4875        window: &mut Window,
 4876        cx: &mut Context<Self>,
 4877    ) {
 4878        if self.read_only(cx) {
 4879            return;
 4880        }
 4881
 4882        let text: Arc<str> = text.into();
 4883        self.transact(window, cx, |this, window, cx| {
 4884            let old_selections = this.selections.all_adjusted(cx);
 4885            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4886                let anchors = {
 4887                    let snapshot = buffer.read(cx);
 4888                    old_selections
 4889                        .iter()
 4890                        .map(|s| {
 4891                            let anchor = snapshot.anchor_after(s.head());
 4892                            s.map(|_| anchor)
 4893                        })
 4894                        .collect::<Vec<_>>()
 4895                };
 4896                buffer.edit(
 4897                    old_selections
 4898                        .iter()
 4899                        .map(|s| (s.start..s.end, text.clone())),
 4900                    autoindent_mode,
 4901                    cx,
 4902                );
 4903                anchors
 4904            });
 4905
 4906            this.change_selections(Default::default(), window, cx, |s| {
 4907                s.select_anchors(selection_anchors);
 4908            });
 4909
 4910            cx.notify();
 4911        });
 4912    }
 4913
 4914    fn trigger_completion_on_input(
 4915        &mut self,
 4916        text: &str,
 4917        trigger_in_words: bool,
 4918        window: &mut Window,
 4919        cx: &mut Context<Self>,
 4920    ) {
 4921        let completions_source = self
 4922            .context_menu
 4923            .borrow()
 4924            .as_ref()
 4925            .and_then(|menu| match menu {
 4926                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4927                CodeContextMenu::CodeActions(_) => None,
 4928            });
 4929
 4930        match completions_source {
 4931            Some(CompletionsMenuSource::Words { .. }) => {
 4932                self.open_or_update_completions_menu(
 4933                    Some(CompletionsMenuSource::Words {
 4934                        ignore_threshold: false,
 4935                    }),
 4936                    None,
 4937                    window,
 4938                    cx,
 4939                );
 4940            }
 4941            Some(CompletionsMenuSource::Normal)
 4942            | Some(CompletionsMenuSource::SnippetChoices)
 4943            | None
 4944                if self.is_completion_trigger(
 4945                    text,
 4946                    trigger_in_words,
 4947                    completions_source.is_some(),
 4948                    cx,
 4949                ) =>
 4950            {
 4951                self.show_completions(
 4952                    &ShowCompletions {
 4953                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4954                    },
 4955                    window,
 4956                    cx,
 4957                )
 4958            }
 4959            _ => {
 4960                self.hide_context_menu(window, cx);
 4961            }
 4962        }
 4963    }
 4964
 4965    fn is_completion_trigger(
 4966        &self,
 4967        text: &str,
 4968        trigger_in_words: bool,
 4969        menu_is_open: bool,
 4970        cx: &mut Context<Self>,
 4971    ) -> bool {
 4972        let position = self.selections.newest_anchor().head();
 4973        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4974            return false;
 4975        };
 4976
 4977        if let Some(completion_provider) = &self.completion_provider {
 4978            completion_provider.is_completion_trigger(
 4979                &buffer,
 4980                position.text_anchor,
 4981                text,
 4982                trigger_in_words,
 4983                menu_is_open,
 4984                cx,
 4985            )
 4986        } else {
 4987            false
 4988        }
 4989    }
 4990
 4991    /// If any empty selections is touching the start of its innermost containing autoclose
 4992    /// region, expand it to select the brackets.
 4993    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4994        let selections = self.selections.all::<usize>(cx);
 4995        let buffer = self.buffer.read(cx).read(cx);
 4996        let new_selections = self
 4997            .selections_with_autoclose_regions(selections, &buffer)
 4998            .map(|(mut selection, region)| {
 4999                if !selection.is_empty() {
 5000                    return selection;
 5001                }
 5002
 5003                if let Some(region) = region {
 5004                    let mut range = region.range.to_offset(&buffer);
 5005                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5006                        range.start -= region.pair.start.len();
 5007                        if buffer.contains_str_at(range.start, &region.pair.start)
 5008                            && buffer.contains_str_at(range.end, &region.pair.end)
 5009                        {
 5010                            range.end += region.pair.end.len();
 5011                            selection.start = range.start;
 5012                            selection.end = range.end;
 5013
 5014                            return selection;
 5015                        }
 5016                    }
 5017                }
 5018
 5019                let always_treat_brackets_as_autoclosed = buffer
 5020                    .language_settings_at(selection.start, cx)
 5021                    .always_treat_brackets_as_autoclosed;
 5022
 5023                if !always_treat_brackets_as_autoclosed {
 5024                    return selection;
 5025                }
 5026
 5027                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5028                    for (pair, enabled) in scope.brackets() {
 5029                        if !enabled || !pair.close {
 5030                            continue;
 5031                        }
 5032
 5033                        if buffer.contains_str_at(selection.start, &pair.end) {
 5034                            let pair_start_len = pair.start.len();
 5035                            if buffer.contains_str_at(
 5036                                selection.start.saturating_sub(pair_start_len),
 5037                                &pair.start,
 5038                            ) {
 5039                                selection.start -= pair_start_len;
 5040                                selection.end += pair.end.len();
 5041
 5042                                return selection;
 5043                            }
 5044                        }
 5045                    }
 5046                }
 5047
 5048                selection
 5049            })
 5050            .collect();
 5051
 5052        drop(buffer);
 5053        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5054            selections.select(new_selections)
 5055        });
 5056    }
 5057
 5058    /// Iterate the given selections, and for each one, find the smallest surrounding
 5059    /// autoclose region. This uses the ordering of the selections and the autoclose
 5060    /// regions to avoid repeated comparisons.
 5061    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5062        &'a self,
 5063        selections: impl IntoIterator<Item = Selection<D>>,
 5064        buffer: &'a MultiBufferSnapshot,
 5065    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5066        let mut i = 0;
 5067        let mut regions = self.autoclose_regions.as_slice();
 5068        selections.into_iter().map(move |selection| {
 5069            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5070
 5071            let mut enclosing = None;
 5072            while let Some(pair_state) = regions.get(i) {
 5073                if pair_state.range.end.to_offset(buffer) < range.start {
 5074                    regions = &regions[i + 1..];
 5075                    i = 0;
 5076                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5077                    break;
 5078                } else {
 5079                    if pair_state.selection_id == selection.id {
 5080                        enclosing = Some(pair_state);
 5081                    }
 5082                    i += 1;
 5083                }
 5084            }
 5085
 5086            (selection, enclosing)
 5087        })
 5088    }
 5089
 5090    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5091    fn invalidate_autoclose_regions(
 5092        &mut self,
 5093        mut selections: &[Selection<Anchor>],
 5094        buffer: &MultiBufferSnapshot,
 5095    ) {
 5096        self.autoclose_regions.retain(|state| {
 5097            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5098                return false;
 5099            }
 5100
 5101            let mut i = 0;
 5102            while let Some(selection) = selections.get(i) {
 5103                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5104                    selections = &selections[1..];
 5105                    continue;
 5106                }
 5107                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5108                    break;
 5109                }
 5110                if selection.id == state.selection_id {
 5111                    return true;
 5112                } else {
 5113                    i += 1;
 5114                }
 5115            }
 5116            false
 5117        });
 5118    }
 5119
 5120    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5121        let offset = position.to_offset(buffer);
 5122        let (word_range, kind) =
 5123            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5124        if offset > word_range.start && kind == Some(CharKind::Word) {
 5125            Some(
 5126                buffer
 5127                    .text_for_range(word_range.start..offset)
 5128                    .collect::<String>(),
 5129            )
 5130        } else {
 5131            None
 5132        }
 5133    }
 5134
 5135    pub fn toggle_inline_values(
 5136        &mut self,
 5137        _: &ToggleInlineValues,
 5138        _: &mut Window,
 5139        cx: &mut Context<Self>,
 5140    ) {
 5141        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5142
 5143        self.refresh_inline_values(cx);
 5144    }
 5145
 5146    pub fn toggle_inlay_hints(
 5147        &mut self,
 5148        _: &ToggleInlayHints,
 5149        _: &mut Window,
 5150        cx: &mut Context<Self>,
 5151    ) {
 5152        self.refresh_inlay_hints(
 5153            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5154            cx,
 5155        );
 5156    }
 5157
 5158    pub fn inlay_hints_enabled(&self) -> bool {
 5159        self.inlay_hint_cache.enabled
 5160    }
 5161
 5162    pub fn inline_values_enabled(&self) -> bool {
 5163        self.inline_value_cache.enabled
 5164    }
 5165
 5166    #[cfg(any(test, feature = "test-support"))]
 5167    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5168        self.display_map
 5169            .read(cx)
 5170            .current_inlays()
 5171            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5172            .cloned()
 5173            .collect()
 5174    }
 5175
 5176    #[cfg(any(test, feature = "test-support"))]
 5177    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5178        self.display_map
 5179            .read(cx)
 5180            .current_inlays()
 5181            .cloned()
 5182            .collect()
 5183    }
 5184
 5185    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5186        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5187            return;
 5188        }
 5189
 5190        let reason_description = reason.description();
 5191        let ignore_debounce = matches!(
 5192            reason,
 5193            InlayHintRefreshReason::SettingsChange(_)
 5194                | InlayHintRefreshReason::Toggle(_)
 5195                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5196                | InlayHintRefreshReason::ModifiersChanged(_)
 5197        );
 5198        let (invalidate_cache, required_languages) = match reason {
 5199            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5200                match self.inlay_hint_cache.modifiers_override(enabled) {
 5201                    Some(enabled) => {
 5202                        if enabled {
 5203                            (InvalidationStrategy::RefreshRequested, None)
 5204                        } else {
 5205                            self.splice_inlays(
 5206                                &self
 5207                                    .visible_inlay_hints(cx)
 5208                                    .iter()
 5209                                    .map(|inlay| inlay.id)
 5210                                    .collect::<Vec<InlayId>>(),
 5211                                Vec::new(),
 5212                                cx,
 5213                            );
 5214                            return;
 5215                        }
 5216                    }
 5217                    None => return,
 5218                }
 5219            }
 5220            InlayHintRefreshReason::Toggle(enabled) => {
 5221                if self.inlay_hint_cache.toggle(enabled) {
 5222                    if enabled {
 5223                        (InvalidationStrategy::RefreshRequested, None)
 5224                    } else {
 5225                        self.splice_inlays(
 5226                            &self
 5227                                .visible_inlay_hints(cx)
 5228                                .iter()
 5229                                .map(|inlay| inlay.id)
 5230                                .collect::<Vec<InlayId>>(),
 5231                            Vec::new(),
 5232                            cx,
 5233                        );
 5234                        return;
 5235                    }
 5236                } else {
 5237                    return;
 5238                }
 5239            }
 5240            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5241                match self.inlay_hint_cache.update_settings(
 5242                    &self.buffer,
 5243                    new_settings,
 5244                    self.visible_inlay_hints(cx),
 5245                    cx,
 5246                ) {
 5247                    ControlFlow::Break(Some(InlaySplice {
 5248                        to_remove,
 5249                        to_insert,
 5250                    })) => {
 5251                        self.splice_inlays(&to_remove, to_insert, cx);
 5252                        return;
 5253                    }
 5254                    ControlFlow::Break(None) => return,
 5255                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5256                }
 5257            }
 5258            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5259                if let Some(InlaySplice {
 5260                    to_remove,
 5261                    to_insert,
 5262                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5263                {
 5264                    self.splice_inlays(&to_remove, to_insert, cx);
 5265                }
 5266                self.display_map.update(cx, |display_map, _| {
 5267                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5268                });
 5269                return;
 5270            }
 5271            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5272            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5273                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5274            }
 5275            InlayHintRefreshReason::RefreshRequested => {
 5276                (InvalidationStrategy::RefreshRequested, None)
 5277            }
 5278        };
 5279
 5280        if let Some(InlaySplice {
 5281            to_remove,
 5282            to_insert,
 5283        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5284            reason_description,
 5285            self.visible_excerpts(required_languages.as_ref(), cx),
 5286            invalidate_cache,
 5287            ignore_debounce,
 5288            cx,
 5289        ) {
 5290            self.splice_inlays(&to_remove, to_insert, cx);
 5291        }
 5292    }
 5293
 5294    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5295        self.display_map
 5296            .read(cx)
 5297            .current_inlays()
 5298            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5299            .cloned()
 5300            .collect()
 5301    }
 5302
 5303    pub fn visible_excerpts(
 5304        &self,
 5305        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5306        cx: &mut Context<Editor>,
 5307    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5308        let Some(project) = self.project() else {
 5309            return HashMap::default();
 5310        };
 5311        let project = project.read(cx);
 5312        let multi_buffer = self.buffer().read(cx);
 5313        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5314        let multi_buffer_visible_start = self
 5315            .scroll_manager
 5316            .anchor()
 5317            .anchor
 5318            .to_point(&multi_buffer_snapshot);
 5319        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5320            multi_buffer_visible_start
 5321                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5322            Bias::Left,
 5323        );
 5324        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5325        multi_buffer_snapshot
 5326            .range_to_buffer_ranges(multi_buffer_visible_range)
 5327            .into_iter()
 5328            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5329            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5330                let buffer_file = project::File::from_dyn(buffer.file())?;
 5331                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5332                let worktree_entry = buffer_worktree
 5333                    .read(cx)
 5334                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5335                if worktree_entry.is_ignored {
 5336                    return None;
 5337                }
 5338
 5339                let language = buffer.language()?;
 5340                if let Some(restrict_to_languages) = restrict_to_languages
 5341                    && !restrict_to_languages.contains(language)
 5342                {
 5343                    return None;
 5344                }
 5345                Some((
 5346                    excerpt_id,
 5347                    (
 5348                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5349                        buffer.version().clone(),
 5350                        excerpt_visible_range,
 5351                    ),
 5352                ))
 5353            })
 5354            .collect()
 5355    }
 5356
 5357    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5358        TextLayoutDetails {
 5359            text_system: window.text_system().clone(),
 5360            editor_style: self.style.clone().unwrap(),
 5361            rem_size: window.rem_size(),
 5362            scroll_anchor: self.scroll_manager.anchor(),
 5363            visible_rows: self.visible_line_count(),
 5364            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5365        }
 5366    }
 5367
 5368    pub fn splice_inlays(
 5369        &self,
 5370        to_remove: &[InlayId],
 5371        to_insert: Vec<Inlay>,
 5372        cx: &mut Context<Self>,
 5373    ) {
 5374        self.display_map.update(cx, |display_map, cx| {
 5375            display_map.splice_inlays(to_remove, to_insert, cx)
 5376        });
 5377        cx.notify();
 5378    }
 5379
 5380    fn trigger_on_type_formatting(
 5381        &self,
 5382        input: String,
 5383        window: &mut Window,
 5384        cx: &mut Context<Self>,
 5385    ) -> Option<Task<Result<()>>> {
 5386        if input.len() != 1 {
 5387            return None;
 5388        }
 5389
 5390        let project = self.project()?;
 5391        let position = self.selections.newest_anchor().head();
 5392        let (buffer, buffer_position) = self
 5393            .buffer
 5394            .read(cx)
 5395            .text_anchor_for_position(position, cx)?;
 5396
 5397        let settings = language_settings::language_settings(
 5398            buffer
 5399                .read(cx)
 5400                .language_at(buffer_position)
 5401                .map(|l| l.name()),
 5402            buffer.read(cx).file(),
 5403            cx,
 5404        );
 5405        if !settings.use_on_type_format {
 5406            return None;
 5407        }
 5408
 5409        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5410        // hence we do LSP request & edit on host side only — add formats to host's history.
 5411        let push_to_lsp_host_history = true;
 5412        // If this is not the host, append its history with new edits.
 5413        let push_to_client_history = project.read(cx).is_via_collab();
 5414
 5415        let on_type_formatting = project.update(cx, |project, cx| {
 5416            project.on_type_format(
 5417                buffer.clone(),
 5418                buffer_position,
 5419                input,
 5420                push_to_lsp_host_history,
 5421                cx,
 5422            )
 5423        });
 5424        Some(cx.spawn_in(window, async move |editor, cx| {
 5425            if let Some(transaction) = on_type_formatting.await? {
 5426                if push_to_client_history {
 5427                    buffer
 5428                        .update(cx, |buffer, _| {
 5429                            buffer.push_transaction(transaction, Instant::now());
 5430                            buffer.finalize_last_transaction();
 5431                        })
 5432                        .ok();
 5433                }
 5434                editor.update(cx, |editor, cx| {
 5435                    editor.refresh_document_highlights(cx);
 5436                })?;
 5437            }
 5438            Ok(())
 5439        }))
 5440    }
 5441
 5442    pub fn show_word_completions(
 5443        &mut self,
 5444        _: &ShowWordCompletions,
 5445        window: &mut Window,
 5446        cx: &mut Context<Self>,
 5447    ) {
 5448        self.open_or_update_completions_menu(
 5449            Some(CompletionsMenuSource::Words {
 5450                ignore_threshold: true,
 5451            }),
 5452            None,
 5453            window,
 5454            cx,
 5455        );
 5456    }
 5457
 5458    pub fn show_completions(
 5459        &mut self,
 5460        options: &ShowCompletions,
 5461        window: &mut Window,
 5462        cx: &mut Context<Self>,
 5463    ) {
 5464        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5465    }
 5466
 5467    fn open_or_update_completions_menu(
 5468        &mut self,
 5469        requested_source: Option<CompletionsMenuSource>,
 5470        trigger: Option<&str>,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) {
 5474        if self.pending_rename.is_some() {
 5475            return;
 5476        }
 5477
 5478        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5479
 5480        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5481        // inserted and selected. To handle that case, the start of the selection is used so that
 5482        // the menu starts with all choices.
 5483        let position = self
 5484            .selections
 5485            .newest_anchor()
 5486            .start
 5487            .bias_right(&multibuffer_snapshot);
 5488        if position.diff_base_anchor.is_some() {
 5489            return;
 5490        }
 5491        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5492        let Some(buffer) = buffer_position
 5493            .buffer_id
 5494            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5495        else {
 5496            return;
 5497        };
 5498        let buffer_snapshot = buffer.read(cx).snapshot();
 5499
 5500        let query: Option<Arc<String>> =
 5501            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5502                .map(|query| query.into());
 5503
 5504        drop(multibuffer_snapshot);
 5505
 5506        // Hide the current completions menu when query is empty. Without this, cached
 5507        // completions from before the trigger char may be reused (#32774).
 5508        if query.is_none() {
 5509            let menu_is_open = matches!(
 5510                self.context_menu.borrow().as_ref(),
 5511                Some(CodeContextMenu::Completions(_))
 5512            );
 5513            if menu_is_open {
 5514                self.hide_context_menu(window, cx);
 5515            }
 5516        }
 5517
 5518        let mut ignore_word_threshold = false;
 5519        let provider = match requested_source {
 5520            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5521            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5522                ignore_word_threshold = ignore_threshold;
 5523                None
 5524            }
 5525            Some(CompletionsMenuSource::SnippetChoices) => {
 5526                log::error!("bug: SnippetChoices requested_source is not handled");
 5527                None
 5528            }
 5529        };
 5530
 5531        let sort_completions = provider
 5532            .as_ref()
 5533            .is_some_and(|provider| provider.sort_completions());
 5534
 5535        let filter_completions = provider
 5536            .as_ref()
 5537            .is_none_or(|provider| provider.filter_completions());
 5538
 5539        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5540            if filter_completions {
 5541                menu.filter(query.clone(), provider.clone(), window, cx);
 5542            }
 5543            // When `is_incomplete` is false, no need to re-query completions when the current query
 5544            // is a suffix of the initial query.
 5545            if !menu.is_incomplete {
 5546                // If the new query is a suffix of the old query (typing more characters) and
 5547                // the previous result was complete, the existing completions can be filtered.
 5548                //
 5549                // Note that this is always true for snippet completions.
 5550                let query_matches = match (&menu.initial_query, &query) {
 5551                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5552                    (None, _) => true,
 5553                    _ => false,
 5554                };
 5555                if query_matches {
 5556                    let position_matches = if menu.initial_position == position {
 5557                        true
 5558                    } else {
 5559                        let snapshot = self.buffer.read(cx).read(cx);
 5560                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5561                    };
 5562                    if position_matches {
 5563                        return;
 5564                    }
 5565                }
 5566            }
 5567        };
 5568
 5569        let trigger_kind = match trigger {
 5570            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5571                CompletionTriggerKind::TRIGGER_CHARACTER
 5572            }
 5573            _ => CompletionTriggerKind::INVOKED,
 5574        };
 5575        let completion_context = CompletionContext {
 5576            trigger_character: trigger.and_then(|trigger| {
 5577                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5578                    Some(String::from(trigger))
 5579                } else {
 5580                    None
 5581                }
 5582            }),
 5583            trigger_kind,
 5584        };
 5585
 5586        let Anchor {
 5587            excerpt_id: buffer_excerpt_id,
 5588            text_anchor: buffer_position,
 5589            ..
 5590        } = buffer_position;
 5591
 5592        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5593            buffer_snapshot.surrounding_word(buffer_position, None)
 5594        {
 5595            let word_to_exclude = buffer_snapshot
 5596                .text_for_range(word_range.clone())
 5597                .collect::<String>();
 5598            (
 5599                buffer_snapshot.anchor_before(word_range.start)
 5600                    ..buffer_snapshot.anchor_after(buffer_position),
 5601                Some(word_to_exclude),
 5602            )
 5603        } else {
 5604            (buffer_position..buffer_position, None)
 5605        };
 5606
 5607        let language = buffer_snapshot
 5608            .language_at(buffer_position)
 5609            .map(|language| language.name());
 5610
 5611        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5612            .completions
 5613            .clone();
 5614
 5615        let show_completion_documentation = buffer_snapshot
 5616            .settings_at(buffer_position, cx)
 5617            .show_completion_documentation;
 5618
 5619        // The document can be large, so stay in reasonable bounds when searching for words,
 5620        // otherwise completion pop-up might be slow to appear.
 5621        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5622        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5623        let min_word_search = buffer_snapshot.clip_point(
 5624            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5625            Bias::Left,
 5626        );
 5627        let max_word_search = buffer_snapshot.clip_point(
 5628            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5629            Bias::Right,
 5630        );
 5631        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5632            ..buffer_snapshot.point_to_offset(max_word_search);
 5633
 5634        let skip_digits = query
 5635            .as_ref()
 5636            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5637
 5638        let omit_word_completions = !self.word_completions_enabled
 5639            || (!ignore_word_threshold
 5640                && match &query {
 5641                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5642                    None => completion_settings.words_min_length != 0,
 5643                });
 5644
 5645        let (mut words, provider_responses) = match &provider {
 5646            Some(provider) => {
 5647                let provider_responses = provider.completions(
 5648                    buffer_excerpt_id,
 5649                    &buffer,
 5650                    buffer_position,
 5651                    completion_context,
 5652                    window,
 5653                    cx,
 5654                );
 5655
 5656                let words = match (omit_word_completions, completion_settings.words) {
 5657                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5658                        Task::ready(BTreeMap::default())
 5659                    }
 5660                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5661                        .background_spawn(async move {
 5662                            buffer_snapshot.words_in_range(WordsQuery {
 5663                                fuzzy_contents: None,
 5664                                range: word_search_range,
 5665                                skip_digits,
 5666                            })
 5667                        }),
 5668                };
 5669
 5670                (words, provider_responses)
 5671            }
 5672            None => {
 5673                let words = if omit_word_completions {
 5674                    Task::ready(BTreeMap::default())
 5675                } else {
 5676                    cx.background_spawn(async move {
 5677                        buffer_snapshot.words_in_range(WordsQuery {
 5678                            fuzzy_contents: None,
 5679                            range: word_search_range,
 5680                            skip_digits,
 5681                        })
 5682                    })
 5683                };
 5684                (words, Task::ready(Ok(Vec::new())))
 5685            }
 5686        };
 5687
 5688        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5689
 5690        let id = post_inc(&mut self.next_completion_id);
 5691        let task = cx.spawn_in(window, async move |editor, cx| {
 5692            let Ok(()) = editor.update(cx, |this, _| {
 5693                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5694            }) else {
 5695                return;
 5696            };
 5697
 5698            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5699            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5700            let mut completions = Vec::new();
 5701            let mut is_incomplete = false;
 5702            let mut display_options: Option<CompletionDisplayOptions> = None;
 5703            if let Some(provider_responses) = provider_responses.await.log_err()
 5704                && !provider_responses.is_empty()
 5705            {
 5706                for response in provider_responses {
 5707                    completions.extend(response.completions);
 5708                    is_incomplete = is_incomplete || response.is_incomplete;
 5709                    match display_options.as_mut() {
 5710                        None => {
 5711                            display_options = Some(response.display_options);
 5712                        }
 5713                        Some(options) => options.merge(&response.display_options),
 5714                    }
 5715                }
 5716                if completion_settings.words == WordsCompletionMode::Fallback {
 5717                    words = Task::ready(BTreeMap::default());
 5718                }
 5719            }
 5720            let display_options = display_options.unwrap_or_default();
 5721
 5722            let mut words = words.await;
 5723            if let Some(word_to_exclude) = &word_to_exclude {
 5724                words.remove(word_to_exclude);
 5725            }
 5726            for lsp_completion in &completions {
 5727                words.remove(&lsp_completion.new_text);
 5728            }
 5729            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5730                replace_range: word_replace_range.clone(),
 5731                new_text: word.clone(),
 5732                label: CodeLabel::plain(word, None),
 5733                icon_path: None,
 5734                documentation: None,
 5735                source: CompletionSource::BufferWord {
 5736                    word_range,
 5737                    resolved: false,
 5738                },
 5739                insert_text_mode: Some(InsertTextMode::AS_IS),
 5740                confirm: None,
 5741            }));
 5742
 5743            let menu = if completions.is_empty() {
 5744                None
 5745            } else {
 5746                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5747                    let languages = editor
 5748                        .workspace
 5749                        .as_ref()
 5750                        .and_then(|(workspace, _)| workspace.upgrade())
 5751                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5752                    let menu = CompletionsMenu::new(
 5753                        id,
 5754                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5755                        sort_completions,
 5756                        show_completion_documentation,
 5757                        position,
 5758                        query.clone(),
 5759                        is_incomplete,
 5760                        buffer.clone(),
 5761                        completions.into(),
 5762                        display_options,
 5763                        snippet_sort_order,
 5764                        languages,
 5765                        language,
 5766                        cx,
 5767                    );
 5768
 5769                    let query = if filter_completions { query } else { None };
 5770                    let matches_task = if let Some(query) = query {
 5771                        menu.do_async_filtering(query, cx)
 5772                    } else {
 5773                        Task::ready(menu.unfiltered_matches())
 5774                    };
 5775                    (menu, matches_task)
 5776                }) else {
 5777                    return;
 5778                };
 5779
 5780                let matches = matches_task.await;
 5781
 5782                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5783                    // Newer menu already set, so exit.
 5784                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5785                        editor.context_menu.borrow().as_ref()
 5786                        && prev_menu.id > id
 5787                    {
 5788                        return;
 5789                    };
 5790
 5791                    // Only valid to take prev_menu because it the new menu is immediately set
 5792                    // below, or the menu is hidden.
 5793                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5794                        editor.context_menu.borrow_mut().take()
 5795                    {
 5796                        let position_matches =
 5797                            if prev_menu.initial_position == menu.initial_position {
 5798                                true
 5799                            } else {
 5800                                let snapshot = editor.buffer.read(cx).read(cx);
 5801                                prev_menu.initial_position.to_offset(&snapshot)
 5802                                    == menu.initial_position.to_offset(&snapshot)
 5803                            };
 5804                        if position_matches {
 5805                            // Preserve markdown cache before `set_filter_results` because it will
 5806                            // try to populate the documentation cache.
 5807                            menu.preserve_markdown_cache(prev_menu);
 5808                        }
 5809                    };
 5810
 5811                    menu.set_filter_results(matches, provider, window, cx);
 5812                }) else {
 5813                    return;
 5814                };
 5815
 5816                menu.visible().then_some(menu)
 5817            };
 5818
 5819            editor
 5820                .update_in(cx, |editor, window, cx| {
 5821                    if editor.focus_handle.is_focused(window)
 5822                        && let Some(menu) = menu
 5823                    {
 5824                        *editor.context_menu.borrow_mut() =
 5825                            Some(CodeContextMenu::Completions(menu));
 5826
 5827                        crate::hover_popover::hide_hover(editor, cx);
 5828                        if editor.show_edit_predictions_in_menu() {
 5829                            editor.update_visible_edit_prediction(window, cx);
 5830                        } else {
 5831                            editor.discard_edit_prediction(false, cx);
 5832                        }
 5833
 5834                        cx.notify();
 5835                        return;
 5836                    }
 5837
 5838                    if editor.completion_tasks.len() <= 1 {
 5839                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5840                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5841                        // If it was already hidden and we don't show edit predictions in the menu,
 5842                        // we should also show the edit prediction when available.
 5843                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5844                            editor.update_visible_edit_prediction(window, cx);
 5845                        }
 5846                    }
 5847                })
 5848                .ok();
 5849        });
 5850
 5851        self.completion_tasks.push((id, task));
 5852    }
 5853
 5854    #[cfg(feature = "test-support")]
 5855    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5856        let menu = self.context_menu.borrow();
 5857        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5858            let completions = menu.completions.borrow();
 5859            Some(completions.to_vec())
 5860        } else {
 5861            None
 5862        }
 5863    }
 5864
 5865    pub fn with_completions_menu_matching_id<R>(
 5866        &self,
 5867        id: CompletionId,
 5868        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5869    ) -> R {
 5870        let mut context_menu = self.context_menu.borrow_mut();
 5871        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5872            return f(None);
 5873        };
 5874        if completions_menu.id != id {
 5875            return f(None);
 5876        }
 5877        f(Some(completions_menu))
 5878    }
 5879
 5880    pub fn confirm_completion(
 5881        &mut self,
 5882        action: &ConfirmCompletion,
 5883        window: &mut Window,
 5884        cx: &mut Context<Self>,
 5885    ) -> Option<Task<Result<()>>> {
 5886        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5887        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5888    }
 5889
 5890    pub fn confirm_completion_insert(
 5891        &mut self,
 5892        _: &ConfirmCompletionInsert,
 5893        window: &mut Window,
 5894        cx: &mut Context<Self>,
 5895    ) -> Option<Task<Result<()>>> {
 5896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5897        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5898    }
 5899
 5900    pub fn confirm_completion_replace(
 5901        &mut self,
 5902        _: &ConfirmCompletionReplace,
 5903        window: &mut Window,
 5904        cx: &mut Context<Self>,
 5905    ) -> Option<Task<Result<()>>> {
 5906        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5907        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5908    }
 5909
 5910    pub fn compose_completion(
 5911        &mut self,
 5912        action: &ComposeCompletion,
 5913        window: &mut Window,
 5914        cx: &mut Context<Self>,
 5915    ) -> Option<Task<Result<()>>> {
 5916        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5917        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5918    }
 5919
 5920    fn do_completion(
 5921        &mut self,
 5922        item_ix: Option<usize>,
 5923        intent: CompletionIntent,
 5924        window: &mut Window,
 5925        cx: &mut Context<Editor>,
 5926    ) -> Option<Task<Result<()>>> {
 5927        use language::ToOffset as _;
 5928
 5929        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5930        else {
 5931            return None;
 5932        };
 5933
 5934        let candidate_id = {
 5935            let entries = completions_menu.entries.borrow();
 5936            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5937            if self.show_edit_predictions_in_menu() {
 5938                self.discard_edit_prediction(true, cx);
 5939            }
 5940            mat.candidate_id
 5941        };
 5942
 5943        let completion = completions_menu
 5944            .completions
 5945            .borrow()
 5946            .get(candidate_id)?
 5947            .clone();
 5948        cx.stop_propagation();
 5949
 5950        let buffer_handle = completions_menu.buffer.clone();
 5951
 5952        let CompletionEdit {
 5953            new_text,
 5954            snippet,
 5955            replace_range,
 5956        } = process_completion_for_edit(
 5957            &completion,
 5958            intent,
 5959            &buffer_handle,
 5960            &completions_menu.initial_position.text_anchor,
 5961            cx,
 5962        );
 5963
 5964        let buffer = buffer_handle.read(cx);
 5965        let snapshot = self.buffer.read(cx).snapshot(cx);
 5966        let newest_anchor = self.selections.newest_anchor();
 5967        let replace_range_multibuffer = {
 5968            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5969            let multibuffer_anchor = snapshot
 5970                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5971                .unwrap()
 5972                ..snapshot
 5973                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5974                    .unwrap();
 5975            multibuffer_anchor.start.to_offset(&snapshot)
 5976                ..multibuffer_anchor.end.to_offset(&snapshot)
 5977        };
 5978        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5979            return None;
 5980        }
 5981
 5982        let old_text = buffer
 5983            .text_for_range(replace_range.clone())
 5984            .collect::<String>();
 5985        let lookbehind = newest_anchor
 5986            .start
 5987            .text_anchor
 5988            .to_offset(buffer)
 5989            .saturating_sub(replace_range.start);
 5990        let lookahead = replace_range
 5991            .end
 5992            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5993        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5994        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5995
 5996        let selections = self.selections.all::<usize>(cx);
 5997        let mut ranges = Vec::new();
 5998        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5999
 6000        for selection in &selections {
 6001            let range = if selection.id == newest_anchor.id {
 6002                replace_range_multibuffer.clone()
 6003            } else {
 6004                let mut range = selection.range();
 6005
 6006                // if prefix is present, don't duplicate it
 6007                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6008                    range.start = range.start.saturating_sub(lookbehind);
 6009
 6010                    // if suffix is also present, mimic the newest cursor and replace it
 6011                    if selection.id != newest_anchor.id
 6012                        && snapshot.contains_str_at(range.end, suffix)
 6013                    {
 6014                        range.end += lookahead;
 6015                    }
 6016                }
 6017                range
 6018            };
 6019
 6020            ranges.push(range.clone());
 6021
 6022            if !self.linked_edit_ranges.is_empty() {
 6023                let start_anchor = snapshot.anchor_before(range.start);
 6024                let end_anchor = snapshot.anchor_after(range.end);
 6025                if let Some(ranges) = self
 6026                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6027                {
 6028                    for (buffer, edits) in ranges {
 6029                        linked_edits
 6030                            .entry(buffer.clone())
 6031                            .or_default()
 6032                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6033                    }
 6034                }
 6035            }
 6036        }
 6037
 6038        let common_prefix_len = old_text
 6039            .chars()
 6040            .zip(new_text.chars())
 6041            .take_while(|(a, b)| a == b)
 6042            .map(|(a, _)| a.len_utf8())
 6043            .sum::<usize>();
 6044
 6045        cx.emit(EditorEvent::InputHandled {
 6046            utf16_range_to_replace: None,
 6047            text: new_text[common_prefix_len..].into(),
 6048        });
 6049
 6050        self.transact(window, cx, |editor, window, cx| {
 6051            if let Some(mut snippet) = snippet {
 6052                snippet.text = new_text.to_string();
 6053                editor
 6054                    .insert_snippet(&ranges, snippet, window, cx)
 6055                    .log_err();
 6056            } else {
 6057                editor.buffer.update(cx, |multi_buffer, cx| {
 6058                    let auto_indent = match completion.insert_text_mode {
 6059                        Some(InsertTextMode::AS_IS) => None,
 6060                        _ => editor.autoindent_mode.clone(),
 6061                    };
 6062                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6063                    multi_buffer.edit(edits, auto_indent, cx);
 6064                });
 6065            }
 6066            for (buffer, edits) in linked_edits {
 6067                buffer.update(cx, |buffer, cx| {
 6068                    let snapshot = buffer.snapshot();
 6069                    let edits = edits
 6070                        .into_iter()
 6071                        .map(|(range, text)| {
 6072                            use text::ToPoint as TP;
 6073                            let end_point = TP::to_point(&range.end, &snapshot);
 6074                            let start_point = TP::to_point(&range.start, &snapshot);
 6075                            (start_point..end_point, text)
 6076                        })
 6077                        .sorted_by_key(|(range, _)| range.start);
 6078                    buffer.edit(edits, None, cx);
 6079                })
 6080            }
 6081
 6082            editor.refresh_edit_prediction(true, false, window, cx);
 6083        });
 6084        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6085
 6086        let show_new_completions_on_confirm = completion
 6087            .confirm
 6088            .as_ref()
 6089            .is_some_and(|confirm| confirm(intent, window, cx));
 6090        if show_new_completions_on_confirm {
 6091            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6092        }
 6093
 6094        let provider = self.completion_provider.as_ref()?;
 6095        drop(completion);
 6096        let apply_edits = provider.apply_additional_edits_for_completion(
 6097            buffer_handle,
 6098            completions_menu.completions.clone(),
 6099            candidate_id,
 6100            true,
 6101            cx,
 6102        );
 6103
 6104        let editor_settings = EditorSettings::get_global(cx);
 6105        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6106            // After the code completion is finished, users often want to know what signatures are needed.
 6107            // so we should automatically call signature_help
 6108            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6109        }
 6110
 6111        Some(cx.foreground_executor().spawn(async move {
 6112            apply_edits.await?;
 6113            Ok(())
 6114        }))
 6115    }
 6116
 6117    pub fn toggle_code_actions(
 6118        &mut self,
 6119        action: &ToggleCodeActions,
 6120        window: &mut Window,
 6121        cx: &mut Context<Self>,
 6122    ) {
 6123        let quick_launch = action.quick_launch;
 6124        let mut context_menu = self.context_menu.borrow_mut();
 6125        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6126            if code_actions.deployed_from == action.deployed_from {
 6127                // Toggle if we're selecting the same one
 6128                *context_menu = None;
 6129                cx.notify();
 6130                return;
 6131            } else {
 6132                // Otherwise, clear it and start a new one
 6133                *context_menu = None;
 6134                cx.notify();
 6135            }
 6136        }
 6137        drop(context_menu);
 6138        let snapshot = self.snapshot(window, cx);
 6139        let deployed_from = action.deployed_from.clone();
 6140        let action = action.clone();
 6141        self.completion_tasks.clear();
 6142        self.discard_edit_prediction(false, cx);
 6143
 6144        let multibuffer_point = match &action.deployed_from {
 6145            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6146                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6147            }
 6148            _ => self.selections.newest::<Point>(cx).head(),
 6149        };
 6150        let Some((buffer, buffer_row)) = snapshot
 6151            .buffer_snapshot
 6152            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6153            .and_then(|(buffer_snapshot, range)| {
 6154                self.buffer()
 6155                    .read(cx)
 6156                    .buffer(buffer_snapshot.remote_id())
 6157                    .map(|buffer| (buffer, range.start.row))
 6158            })
 6159        else {
 6160            return;
 6161        };
 6162        let buffer_id = buffer.read(cx).remote_id();
 6163        let tasks = self
 6164            .tasks
 6165            .get(&(buffer_id, buffer_row))
 6166            .map(|t| Arc::new(t.to_owned()));
 6167
 6168        if !self.focus_handle.is_focused(window) {
 6169            return;
 6170        }
 6171        let project = self.project.clone();
 6172
 6173        let code_actions_task = match deployed_from {
 6174            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6175            _ => self.code_actions(buffer_row, window, cx),
 6176        };
 6177
 6178        let runnable_task = match deployed_from {
 6179            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6180            _ => {
 6181                let mut task_context_task = Task::ready(None);
 6182                if let Some(tasks) = &tasks
 6183                    && let Some(project) = project
 6184                {
 6185                    task_context_task =
 6186                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6187                }
 6188
 6189                cx.spawn_in(window, {
 6190                    let buffer = buffer.clone();
 6191                    async move |editor, cx| {
 6192                        let task_context = task_context_task.await;
 6193
 6194                        let resolved_tasks =
 6195                            tasks
 6196                                .zip(task_context.clone())
 6197                                .map(|(tasks, task_context)| ResolvedTasks {
 6198                                    templates: tasks.resolve(&task_context).collect(),
 6199                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6200                                        multibuffer_point.row,
 6201                                        tasks.column,
 6202                                    )),
 6203                                });
 6204                        let debug_scenarios = editor
 6205                            .update(cx, |editor, cx| {
 6206                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6207                            })?
 6208                            .await;
 6209                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6210                    }
 6211                })
 6212            }
 6213        };
 6214
 6215        cx.spawn_in(window, async move |editor, cx| {
 6216            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6217            let code_actions = code_actions_task.await;
 6218            let spawn_straight_away = quick_launch
 6219                && resolved_tasks
 6220                    .as_ref()
 6221                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6222                && code_actions
 6223                    .as_ref()
 6224                    .is_none_or(|actions| actions.is_empty())
 6225                && debug_scenarios.is_empty();
 6226
 6227            editor.update_in(cx, |editor, window, cx| {
 6228                crate::hover_popover::hide_hover(editor, cx);
 6229                let actions = CodeActionContents::new(
 6230                    resolved_tasks,
 6231                    code_actions,
 6232                    debug_scenarios,
 6233                    task_context.unwrap_or_default(),
 6234                );
 6235
 6236                // Don't show the menu if there are no actions available
 6237                if actions.is_empty() {
 6238                    cx.notify();
 6239                    return Task::ready(Ok(()));
 6240                }
 6241
 6242                *editor.context_menu.borrow_mut() =
 6243                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6244                        buffer,
 6245                        actions,
 6246                        selected_item: Default::default(),
 6247                        scroll_handle: UniformListScrollHandle::default(),
 6248                        deployed_from,
 6249                    }));
 6250                cx.notify();
 6251                if spawn_straight_away
 6252                    && let Some(task) = editor.confirm_code_action(
 6253                        &ConfirmCodeAction { item_ix: Some(0) },
 6254                        window,
 6255                        cx,
 6256                    )
 6257                {
 6258                    return task;
 6259                }
 6260
 6261                Task::ready(Ok(()))
 6262            })
 6263        })
 6264        .detach_and_log_err(cx);
 6265    }
 6266
 6267    fn debug_scenarios(
 6268        &mut self,
 6269        resolved_tasks: &Option<ResolvedTasks>,
 6270        buffer: &Entity<Buffer>,
 6271        cx: &mut App,
 6272    ) -> Task<Vec<task::DebugScenario>> {
 6273        maybe!({
 6274            let project = self.project()?;
 6275            let dap_store = project.read(cx).dap_store();
 6276            let mut scenarios = vec![];
 6277            let resolved_tasks = resolved_tasks.as_ref()?;
 6278            let buffer = buffer.read(cx);
 6279            let language = buffer.language()?;
 6280            let file = buffer.file();
 6281            let debug_adapter = language_settings(language.name().into(), file, cx)
 6282                .debuggers
 6283                .first()
 6284                .map(SharedString::from)
 6285                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6286
 6287            dap_store.update(cx, |dap_store, cx| {
 6288                for (_, task) in &resolved_tasks.templates {
 6289                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6290                        task.original_task().clone(),
 6291                        debug_adapter.clone().into(),
 6292                        task.display_label().to_owned().into(),
 6293                        cx,
 6294                    );
 6295                    scenarios.push(maybe_scenario);
 6296                }
 6297            });
 6298            Some(cx.background_spawn(async move {
 6299                futures::future::join_all(scenarios)
 6300                    .await
 6301                    .into_iter()
 6302                    .flatten()
 6303                    .collect::<Vec<_>>()
 6304            }))
 6305        })
 6306        .unwrap_or_else(|| Task::ready(vec![]))
 6307    }
 6308
 6309    fn code_actions(
 6310        &mut self,
 6311        buffer_row: u32,
 6312        window: &mut Window,
 6313        cx: &mut Context<Self>,
 6314    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6315        let mut task = self.code_actions_task.take();
 6316        cx.spawn_in(window, async move |editor, cx| {
 6317            while let Some(prev_task) = task {
 6318                prev_task.await.log_err();
 6319                task = editor
 6320                    .update(cx, |this, _| this.code_actions_task.take())
 6321                    .ok()?;
 6322            }
 6323
 6324            editor
 6325                .update(cx, |editor, cx| {
 6326                    editor
 6327                        .available_code_actions
 6328                        .clone()
 6329                        .and_then(|(location, code_actions)| {
 6330                            let snapshot = location.buffer.read(cx).snapshot();
 6331                            let point_range = location.range.to_point(&snapshot);
 6332                            let point_range = point_range.start.row..=point_range.end.row;
 6333                            if point_range.contains(&buffer_row) {
 6334                                Some(code_actions)
 6335                            } else {
 6336                                None
 6337                            }
 6338                        })
 6339                })
 6340                .ok()
 6341                .flatten()
 6342        })
 6343    }
 6344
 6345    pub fn confirm_code_action(
 6346        &mut self,
 6347        action: &ConfirmCodeAction,
 6348        window: &mut Window,
 6349        cx: &mut Context<Self>,
 6350    ) -> Option<Task<Result<()>>> {
 6351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6352
 6353        let actions_menu =
 6354            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6355                menu
 6356            } else {
 6357                return None;
 6358            };
 6359
 6360        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6361        let action = actions_menu.actions.get(action_ix)?;
 6362        let title = action.label();
 6363        let buffer = actions_menu.buffer;
 6364        let workspace = self.workspace()?;
 6365
 6366        match action {
 6367            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6368                workspace.update(cx, |workspace, cx| {
 6369                    workspace.schedule_resolved_task(
 6370                        task_source_kind,
 6371                        resolved_task,
 6372                        false,
 6373                        window,
 6374                        cx,
 6375                    );
 6376
 6377                    Some(Task::ready(Ok(())))
 6378                })
 6379            }
 6380            CodeActionsItem::CodeAction {
 6381                excerpt_id,
 6382                action,
 6383                provider,
 6384            } => {
 6385                let apply_code_action =
 6386                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6387                let workspace = workspace.downgrade();
 6388                Some(cx.spawn_in(window, async move |editor, cx| {
 6389                    let project_transaction = apply_code_action.await?;
 6390                    Self::open_project_transaction(
 6391                        &editor,
 6392                        workspace,
 6393                        project_transaction,
 6394                        title,
 6395                        cx,
 6396                    )
 6397                    .await
 6398                }))
 6399            }
 6400            CodeActionsItem::DebugScenario(scenario) => {
 6401                let context = actions_menu.actions.context;
 6402
 6403                workspace.update(cx, |workspace, cx| {
 6404                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6405                    workspace.start_debug_session(
 6406                        scenario,
 6407                        context,
 6408                        Some(buffer),
 6409                        None,
 6410                        window,
 6411                        cx,
 6412                    );
 6413                });
 6414                Some(Task::ready(Ok(())))
 6415            }
 6416        }
 6417    }
 6418
 6419    pub async fn open_project_transaction(
 6420        editor: &WeakEntity<Editor>,
 6421        workspace: WeakEntity<Workspace>,
 6422        transaction: ProjectTransaction,
 6423        title: String,
 6424        cx: &mut AsyncWindowContext,
 6425    ) -> Result<()> {
 6426        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6427        cx.update(|_, cx| {
 6428            entries.sort_unstable_by_key(|(buffer, _)| {
 6429                buffer.read(cx).file().map(|f| f.path().clone())
 6430            });
 6431        })?;
 6432        if entries.is_empty() {
 6433            return Ok(());
 6434        }
 6435
 6436        // If the project transaction's edits are all contained within this editor, then
 6437        // avoid opening a new editor to display them.
 6438
 6439        if let [(buffer, transaction)] = &*entries {
 6440            let excerpt = editor.update(cx, |editor, cx| {
 6441                editor
 6442                    .buffer()
 6443                    .read(cx)
 6444                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6445            })?;
 6446            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6447                && excerpted_buffer == *buffer
 6448            {
 6449                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6450                    let excerpt_range = excerpt_range.to_offset(buffer);
 6451                    buffer
 6452                        .edited_ranges_for_transaction::<usize>(transaction)
 6453                        .all(|range| {
 6454                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6455                        })
 6456                })?;
 6457
 6458                if all_edits_within_excerpt {
 6459                    return Ok(());
 6460                }
 6461            }
 6462        }
 6463
 6464        let mut ranges_to_highlight = Vec::new();
 6465        let excerpt_buffer = cx.new(|cx| {
 6466            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6467            for (buffer_handle, transaction) in &entries {
 6468                let edited_ranges = buffer_handle
 6469                    .read(cx)
 6470                    .edited_ranges_for_transaction::<Point>(transaction)
 6471                    .collect::<Vec<_>>();
 6472                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6473                    PathKey::for_buffer(buffer_handle, cx),
 6474                    buffer_handle.clone(),
 6475                    edited_ranges,
 6476                    multibuffer_context_lines(cx),
 6477                    cx,
 6478                );
 6479
 6480                ranges_to_highlight.extend(ranges);
 6481            }
 6482            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6483            multibuffer
 6484        })?;
 6485
 6486        workspace.update_in(cx, |workspace, window, cx| {
 6487            let project = workspace.project().clone();
 6488            let editor =
 6489                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6490            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6491            editor.update(cx, |editor, cx| {
 6492                editor.highlight_background::<Self>(
 6493                    &ranges_to_highlight,
 6494                    |theme| theme.colors().editor_highlighted_line_background,
 6495                    cx,
 6496                );
 6497            });
 6498        })?;
 6499
 6500        Ok(())
 6501    }
 6502
 6503    pub fn clear_code_action_providers(&mut self) {
 6504        self.code_action_providers.clear();
 6505        self.available_code_actions.take();
 6506    }
 6507
 6508    pub fn add_code_action_provider(
 6509        &mut self,
 6510        provider: Rc<dyn CodeActionProvider>,
 6511        window: &mut Window,
 6512        cx: &mut Context<Self>,
 6513    ) {
 6514        if self
 6515            .code_action_providers
 6516            .iter()
 6517            .any(|existing_provider| existing_provider.id() == provider.id())
 6518        {
 6519            return;
 6520        }
 6521
 6522        self.code_action_providers.push(provider);
 6523        self.refresh_code_actions(window, cx);
 6524    }
 6525
 6526    pub fn remove_code_action_provider(
 6527        &mut self,
 6528        id: Arc<str>,
 6529        window: &mut Window,
 6530        cx: &mut Context<Self>,
 6531    ) {
 6532        self.code_action_providers
 6533            .retain(|provider| provider.id() != id);
 6534        self.refresh_code_actions(window, cx);
 6535    }
 6536
 6537    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6538        !self.code_action_providers.is_empty()
 6539            && EditorSettings::get_global(cx).toolbar.code_actions
 6540    }
 6541
 6542    pub fn has_available_code_actions(&self) -> bool {
 6543        self.available_code_actions
 6544            .as_ref()
 6545            .is_some_and(|(_, actions)| !actions.is_empty())
 6546    }
 6547
 6548    fn render_inline_code_actions(
 6549        &self,
 6550        icon_size: ui::IconSize,
 6551        display_row: DisplayRow,
 6552        is_active: bool,
 6553        cx: &mut Context<Self>,
 6554    ) -> AnyElement {
 6555        let show_tooltip = !self.context_menu_visible();
 6556        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6557            .icon_size(icon_size)
 6558            .shape(ui::IconButtonShape::Square)
 6559            .icon_color(ui::Color::Hidden)
 6560            .toggle_state(is_active)
 6561            .when(show_tooltip, |this| {
 6562                this.tooltip({
 6563                    let focus_handle = self.focus_handle.clone();
 6564                    move |window, cx| {
 6565                        Tooltip::for_action_in(
 6566                            "Toggle Code Actions",
 6567                            &ToggleCodeActions {
 6568                                deployed_from: None,
 6569                                quick_launch: false,
 6570                            },
 6571                            &focus_handle,
 6572                            window,
 6573                            cx,
 6574                        )
 6575                    }
 6576                })
 6577            })
 6578            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6579                window.focus(&editor.focus_handle(cx));
 6580                editor.toggle_code_actions(
 6581                    &crate::actions::ToggleCodeActions {
 6582                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6583                            display_row,
 6584                        )),
 6585                        quick_launch: false,
 6586                    },
 6587                    window,
 6588                    cx,
 6589                );
 6590            }))
 6591            .into_any_element()
 6592    }
 6593
 6594    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6595        &self.context_menu
 6596    }
 6597
 6598    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6599        let newest_selection = self.selections.newest_anchor().clone();
 6600        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6601        let buffer = self.buffer.read(cx);
 6602        if newest_selection.head().diff_base_anchor.is_some() {
 6603            return None;
 6604        }
 6605        let (start_buffer, start) =
 6606            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6607        let (end_buffer, end) =
 6608            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6609        if start_buffer != end_buffer {
 6610            return None;
 6611        }
 6612
 6613        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6614            cx.background_executor()
 6615                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6616                .await;
 6617
 6618            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6619                let providers = this.code_action_providers.clone();
 6620                let tasks = this
 6621                    .code_action_providers
 6622                    .iter()
 6623                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6624                    .collect::<Vec<_>>();
 6625                (providers, tasks)
 6626            })?;
 6627
 6628            let mut actions = Vec::new();
 6629            for (provider, provider_actions) in
 6630                providers.into_iter().zip(future::join_all(tasks).await)
 6631            {
 6632                if let Some(provider_actions) = provider_actions.log_err() {
 6633                    actions.extend(provider_actions.into_iter().map(|action| {
 6634                        AvailableCodeAction {
 6635                            excerpt_id: newest_selection.start.excerpt_id,
 6636                            action,
 6637                            provider: provider.clone(),
 6638                        }
 6639                    }));
 6640                }
 6641            }
 6642
 6643            this.update(cx, |this, cx| {
 6644                this.available_code_actions = if actions.is_empty() {
 6645                    None
 6646                } else {
 6647                    Some((
 6648                        Location {
 6649                            buffer: start_buffer,
 6650                            range: start..end,
 6651                        },
 6652                        actions.into(),
 6653                    ))
 6654                };
 6655                cx.notify();
 6656            })
 6657        }));
 6658        None
 6659    }
 6660
 6661    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6662        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6663            self.show_git_blame_inline = false;
 6664
 6665            self.show_git_blame_inline_delay_task =
 6666                Some(cx.spawn_in(window, async move |this, cx| {
 6667                    cx.background_executor().timer(delay).await;
 6668
 6669                    this.update(cx, |this, cx| {
 6670                        this.show_git_blame_inline = true;
 6671                        cx.notify();
 6672                    })
 6673                    .log_err();
 6674                }));
 6675        }
 6676    }
 6677
 6678    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6679        let snapshot = self.snapshot(window, cx);
 6680        let cursor = self.selections.newest::<Point>(cx).head();
 6681        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6682        else {
 6683            return;
 6684        };
 6685
 6686        let Some(blame) = self.blame.as_ref() else {
 6687            return;
 6688        };
 6689
 6690        let row_info = RowInfo {
 6691            buffer_id: Some(buffer.remote_id()),
 6692            buffer_row: Some(point.row),
 6693            ..Default::default()
 6694        };
 6695        let Some((buffer, blame_entry)) = blame
 6696            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6697            .flatten()
 6698        else {
 6699            return;
 6700        };
 6701
 6702        let anchor = self.selections.newest_anchor().head();
 6703        let position = self.to_pixel_point(anchor, &snapshot, window);
 6704        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6705            self.show_blame_popover(
 6706                buffer,
 6707                &blame_entry,
 6708                position + last_bounds.origin,
 6709                true,
 6710                cx,
 6711            );
 6712        };
 6713    }
 6714
 6715    fn show_blame_popover(
 6716        &mut self,
 6717        buffer: BufferId,
 6718        blame_entry: &BlameEntry,
 6719        position: gpui::Point<Pixels>,
 6720        ignore_timeout: bool,
 6721        cx: &mut Context<Self>,
 6722    ) {
 6723        if let Some(state) = &mut self.inline_blame_popover {
 6724            state.hide_task.take();
 6725        } else {
 6726            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6727            let blame_entry = blame_entry.clone();
 6728            let show_task = cx.spawn(async move |editor, cx| {
 6729                if !ignore_timeout {
 6730                    cx.background_executor()
 6731                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6732                        .await;
 6733                }
 6734                editor
 6735                    .update(cx, |editor, cx| {
 6736                        editor.inline_blame_popover_show_task.take();
 6737                        let Some(blame) = editor.blame.as_ref() else {
 6738                            return;
 6739                        };
 6740                        let blame = blame.read(cx);
 6741                        let details = blame.details_for_entry(buffer, &blame_entry);
 6742                        let markdown = cx.new(|cx| {
 6743                            Markdown::new(
 6744                                details
 6745                                    .as_ref()
 6746                                    .map(|message| message.message.clone())
 6747                                    .unwrap_or_default(),
 6748                                None,
 6749                                None,
 6750                                cx,
 6751                            )
 6752                        });
 6753                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6754                            position,
 6755                            hide_task: None,
 6756                            popover_bounds: None,
 6757                            popover_state: InlineBlamePopoverState {
 6758                                scroll_handle: ScrollHandle::new(),
 6759                                commit_message: details,
 6760                                markdown,
 6761                            },
 6762                            keyboard_grace: ignore_timeout,
 6763                        });
 6764                        cx.notify();
 6765                    })
 6766                    .ok();
 6767            });
 6768            self.inline_blame_popover_show_task = Some(show_task);
 6769        }
 6770    }
 6771
 6772    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6773        self.inline_blame_popover_show_task.take();
 6774        if let Some(state) = &mut self.inline_blame_popover {
 6775            let hide_task = cx.spawn(async move |editor, cx| {
 6776                cx.background_executor()
 6777                    .timer(std::time::Duration::from_millis(100))
 6778                    .await;
 6779                editor
 6780                    .update(cx, |editor, cx| {
 6781                        editor.inline_blame_popover.take();
 6782                        cx.notify();
 6783                    })
 6784                    .ok();
 6785            });
 6786            state.hide_task = Some(hide_task);
 6787        }
 6788    }
 6789
 6790    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6791        if self.pending_rename.is_some() {
 6792            return None;
 6793        }
 6794
 6795        let provider = self.semantics_provider.clone()?;
 6796        let buffer = self.buffer.read(cx);
 6797        let newest_selection = self.selections.newest_anchor().clone();
 6798        let cursor_position = newest_selection.head();
 6799        let (cursor_buffer, cursor_buffer_position) =
 6800            buffer.text_anchor_for_position(cursor_position, cx)?;
 6801        let (tail_buffer, tail_buffer_position) =
 6802            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6803        if cursor_buffer != tail_buffer {
 6804            return None;
 6805        }
 6806
 6807        let snapshot = cursor_buffer.read(cx).snapshot();
 6808        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6809        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6810        if start_word_range != end_word_range {
 6811            self.document_highlights_task.take();
 6812            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6813            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6814            return None;
 6815        }
 6816
 6817        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6818        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6819            cx.background_executor()
 6820                .timer(Duration::from_millis(debounce))
 6821                .await;
 6822
 6823            let highlights = if let Some(highlights) = cx
 6824                .update(|cx| {
 6825                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6826                })
 6827                .ok()
 6828                .flatten()
 6829            {
 6830                highlights.await.log_err()
 6831            } else {
 6832                None
 6833            };
 6834
 6835            if let Some(highlights) = highlights {
 6836                this.update(cx, |this, cx| {
 6837                    if this.pending_rename.is_some() {
 6838                        return;
 6839                    }
 6840
 6841                    let buffer = this.buffer.read(cx);
 6842                    if buffer
 6843                        .text_anchor_for_position(cursor_position, cx)
 6844                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6845                    {
 6846                        return;
 6847                    }
 6848
 6849                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6850                    let mut write_ranges = Vec::new();
 6851                    let mut read_ranges = Vec::new();
 6852                    for highlight in highlights {
 6853                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6854                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6855                        {
 6856                            let start = highlight
 6857                                .range
 6858                                .start
 6859                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6860                            let end = highlight
 6861                                .range
 6862                                .end
 6863                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6864                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6865                                continue;
 6866                            }
 6867
 6868                            let range = Anchor {
 6869                                buffer_id: Some(buffer_id),
 6870                                excerpt_id,
 6871                                text_anchor: start,
 6872                                diff_base_anchor: None,
 6873                            }..Anchor {
 6874                                buffer_id: Some(buffer_id),
 6875                                excerpt_id,
 6876                                text_anchor: end,
 6877                                diff_base_anchor: None,
 6878                            };
 6879                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6880                                write_ranges.push(range);
 6881                            } else {
 6882                                read_ranges.push(range);
 6883                            }
 6884                        }
 6885                    }
 6886
 6887                    this.highlight_background::<DocumentHighlightRead>(
 6888                        &read_ranges,
 6889                        |theme| theme.colors().editor_document_highlight_read_background,
 6890                        cx,
 6891                    );
 6892                    this.highlight_background::<DocumentHighlightWrite>(
 6893                        &write_ranges,
 6894                        |theme| theme.colors().editor_document_highlight_write_background,
 6895                        cx,
 6896                    );
 6897                    cx.notify();
 6898                })
 6899                .log_err();
 6900            }
 6901        }));
 6902        None
 6903    }
 6904
 6905    fn prepare_highlight_query_from_selection(
 6906        &mut self,
 6907        cx: &mut Context<Editor>,
 6908    ) -> Option<(String, Range<Anchor>)> {
 6909        if matches!(self.mode, EditorMode::SingleLine) {
 6910            return None;
 6911        }
 6912        if !EditorSettings::get_global(cx).selection_highlight {
 6913            return None;
 6914        }
 6915        if self.selections.count() != 1 || self.selections.line_mode() {
 6916            return None;
 6917        }
 6918        let selection = self.selections.newest::<Point>(cx);
 6919        if selection.is_empty() || selection.start.row != selection.end.row {
 6920            return None;
 6921        }
 6922        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6923        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6924        let query = multi_buffer_snapshot
 6925            .text_for_range(selection_anchor_range.clone())
 6926            .collect::<String>();
 6927        if query.trim().is_empty() {
 6928            return None;
 6929        }
 6930        Some((query, selection_anchor_range))
 6931    }
 6932
 6933    fn update_selection_occurrence_highlights(
 6934        &mut self,
 6935        query_text: String,
 6936        query_range: Range<Anchor>,
 6937        multi_buffer_range_to_query: Range<Point>,
 6938        use_debounce: bool,
 6939        window: &mut Window,
 6940        cx: &mut Context<Editor>,
 6941    ) -> Task<()> {
 6942        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6943        cx.spawn_in(window, async move |editor, cx| {
 6944            if use_debounce {
 6945                cx.background_executor()
 6946                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6947                    .await;
 6948            }
 6949            let match_task = cx.background_spawn(async move {
 6950                let buffer_ranges = multi_buffer_snapshot
 6951                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6952                    .into_iter()
 6953                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6954                let mut match_ranges = Vec::new();
 6955                let Ok(regex) = project::search::SearchQuery::text(
 6956                    query_text.clone(),
 6957                    false,
 6958                    false,
 6959                    false,
 6960                    Default::default(),
 6961                    Default::default(),
 6962                    false,
 6963                    None,
 6964                ) else {
 6965                    return Vec::default();
 6966                };
 6967                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6968                    match_ranges.extend(
 6969                        regex
 6970                            .search(buffer_snapshot, Some(search_range.clone()))
 6971                            .await
 6972                            .into_iter()
 6973                            .filter_map(|match_range| {
 6974                                let match_start = buffer_snapshot
 6975                                    .anchor_after(search_range.start + match_range.start);
 6976                                let match_end = buffer_snapshot
 6977                                    .anchor_before(search_range.start + match_range.end);
 6978                                let match_anchor_range = Anchor::range_in_buffer(
 6979                                    excerpt_id,
 6980                                    buffer_snapshot.remote_id(),
 6981                                    match_start..match_end,
 6982                                );
 6983                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6984                            }),
 6985                    );
 6986                }
 6987                match_ranges
 6988            });
 6989            let match_ranges = match_task.await;
 6990            editor
 6991                .update_in(cx, |editor, _, cx| {
 6992                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6993                    if !match_ranges.is_empty() {
 6994                        editor.highlight_background::<SelectedTextHighlight>(
 6995                            &match_ranges,
 6996                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6997                            cx,
 6998                        )
 6999                    }
 7000                })
 7001                .log_err();
 7002        })
 7003    }
 7004
 7005    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7006        struct NewlineFold;
 7007        let type_id = std::any::TypeId::of::<NewlineFold>();
 7008        if !self.mode.is_single_line() {
 7009            return;
 7010        }
 7011        let snapshot = self.snapshot(window, cx);
 7012        if snapshot.buffer_snapshot.max_point().row == 0 {
 7013            return;
 7014        }
 7015        let task = cx.background_spawn(async move {
 7016            let new_newlines = snapshot
 7017                .buffer_chars_at(0)
 7018                .filter_map(|(c, i)| {
 7019                    if c == '\n' {
 7020                        Some(
 7021                            snapshot.buffer_snapshot.anchor_after(i)
 7022                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7023                        )
 7024                    } else {
 7025                        None
 7026                    }
 7027                })
 7028                .collect::<Vec<_>>();
 7029            let existing_newlines = snapshot
 7030                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7031                .filter_map(|fold| {
 7032                    if fold.placeholder.type_tag == Some(type_id) {
 7033                        Some(fold.range.start..fold.range.end)
 7034                    } else {
 7035                        None
 7036                    }
 7037                })
 7038                .collect::<Vec<_>>();
 7039
 7040            (new_newlines, existing_newlines)
 7041        });
 7042        self.folding_newlines = cx.spawn(async move |this, cx| {
 7043            let (new_newlines, existing_newlines) = task.await;
 7044            if new_newlines == existing_newlines {
 7045                return;
 7046            }
 7047            let placeholder = FoldPlaceholder {
 7048                render: Arc::new(move |_, _, cx| {
 7049                    div()
 7050                        .bg(cx.theme().status().hint_background)
 7051                        .border_b_1()
 7052                        .size_full()
 7053                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7054                        .border_color(cx.theme().status().hint)
 7055                        .child("\\n")
 7056                        .into_any()
 7057                }),
 7058                constrain_width: false,
 7059                merge_adjacent: false,
 7060                type_tag: Some(type_id),
 7061            };
 7062            let creases = new_newlines
 7063                .into_iter()
 7064                .map(|range| Crease::simple(range, placeholder.clone()))
 7065                .collect();
 7066            this.update(cx, |this, cx| {
 7067                this.display_map.update(cx, |display_map, cx| {
 7068                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7069                    display_map.fold(creases, cx);
 7070                });
 7071            })
 7072            .ok();
 7073        });
 7074    }
 7075
 7076    fn refresh_selected_text_highlights(
 7077        &mut self,
 7078        on_buffer_edit: bool,
 7079        window: &mut Window,
 7080        cx: &mut Context<Editor>,
 7081    ) {
 7082        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7083        else {
 7084            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7085            self.quick_selection_highlight_task.take();
 7086            self.debounced_selection_highlight_task.take();
 7087            return;
 7088        };
 7089        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7090        if on_buffer_edit
 7091            || self
 7092                .quick_selection_highlight_task
 7093                .as_ref()
 7094                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7095        {
 7096            let multi_buffer_visible_start = self
 7097                .scroll_manager
 7098                .anchor()
 7099                .anchor
 7100                .to_point(&multi_buffer_snapshot);
 7101            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7102                multi_buffer_visible_start
 7103                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7104                Bias::Left,
 7105            );
 7106            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7107            self.quick_selection_highlight_task = Some((
 7108                query_range.clone(),
 7109                self.update_selection_occurrence_highlights(
 7110                    query_text.clone(),
 7111                    query_range.clone(),
 7112                    multi_buffer_visible_range,
 7113                    false,
 7114                    window,
 7115                    cx,
 7116                ),
 7117            ));
 7118        }
 7119        if on_buffer_edit
 7120            || self
 7121                .debounced_selection_highlight_task
 7122                .as_ref()
 7123                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7124        {
 7125            let multi_buffer_start = multi_buffer_snapshot
 7126                .anchor_before(0)
 7127                .to_point(&multi_buffer_snapshot);
 7128            let multi_buffer_end = multi_buffer_snapshot
 7129                .anchor_after(multi_buffer_snapshot.len())
 7130                .to_point(&multi_buffer_snapshot);
 7131            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7132            self.debounced_selection_highlight_task = Some((
 7133                query_range.clone(),
 7134                self.update_selection_occurrence_highlights(
 7135                    query_text,
 7136                    query_range,
 7137                    multi_buffer_full_range,
 7138                    true,
 7139                    window,
 7140                    cx,
 7141                ),
 7142            ));
 7143        }
 7144    }
 7145
 7146    pub fn refresh_edit_prediction(
 7147        &mut self,
 7148        debounce: bool,
 7149        user_requested: bool,
 7150        window: &mut Window,
 7151        cx: &mut Context<Self>,
 7152    ) -> Option<()> {
 7153        if DisableAiSettings::get_global(cx).disable_ai {
 7154            return None;
 7155        }
 7156
 7157        let provider = self.edit_prediction_provider()?;
 7158        let cursor = self.selections.newest_anchor().head();
 7159        let (buffer, cursor_buffer_position) =
 7160            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7161
 7162        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7163            self.discard_edit_prediction(false, cx);
 7164            return None;
 7165        }
 7166
 7167        self.update_visible_edit_prediction(window, cx);
 7168
 7169        if !user_requested
 7170            && (!self.should_show_edit_predictions()
 7171                || !self.is_focused(window)
 7172                || buffer.read(cx).is_empty())
 7173        {
 7174            self.discard_edit_prediction(false, cx);
 7175            return None;
 7176        }
 7177
 7178        provider.refresh(
 7179            self.project.clone(),
 7180            buffer,
 7181            cursor_buffer_position,
 7182            debounce,
 7183            cx,
 7184        );
 7185        Some(())
 7186    }
 7187
 7188    fn show_edit_predictions_in_menu(&self) -> bool {
 7189        match self.edit_prediction_settings {
 7190            EditPredictionSettings::Disabled => false,
 7191            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7192        }
 7193    }
 7194
 7195    pub fn edit_predictions_enabled(&self) -> bool {
 7196        match self.edit_prediction_settings {
 7197            EditPredictionSettings::Disabled => false,
 7198            EditPredictionSettings::Enabled { .. } => true,
 7199        }
 7200    }
 7201
 7202    fn edit_prediction_requires_modifier(&self) -> bool {
 7203        match self.edit_prediction_settings {
 7204            EditPredictionSettings::Disabled => false,
 7205            EditPredictionSettings::Enabled {
 7206                preview_requires_modifier,
 7207                ..
 7208            } => preview_requires_modifier,
 7209        }
 7210    }
 7211
 7212    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7213        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7214            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7215            self.discard_edit_prediction(false, cx);
 7216        } else {
 7217            let selection = self.selections.newest_anchor();
 7218            let cursor = selection.head();
 7219
 7220            if let Some((buffer, cursor_buffer_position)) =
 7221                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7222            {
 7223                self.edit_prediction_settings =
 7224                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7225            }
 7226        }
 7227    }
 7228
 7229    fn edit_prediction_settings_at_position(
 7230        &self,
 7231        buffer: &Entity<Buffer>,
 7232        buffer_position: language::Anchor,
 7233        cx: &App,
 7234    ) -> EditPredictionSettings {
 7235        if !self.mode.is_full()
 7236            || !self.show_edit_predictions_override.unwrap_or(true)
 7237            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7238        {
 7239            return EditPredictionSettings::Disabled;
 7240        }
 7241
 7242        let buffer = buffer.read(cx);
 7243
 7244        let file = buffer.file();
 7245
 7246        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7247            return EditPredictionSettings::Disabled;
 7248        };
 7249
 7250        let by_provider = matches!(
 7251            self.menu_edit_predictions_policy,
 7252            MenuEditPredictionsPolicy::ByProvider
 7253        );
 7254
 7255        let show_in_menu = by_provider
 7256            && self
 7257                .edit_prediction_provider
 7258                .as_ref()
 7259                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7260
 7261        let preview_requires_modifier =
 7262            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7263
 7264        EditPredictionSettings::Enabled {
 7265            show_in_menu,
 7266            preview_requires_modifier,
 7267        }
 7268    }
 7269
 7270    fn should_show_edit_predictions(&self) -> bool {
 7271        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7272    }
 7273
 7274    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7275        matches!(
 7276            self.edit_prediction_preview,
 7277            EditPredictionPreview::Active { .. }
 7278        )
 7279    }
 7280
 7281    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7282        let cursor = self.selections.newest_anchor().head();
 7283        if let Some((buffer, cursor_position)) =
 7284            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7285        {
 7286            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7287        } else {
 7288            false
 7289        }
 7290    }
 7291
 7292    pub fn supports_minimap(&self, cx: &App) -> bool {
 7293        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7294    }
 7295
 7296    fn edit_predictions_enabled_in_buffer(
 7297        &self,
 7298        buffer: &Entity<Buffer>,
 7299        buffer_position: language::Anchor,
 7300        cx: &App,
 7301    ) -> bool {
 7302        maybe!({
 7303            if self.read_only(cx) {
 7304                return Some(false);
 7305            }
 7306            let provider = self.edit_prediction_provider()?;
 7307            if !provider.is_enabled(buffer, buffer_position, cx) {
 7308                return Some(false);
 7309            }
 7310            let buffer = buffer.read(cx);
 7311            let Some(file) = buffer.file() else {
 7312                return Some(true);
 7313            };
 7314            let settings = all_language_settings(Some(file), cx);
 7315            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7316        })
 7317        .unwrap_or(false)
 7318    }
 7319
 7320    fn cycle_edit_prediction(
 7321        &mut self,
 7322        direction: Direction,
 7323        window: &mut Window,
 7324        cx: &mut Context<Self>,
 7325    ) -> Option<()> {
 7326        let provider = self.edit_prediction_provider()?;
 7327        let cursor = self.selections.newest_anchor().head();
 7328        let (buffer, cursor_buffer_position) =
 7329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7330        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7331            return None;
 7332        }
 7333
 7334        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7335        self.update_visible_edit_prediction(window, cx);
 7336
 7337        Some(())
 7338    }
 7339
 7340    pub fn show_edit_prediction(
 7341        &mut self,
 7342        _: &ShowEditPrediction,
 7343        window: &mut Window,
 7344        cx: &mut Context<Self>,
 7345    ) {
 7346        if !self.has_active_edit_prediction() {
 7347            self.refresh_edit_prediction(false, true, window, cx);
 7348            return;
 7349        }
 7350
 7351        self.update_visible_edit_prediction(window, cx);
 7352    }
 7353
 7354    pub fn display_cursor_names(
 7355        &mut self,
 7356        _: &DisplayCursorNames,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) {
 7360        self.show_cursor_names(window, cx);
 7361    }
 7362
 7363    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7364        self.show_cursor_names = true;
 7365        cx.notify();
 7366        cx.spawn_in(window, async move |this, cx| {
 7367            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7368            this.update(cx, |this, cx| {
 7369                this.show_cursor_names = false;
 7370                cx.notify()
 7371            })
 7372            .ok()
 7373        })
 7374        .detach();
 7375    }
 7376
 7377    pub fn next_edit_prediction(
 7378        &mut self,
 7379        _: &NextEditPrediction,
 7380        window: &mut Window,
 7381        cx: &mut Context<Self>,
 7382    ) {
 7383        if self.has_active_edit_prediction() {
 7384            self.cycle_edit_prediction(Direction::Next, window, cx);
 7385        } else {
 7386            let is_copilot_disabled = self
 7387                .refresh_edit_prediction(false, true, window, cx)
 7388                .is_none();
 7389            if is_copilot_disabled {
 7390                cx.propagate();
 7391            }
 7392        }
 7393    }
 7394
 7395    pub fn previous_edit_prediction(
 7396        &mut self,
 7397        _: &PreviousEditPrediction,
 7398        window: &mut Window,
 7399        cx: &mut Context<Self>,
 7400    ) {
 7401        if self.has_active_edit_prediction() {
 7402            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7403        } else {
 7404            let is_copilot_disabled = self
 7405                .refresh_edit_prediction(false, true, window, cx)
 7406                .is_none();
 7407            if is_copilot_disabled {
 7408                cx.propagate();
 7409            }
 7410        }
 7411    }
 7412
 7413    pub fn accept_edit_prediction(
 7414        &mut self,
 7415        _: &AcceptEditPrediction,
 7416        window: &mut Window,
 7417        cx: &mut Context<Self>,
 7418    ) {
 7419        if self.show_edit_predictions_in_menu() {
 7420            self.hide_context_menu(window, cx);
 7421        }
 7422
 7423        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7424            return;
 7425        };
 7426
 7427        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7428
 7429        match &active_edit_prediction.completion {
 7430            EditPrediction::Move { target, .. } => {
 7431                let target = *target;
 7432
 7433                if let Some(position_map) = &self.last_position_map {
 7434                    if position_map
 7435                        .visible_row_range
 7436                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7437                        || !self.edit_prediction_requires_modifier()
 7438                    {
 7439                        self.unfold_ranges(&[target..target], true, false, cx);
 7440                        // Note that this is also done in vim's handler of the Tab action.
 7441                        self.change_selections(
 7442                            SelectionEffects::scroll(Autoscroll::newest()),
 7443                            window,
 7444                            cx,
 7445                            |selections| {
 7446                                selections.select_anchor_ranges([target..target]);
 7447                            },
 7448                        );
 7449                        self.clear_row_highlights::<EditPredictionPreview>();
 7450
 7451                        self.edit_prediction_preview
 7452                            .set_previous_scroll_position(None);
 7453                    } else {
 7454                        self.edit_prediction_preview
 7455                            .set_previous_scroll_position(Some(
 7456                                position_map.snapshot.scroll_anchor,
 7457                            ));
 7458
 7459                        self.highlight_rows::<EditPredictionPreview>(
 7460                            target..target,
 7461                            cx.theme().colors().editor_highlighted_line_background,
 7462                            RowHighlightOptions {
 7463                                autoscroll: true,
 7464                                ..Default::default()
 7465                            },
 7466                            cx,
 7467                        );
 7468                        self.request_autoscroll(Autoscroll::fit(), cx);
 7469                    }
 7470                }
 7471            }
 7472            EditPrediction::Edit { edits, .. } => {
 7473                if let Some(provider) = self.edit_prediction_provider() {
 7474                    provider.accept(cx);
 7475                }
 7476
 7477                // Store the transaction ID and selections before applying the edit
 7478                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7479
 7480                let snapshot = self.buffer.read(cx).snapshot(cx);
 7481                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7482
 7483                self.buffer.update(cx, |buffer, cx| {
 7484                    buffer.edit(edits.iter().cloned(), None, cx)
 7485                });
 7486
 7487                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7488                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7489                });
 7490
 7491                let selections = self.selections.disjoint_anchors_arc();
 7492                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7493                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7494                    if has_new_transaction {
 7495                        self.selection_history
 7496                            .insert_transaction(transaction_id_now, selections);
 7497                    }
 7498                }
 7499
 7500                self.update_visible_edit_prediction(window, cx);
 7501                if self.active_edit_prediction.is_none() {
 7502                    self.refresh_edit_prediction(true, true, window, cx);
 7503                }
 7504
 7505                cx.notify();
 7506            }
 7507        }
 7508
 7509        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7510    }
 7511
 7512    pub fn accept_partial_edit_prediction(
 7513        &mut self,
 7514        _: &AcceptPartialEditPrediction,
 7515        window: &mut Window,
 7516        cx: &mut Context<Self>,
 7517    ) {
 7518        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7519            return;
 7520        };
 7521        if self.selections.count() != 1 {
 7522            return;
 7523        }
 7524
 7525        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7526
 7527        match &active_edit_prediction.completion {
 7528            EditPrediction::Move { target, .. } => {
 7529                let target = *target;
 7530                self.change_selections(
 7531                    SelectionEffects::scroll(Autoscroll::newest()),
 7532                    window,
 7533                    cx,
 7534                    |selections| {
 7535                        selections.select_anchor_ranges([target..target]);
 7536                    },
 7537                );
 7538            }
 7539            EditPrediction::Edit { edits, .. } => {
 7540                // Find an insertion that starts at the cursor position.
 7541                let snapshot = self.buffer.read(cx).snapshot(cx);
 7542                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7543                let insertion = edits.iter().find_map(|(range, text)| {
 7544                    let range = range.to_offset(&snapshot);
 7545                    if range.is_empty() && range.start == cursor_offset {
 7546                        Some(text)
 7547                    } else {
 7548                        None
 7549                    }
 7550                });
 7551
 7552                if let Some(text) = insertion {
 7553                    let mut partial_completion = text
 7554                        .chars()
 7555                        .by_ref()
 7556                        .take_while(|c| c.is_alphabetic())
 7557                        .collect::<String>();
 7558                    if partial_completion.is_empty() {
 7559                        partial_completion = text
 7560                            .chars()
 7561                            .by_ref()
 7562                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7563                            .collect::<String>();
 7564                    }
 7565
 7566                    cx.emit(EditorEvent::InputHandled {
 7567                        utf16_range_to_replace: None,
 7568                        text: partial_completion.clone().into(),
 7569                    });
 7570
 7571                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7572
 7573                    self.refresh_edit_prediction(true, true, window, cx);
 7574                    cx.notify();
 7575                } else {
 7576                    self.accept_edit_prediction(&Default::default(), window, cx);
 7577                }
 7578            }
 7579        }
 7580    }
 7581
 7582    fn discard_edit_prediction(
 7583        &mut self,
 7584        should_report_edit_prediction_event: bool,
 7585        cx: &mut Context<Self>,
 7586    ) -> bool {
 7587        if should_report_edit_prediction_event {
 7588            let completion_id = self
 7589                .active_edit_prediction
 7590                .as_ref()
 7591                .and_then(|active_completion| active_completion.completion_id.clone());
 7592
 7593            self.report_edit_prediction_event(completion_id, false, cx);
 7594        }
 7595
 7596        if let Some(provider) = self.edit_prediction_provider() {
 7597            provider.discard(cx);
 7598        }
 7599
 7600        self.take_active_edit_prediction(cx)
 7601    }
 7602
 7603    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7604        let Some(provider) = self.edit_prediction_provider() else {
 7605            return;
 7606        };
 7607
 7608        let Some((_, buffer, _)) = self
 7609            .buffer
 7610            .read(cx)
 7611            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7612        else {
 7613            return;
 7614        };
 7615
 7616        let extension = buffer
 7617            .read(cx)
 7618            .file()
 7619            .and_then(|file| Some(file.path().extension()?.to_string()));
 7620
 7621        let event_type = match accepted {
 7622            true => "Edit Prediction Accepted",
 7623            false => "Edit Prediction Discarded",
 7624        };
 7625        telemetry::event!(
 7626            event_type,
 7627            provider = provider.name(),
 7628            prediction_id = id,
 7629            suggestion_accepted = accepted,
 7630            file_extension = extension,
 7631        );
 7632    }
 7633
 7634    pub fn has_active_edit_prediction(&self) -> bool {
 7635        self.active_edit_prediction.is_some()
 7636    }
 7637
 7638    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7639        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7640            return false;
 7641        };
 7642
 7643        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7644        self.clear_highlights::<EditPredictionHighlight>(cx);
 7645        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7646        true
 7647    }
 7648
 7649    /// Returns true when we're displaying the edit prediction popover below the cursor
 7650    /// like we are not previewing and the LSP autocomplete menu is visible
 7651    /// or we are in `when_holding_modifier` mode.
 7652    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7653        if self.edit_prediction_preview_is_active()
 7654            || !self.show_edit_predictions_in_menu()
 7655            || !self.edit_predictions_enabled()
 7656        {
 7657            return false;
 7658        }
 7659
 7660        if self.has_visible_completions_menu() {
 7661            return true;
 7662        }
 7663
 7664        has_completion && self.edit_prediction_requires_modifier()
 7665    }
 7666
 7667    fn handle_modifiers_changed(
 7668        &mut self,
 7669        modifiers: Modifiers,
 7670        position_map: &PositionMap,
 7671        window: &mut Window,
 7672        cx: &mut Context<Self>,
 7673    ) {
 7674        if self.show_edit_predictions_in_menu() {
 7675            self.update_edit_prediction_preview(&modifiers, window, cx);
 7676        }
 7677
 7678        self.update_selection_mode(&modifiers, position_map, window, cx);
 7679
 7680        let mouse_position = window.mouse_position();
 7681        if !position_map.text_hitbox.is_hovered(window) {
 7682            return;
 7683        }
 7684
 7685        self.update_hovered_link(
 7686            position_map.point_for_position(mouse_position),
 7687            &position_map.snapshot,
 7688            modifiers,
 7689            window,
 7690            cx,
 7691        )
 7692    }
 7693
 7694    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7695        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7696        if invert {
 7697            match multi_cursor_setting {
 7698                MultiCursorModifier::Alt => modifiers.alt,
 7699                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7700            }
 7701        } else {
 7702            match multi_cursor_setting {
 7703                MultiCursorModifier::Alt => modifiers.secondary(),
 7704                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7705            }
 7706        }
 7707    }
 7708
 7709    fn columnar_selection_mode(
 7710        modifiers: &Modifiers,
 7711        cx: &mut Context<Self>,
 7712    ) -> Option<ColumnarMode> {
 7713        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7714            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7715                Some(ColumnarMode::FromMouse)
 7716            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7717                Some(ColumnarMode::FromSelection)
 7718            } else {
 7719                None
 7720            }
 7721        } else {
 7722            None
 7723        }
 7724    }
 7725
 7726    fn update_selection_mode(
 7727        &mut self,
 7728        modifiers: &Modifiers,
 7729        position_map: &PositionMap,
 7730        window: &mut Window,
 7731        cx: &mut Context<Self>,
 7732    ) {
 7733        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7734            return;
 7735        };
 7736        if self.selections.pending_anchor().is_none() {
 7737            return;
 7738        }
 7739
 7740        let mouse_position = window.mouse_position();
 7741        let point_for_position = position_map.point_for_position(mouse_position);
 7742        let position = point_for_position.previous_valid;
 7743
 7744        self.select(
 7745            SelectPhase::BeginColumnar {
 7746                position,
 7747                reset: false,
 7748                mode,
 7749                goal_column: point_for_position.exact_unclipped.column(),
 7750            },
 7751            window,
 7752            cx,
 7753        );
 7754    }
 7755
 7756    fn update_edit_prediction_preview(
 7757        &mut self,
 7758        modifiers: &Modifiers,
 7759        window: &mut Window,
 7760        cx: &mut Context<Self>,
 7761    ) {
 7762        let mut modifiers_held = false;
 7763        if let Some(accept_keystroke) = self
 7764            .accept_edit_prediction_keybind(false, window, cx)
 7765            .keystroke()
 7766        {
 7767            modifiers_held = modifiers_held
 7768                || (accept_keystroke.modifiers() == modifiers
 7769                    && accept_keystroke.modifiers().modified());
 7770        };
 7771        if let Some(accept_partial_keystroke) = self
 7772            .accept_edit_prediction_keybind(true, window, cx)
 7773            .keystroke()
 7774        {
 7775            modifiers_held = modifiers_held
 7776                || (accept_partial_keystroke.modifiers() == modifiers
 7777                    && accept_partial_keystroke.modifiers().modified());
 7778        }
 7779
 7780        if modifiers_held {
 7781            if matches!(
 7782                self.edit_prediction_preview,
 7783                EditPredictionPreview::Inactive { .. }
 7784            ) {
 7785                self.edit_prediction_preview = EditPredictionPreview::Active {
 7786                    previous_scroll_position: None,
 7787                    since: Instant::now(),
 7788                };
 7789
 7790                self.update_visible_edit_prediction(window, cx);
 7791                cx.notify();
 7792            }
 7793        } else if let EditPredictionPreview::Active {
 7794            previous_scroll_position,
 7795            since,
 7796        } = self.edit_prediction_preview
 7797        {
 7798            if let (Some(previous_scroll_position), Some(position_map)) =
 7799                (previous_scroll_position, self.last_position_map.as_ref())
 7800            {
 7801                self.set_scroll_position(
 7802                    previous_scroll_position
 7803                        .scroll_position(&position_map.snapshot.display_snapshot),
 7804                    window,
 7805                    cx,
 7806                );
 7807            }
 7808
 7809            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7810                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7811            };
 7812            self.clear_row_highlights::<EditPredictionPreview>();
 7813            self.update_visible_edit_prediction(window, cx);
 7814            cx.notify();
 7815        }
 7816    }
 7817
 7818    fn update_visible_edit_prediction(
 7819        &mut self,
 7820        _window: &mut Window,
 7821        cx: &mut Context<Self>,
 7822    ) -> Option<()> {
 7823        if DisableAiSettings::get_global(cx).disable_ai {
 7824            return None;
 7825        }
 7826
 7827        if self.ime_transaction.is_some() {
 7828            self.discard_edit_prediction(false, cx);
 7829            return None;
 7830        }
 7831
 7832        let selection = self.selections.newest_anchor();
 7833        let cursor = selection.head();
 7834        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7835        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7836        let excerpt_id = cursor.excerpt_id;
 7837
 7838        let show_in_menu = self.show_edit_predictions_in_menu();
 7839        let completions_menu_has_precedence = !show_in_menu
 7840            && (self.context_menu.borrow().is_some()
 7841                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7842
 7843        if completions_menu_has_precedence
 7844            || !offset_selection.is_empty()
 7845            || self
 7846                .active_edit_prediction
 7847                .as_ref()
 7848                .is_some_and(|completion| {
 7849                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7850                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7851                    !invalidation_range.contains(&offset_selection.head())
 7852                })
 7853        {
 7854            self.discard_edit_prediction(false, cx);
 7855            return None;
 7856        }
 7857
 7858        self.take_active_edit_prediction(cx);
 7859        let Some(provider) = self.edit_prediction_provider() else {
 7860            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7861            return None;
 7862        };
 7863
 7864        let (buffer, cursor_buffer_position) =
 7865            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7866
 7867        self.edit_prediction_settings =
 7868            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7869
 7870        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7871
 7872        if self.edit_prediction_indent_conflict {
 7873            let cursor_point = cursor.to_point(&multibuffer);
 7874
 7875            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7876
 7877            if let Some((_, indent)) = indents.iter().next()
 7878                && indent.len == cursor_point.column
 7879            {
 7880                self.edit_prediction_indent_conflict = false;
 7881            }
 7882        }
 7883
 7884        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7885        let edits = edit_prediction
 7886            .edits
 7887            .into_iter()
 7888            .flat_map(|(range, new_text)| {
 7889                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7890                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7891                Some((start..end, new_text))
 7892            })
 7893            .collect::<Vec<_>>();
 7894        if edits.is_empty() {
 7895            return None;
 7896        }
 7897
 7898        let first_edit_start = edits.first().unwrap().0.start;
 7899        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7900        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7901
 7902        let last_edit_end = edits.last().unwrap().0.end;
 7903        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7904        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7905
 7906        let cursor_row = cursor.to_point(&multibuffer).row;
 7907
 7908        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7909
 7910        let mut inlay_ids = Vec::new();
 7911        let invalidation_row_range;
 7912        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7913            Some(cursor_row..edit_end_row)
 7914        } else if cursor_row > edit_end_row {
 7915            Some(edit_start_row..cursor_row)
 7916        } else {
 7917            None
 7918        };
 7919        let supports_jump = self
 7920            .edit_prediction_provider
 7921            .as_ref()
 7922            .map(|provider| provider.provider.supports_jump_to_edit())
 7923            .unwrap_or(true);
 7924
 7925        let is_move = supports_jump
 7926            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7927        let completion = if is_move {
 7928            invalidation_row_range =
 7929                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7930            let target = first_edit_start;
 7931            EditPrediction::Move { target, snapshot }
 7932        } else {
 7933            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7934                && !self.edit_predictions_hidden_for_vim_mode;
 7935
 7936            if show_completions_in_buffer {
 7937                if edits
 7938                    .iter()
 7939                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7940                {
 7941                    let mut inlays = Vec::new();
 7942                    for (range, new_text) in &edits {
 7943                        let inlay = Inlay::edit_prediction(
 7944                            post_inc(&mut self.next_inlay_id),
 7945                            range.start,
 7946                            new_text.as_str(),
 7947                        );
 7948                        inlay_ids.push(inlay.id);
 7949                        inlays.push(inlay);
 7950                    }
 7951
 7952                    self.splice_inlays(&[], inlays, cx);
 7953                } else {
 7954                    let background_color = cx.theme().status().deleted_background;
 7955                    self.highlight_text::<EditPredictionHighlight>(
 7956                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7957                        HighlightStyle {
 7958                            background_color: Some(background_color),
 7959                            ..Default::default()
 7960                        },
 7961                        cx,
 7962                    );
 7963                }
 7964            }
 7965
 7966            invalidation_row_range = edit_start_row..edit_end_row;
 7967
 7968            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7969                if provider.show_tab_accept_marker() {
 7970                    EditDisplayMode::TabAccept
 7971                } else {
 7972                    EditDisplayMode::Inline
 7973                }
 7974            } else {
 7975                EditDisplayMode::DiffPopover
 7976            };
 7977
 7978            EditPrediction::Edit {
 7979                edits,
 7980                edit_preview: edit_prediction.edit_preview,
 7981                display_mode,
 7982                snapshot,
 7983            }
 7984        };
 7985
 7986        let invalidation_range = multibuffer
 7987            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7988            ..multibuffer.anchor_after(Point::new(
 7989                invalidation_row_range.end,
 7990                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7991            ));
 7992
 7993        self.stale_edit_prediction_in_menu = None;
 7994        self.active_edit_prediction = Some(EditPredictionState {
 7995            inlay_ids,
 7996            completion,
 7997            completion_id: edit_prediction.id,
 7998            invalidation_range,
 7999        });
 8000
 8001        cx.notify();
 8002
 8003        Some(())
 8004    }
 8005
 8006    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8007        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8008    }
 8009
 8010    fn clear_tasks(&mut self) {
 8011        self.tasks.clear()
 8012    }
 8013
 8014    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8015        if self.tasks.insert(key, value).is_some() {
 8016            // This case should hopefully be rare, but just in case...
 8017            log::error!(
 8018                "multiple different run targets found on a single line, only the last target will be rendered"
 8019            )
 8020        }
 8021    }
 8022
 8023    /// Get all display points of breakpoints that will be rendered within editor
 8024    ///
 8025    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8026    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8027    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8028    fn active_breakpoints(
 8029        &self,
 8030        range: Range<DisplayRow>,
 8031        window: &mut Window,
 8032        cx: &mut Context<Self>,
 8033    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8034        let mut breakpoint_display_points = HashMap::default();
 8035
 8036        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8037            return breakpoint_display_points;
 8038        };
 8039
 8040        let snapshot = self.snapshot(window, cx);
 8041
 8042        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8043        let Some(project) = self.project() else {
 8044            return breakpoint_display_points;
 8045        };
 8046
 8047        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8048            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8049
 8050        for (buffer_snapshot, range, excerpt_id) in
 8051            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8052        {
 8053            let Some(buffer) = project
 8054                .read(cx)
 8055                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8056            else {
 8057                continue;
 8058            };
 8059            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8060                &buffer,
 8061                Some(
 8062                    buffer_snapshot.anchor_before(range.start)
 8063                        ..buffer_snapshot.anchor_after(range.end),
 8064                ),
 8065                buffer_snapshot,
 8066                cx,
 8067            );
 8068            for (breakpoint, state) in breakpoints {
 8069                let multi_buffer_anchor =
 8070                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8071                let position = multi_buffer_anchor
 8072                    .to_point(multi_buffer_snapshot)
 8073                    .to_display_point(&snapshot);
 8074
 8075                breakpoint_display_points.insert(
 8076                    position.row(),
 8077                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8078                );
 8079            }
 8080        }
 8081
 8082        breakpoint_display_points
 8083    }
 8084
 8085    fn breakpoint_context_menu(
 8086        &self,
 8087        anchor: Anchor,
 8088        window: &mut Window,
 8089        cx: &mut Context<Self>,
 8090    ) -> Entity<ui::ContextMenu> {
 8091        let weak_editor = cx.weak_entity();
 8092        let focus_handle = self.focus_handle(cx);
 8093
 8094        let row = self
 8095            .buffer
 8096            .read(cx)
 8097            .snapshot(cx)
 8098            .summary_for_anchor::<Point>(&anchor)
 8099            .row;
 8100
 8101        let breakpoint = self
 8102            .breakpoint_at_row(row, window, cx)
 8103            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8104
 8105        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8106            "Edit Log Breakpoint"
 8107        } else {
 8108            "Set Log Breakpoint"
 8109        };
 8110
 8111        let condition_breakpoint_msg = if breakpoint
 8112            .as_ref()
 8113            .is_some_and(|bp| bp.1.condition.is_some())
 8114        {
 8115            "Edit Condition Breakpoint"
 8116        } else {
 8117            "Set Condition Breakpoint"
 8118        };
 8119
 8120        let hit_condition_breakpoint_msg = if breakpoint
 8121            .as_ref()
 8122            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8123        {
 8124            "Edit Hit Condition Breakpoint"
 8125        } else {
 8126            "Set Hit Condition Breakpoint"
 8127        };
 8128
 8129        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8130            "Unset Breakpoint"
 8131        } else {
 8132            "Set Breakpoint"
 8133        };
 8134
 8135        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8136
 8137        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8138            BreakpointState::Enabled => Some("Disable"),
 8139            BreakpointState::Disabled => Some("Enable"),
 8140        });
 8141
 8142        let (anchor, breakpoint) =
 8143            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8144
 8145        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8146            menu.on_blur_subscription(Subscription::new(|| {}))
 8147                .context(focus_handle)
 8148                .when(run_to_cursor, |this| {
 8149                    let weak_editor = weak_editor.clone();
 8150                    this.entry("Run to cursor", None, move |window, cx| {
 8151                        weak_editor
 8152                            .update(cx, |editor, cx| {
 8153                                editor.change_selections(
 8154                                    SelectionEffects::no_scroll(),
 8155                                    window,
 8156                                    cx,
 8157                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8158                                );
 8159                            })
 8160                            .ok();
 8161
 8162                        window.dispatch_action(Box::new(RunToCursor), cx);
 8163                    })
 8164                    .separator()
 8165                })
 8166                .when_some(toggle_state_msg, |this, msg| {
 8167                    this.entry(msg, None, {
 8168                        let weak_editor = weak_editor.clone();
 8169                        let breakpoint = breakpoint.clone();
 8170                        move |_window, cx| {
 8171                            weak_editor
 8172                                .update(cx, |this, cx| {
 8173                                    this.edit_breakpoint_at_anchor(
 8174                                        anchor,
 8175                                        breakpoint.as_ref().clone(),
 8176                                        BreakpointEditAction::InvertState,
 8177                                        cx,
 8178                                    );
 8179                                })
 8180                                .log_err();
 8181                        }
 8182                    })
 8183                })
 8184                .entry(set_breakpoint_msg, None, {
 8185                    let weak_editor = weak_editor.clone();
 8186                    let breakpoint = breakpoint.clone();
 8187                    move |_window, cx| {
 8188                        weak_editor
 8189                            .update(cx, |this, cx| {
 8190                                this.edit_breakpoint_at_anchor(
 8191                                    anchor,
 8192                                    breakpoint.as_ref().clone(),
 8193                                    BreakpointEditAction::Toggle,
 8194                                    cx,
 8195                                );
 8196                            })
 8197                            .log_err();
 8198                    }
 8199                })
 8200                .entry(log_breakpoint_msg, None, {
 8201                    let breakpoint = breakpoint.clone();
 8202                    let weak_editor = weak_editor.clone();
 8203                    move |window, cx| {
 8204                        weak_editor
 8205                            .update(cx, |this, cx| {
 8206                                this.add_edit_breakpoint_block(
 8207                                    anchor,
 8208                                    breakpoint.as_ref(),
 8209                                    BreakpointPromptEditAction::Log,
 8210                                    window,
 8211                                    cx,
 8212                                );
 8213                            })
 8214                            .log_err();
 8215                    }
 8216                })
 8217                .entry(condition_breakpoint_msg, None, {
 8218                    let breakpoint = breakpoint.clone();
 8219                    let weak_editor = weak_editor.clone();
 8220                    move |window, cx| {
 8221                        weak_editor
 8222                            .update(cx, |this, cx| {
 8223                                this.add_edit_breakpoint_block(
 8224                                    anchor,
 8225                                    breakpoint.as_ref(),
 8226                                    BreakpointPromptEditAction::Condition,
 8227                                    window,
 8228                                    cx,
 8229                                );
 8230                            })
 8231                            .log_err();
 8232                    }
 8233                })
 8234                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8235                    weak_editor
 8236                        .update(cx, |this, cx| {
 8237                            this.add_edit_breakpoint_block(
 8238                                anchor,
 8239                                breakpoint.as_ref(),
 8240                                BreakpointPromptEditAction::HitCondition,
 8241                                window,
 8242                                cx,
 8243                            );
 8244                        })
 8245                        .log_err();
 8246                })
 8247        })
 8248    }
 8249
 8250    fn render_breakpoint(
 8251        &self,
 8252        position: Anchor,
 8253        row: DisplayRow,
 8254        breakpoint: &Breakpoint,
 8255        state: Option<BreakpointSessionState>,
 8256        cx: &mut Context<Self>,
 8257    ) -> IconButton {
 8258        let is_rejected = state.is_some_and(|s| !s.verified);
 8259        // Is it a breakpoint that shows up when hovering over gutter?
 8260        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8261            (false, false),
 8262            |PhantomBreakpointIndicator {
 8263                 is_active,
 8264                 display_row,
 8265                 collides_with_existing_breakpoint,
 8266             }| {
 8267                (
 8268                    is_active && display_row == row,
 8269                    collides_with_existing_breakpoint,
 8270                )
 8271            },
 8272        );
 8273
 8274        let (color, icon) = {
 8275            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8276                (false, false) => ui::IconName::DebugBreakpoint,
 8277                (true, false) => ui::IconName::DebugLogBreakpoint,
 8278                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8279                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8280            };
 8281
 8282            let color = if is_phantom {
 8283                Color::Hint
 8284            } else if is_rejected {
 8285                Color::Disabled
 8286            } else {
 8287                Color::Debugger
 8288            };
 8289
 8290            (color, icon)
 8291        };
 8292
 8293        let breakpoint = Arc::from(breakpoint.clone());
 8294
 8295        let alt_as_text = gpui::Keystroke {
 8296            modifiers: Modifiers::secondary_key(),
 8297            ..Default::default()
 8298        };
 8299        let primary_action_text = if breakpoint.is_disabled() {
 8300            "Enable breakpoint"
 8301        } else if is_phantom && !collides_with_existing {
 8302            "Set breakpoint"
 8303        } else {
 8304            "Unset breakpoint"
 8305        };
 8306        let focus_handle = self.focus_handle.clone();
 8307
 8308        let meta = if is_rejected {
 8309            SharedString::from("No executable code is associated with this line.")
 8310        } else if collides_with_existing && !breakpoint.is_disabled() {
 8311            SharedString::from(format!(
 8312                "{alt_as_text}-click to disable,\nright-click for more options."
 8313            ))
 8314        } else {
 8315            SharedString::from("Right-click for more options.")
 8316        };
 8317        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8318            .icon_size(IconSize::XSmall)
 8319            .size(ui::ButtonSize::None)
 8320            .when(is_rejected, |this| {
 8321                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8322            })
 8323            .icon_color(color)
 8324            .style(ButtonStyle::Transparent)
 8325            .on_click(cx.listener({
 8326                move |editor, event: &ClickEvent, window, cx| {
 8327                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8328                        BreakpointEditAction::InvertState
 8329                    } else {
 8330                        BreakpointEditAction::Toggle
 8331                    };
 8332
 8333                    window.focus(&editor.focus_handle(cx));
 8334                    editor.edit_breakpoint_at_anchor(
 8335                        position,
 8336                        breakpoint.as_ref().clone(),
 8337                        edit_action,
 8338                        cx,
 8339                    );
 8340                }
 8341            }))
 8342            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8343                editor.set_breakpoint_context_menu(
 8344                    row,
 8345                    Some(position),
 8346                    event.position(),
 8347                    window,
 8348                    cx,
 8349                );
 8350            }))
 8351            .tooltip(move |window, cx| {
 8352                Tooltip::with_meta_in(
 8353                    primary_action_text,
 8354                    Some(&ToggleBreakpoint),
 8355                    meta.clone(),
 8356                    &focus_handle,
 8357                    window,
 8358                    cx,
 8359                )
 8360            })
 8361    }
 8362
 8363    fn build_tasks_context(
 8364        project: &Entity<Project>,
 8365        buffer: &Entity<Buffer>,
 8366        buffer_row: u32,
 8367        tasks: &Arc<RunnableTasks>,
 8368        cx: &mut Context<Self>,
 8369    ) -> Task<Option<task::TaskContext>> {
 8370        let position = Point::new(buffer_row, tasks.column);
 8371        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8372        let location = Location {
 8373            buffer: buffer.clone(),
 8374            range: range_start..range_start,
 8375        };
 8376        // Fill in the environmental variables from the tree-sitter captures
 8377        let mut captured_task_variables = TaskVariables::default();
 8378        for (capture_name, value) in tasks.extra_variables.clone() {
 8379            captured_task_variables.insert(
 8380                task::VariableName::Custom(capture_name.into()),
 8381                value.clone(),
 8382            );
 8383        }
 8384        project.update(cx, |project, cx| {
 8385            project.task_store().update(cx, |task_store, cx| {
 8386                task_store.task_context_for_location(captured_task_variables, location, cx)
 8387            })
 8388        })
 8389    }
 8390
 8391    pub fn spawn_nearest_task(
 8392        &mut self,
 8393        action: &SpawnNearestTask,
 8394        window: &mut Window,
 8395        cx: &mut Context<Self>,
 8396    ) {
 8397        let Some((workspace, _)) = self.workspace.clone() else {
 8398            return;
 8399        };
 8400        let Some(project) = self.project.clone() else {
 8401            return;
 8402        };
 8403
 8404        // Try to find a closest, enclosing node using tree-sitter that has a task
 8405        let Some((buffer, buffer_row, tasks)) = self
 8406            .find_enclosing_node_task(cx)
 8407            // Or find the task that's closest in row-distance.
 8408            .or_else(|| self.find_closest_task(cx))
 8409        else {
 8410            return;
 8411        };
 8412
 8413        let reveal_strategy = action.reveal;
 8414        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8415        cx.spawn_in(window, async move |_, cx| {
 8416            let context = task_context.await?;
 8417            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8418
 8419            let resolved = &mut resolved_task.resolved;
 8420            resolved.reveal = reveal_strategy;
 8421
 8422            workspace
 8423                .update_in(cx, |workspace, window, cx| {
 8424                    workspace.schedule_resolved_task(
 8425                        task_source_kind,
 8426                        resolved_task,
 8427                        false,
 8428                        window,
 8429                        cx,
 8430                    );
 8431                })
 8432                .ok()
 8433        })
 8434        .detach();
 8435    }
 8436
 8437    fn find_closest_task(
 8438        &mut self,
 8439        cx: &mut Context<Self>,
 8440    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8441        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8442
 8443        let ((buffer_id, row), tasks) = self
 8444            .tasks
 8445            .iter()
 8446            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8447
 8448        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8449        let tasks = Arc::new(tasks.to_owned());
 8450        Some((buffer, *row, tasks))
 8451    }
 8452
 8453    fn find_enclosing_node_task(
 8454        &mut self,
 8455        cx: &mut Context<Self>,
 8456    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8457        let snapshot = self.buffer.read(cx).snapshot(cx);
 8458        let offset = self.selections.newest::<usize>(cx).head();
 8459        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8460        let buffer_id = excerpt.buffer().remote_id();
 8461
 8462        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8463        let mut cursor = layer.node().walk();
 8464
 8465        while cursor.goto_first_child_for_byte(offset).is_some() {
 8466            if cursor.node().end_byte() == offset {
 8467                cursor.goto_next_sibling();
 8468            }
 8469        }
 8470
 8471        // Ascend to the smallest ancestor that contains the range and has a task.
 8472        loop {
 8473            let node = cursor.node();
 8474            let node_range = node.byte_range();
 8475            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8476
 8477            // Check if this node contains our offset
 8478            if node_range.start <= offset && node_range.end >= offset {
 8479                // If it contains offset, check for task
 8480                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8481                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8482                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8483                }
 8484            }
 8485
 8486            if !cursor.goto_parent() {
 8487                break;
 8488            }
 8489        }
 8490        None
 8491    }
 8492
 8493    fn render_run_indicator(
 8494        &self,
 8495        _style: &EditorStyle,
 8496        is_active: bool,
 8497        row: DisplayRow,
 8498        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8499        cx: &mut Context<Self>,
 8500    ) -> IconButton {
 8501        let color = Color::Muted;
 8502        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8503
 8504        IconButton::new(
 8505            ("run_indicator", row.0 as usize),
 8506            ui::IconName::PlayOutlined,
 8507        )
 8508        .shape(ui::IconButtonShape::Square)
 8509        .icon_size(IconSize::XSmall)
 8510        .icon_color(color)
 8511        .toggle_state(is_active)
 8512        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8513            let quick_launch = match e {
 8514                ClickEvent::Keyboard(_) => true,
 8515                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8516            };
 8517
 8518            window.focus(&editor.focus_handle(cx));
 8519            editor.toggle_code_actions(
 8520                &ToggleCodeActions {
 8521                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8522                    quick_launch,
 8523                },
 8524                window,
 8525                cx,
 8526            );
 8527        }))
 8528        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8529            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8530        }))
 8531    }
 8532
 8533    pub fn context_menu_visible(&self) -> bool {
 8534        !self.edit_prediction_preview_is_active()
 8535            && self
 8536                .context_menu
 8537                .borrow()
 8538                .as_ref()
 8539                .is_some_and(|menu| menu.visible())
 8540    }
 8541
 8542    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8543        self.context_menu
 8544            .borrow()
 8545            .as_ref()
 8546            .map(|menu| menu.origin())
 8547    }
 8548
 8549    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8550        self.context_menu_options = Some(options);
 8551    }
 8552
 8553    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8554    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8555
 8556    fn render_edit_prediction_popover(
 8557        &mut self,
 8558        text_bounds: &Bounds<Pixels>,
 8559        content_origin: gpui::Point<Pixels>,
 8560        right_margin: Pixels,
 8561        editor_snapshot: &EditorSnapshot,
 8562        visible_row_range: Range<DisplayRow>,
 8563        scroll_top: f32,
 8564        scroll_bottom: f32,
 8565        line_layouts: &[LineWithInvisibles],
 8566        line_height: Pixels,
 8567        scroll_pixel_position: gpui::Point<Pixels>,
 8568        newest_selection_head: Option<DisplayPoint>,
 8569        editor_width: Pixels,
 8570        style: &EditorStyle,
 8571        window: &mut Window,
 8572        cx: &mut App,
 8573    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8574        if self.mode().is_minimap() {
 8575            return None;
 8576        }
 8577        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8578
 8579        if self.edit_prediction_visible_in_cursor_popover(true) {
 8580            return None;
 8581        }
 8582
 8583        match &active_edit_prediction.completion {
 8584            EditPrediction::Move { target, .. } => {
 8585                let target_display_point = target.to_display_point(editor_snapshot);
 8586
 8587                if self.edit_prediction_requires_modifier() {
 8588                    if !self.edit_prediction_preview_is_active() {
 8589                        return None;
 8590                    }
 8591
 8592                    self.render_edit_prediction_modifier_jump_popover(
 8593                        text_bounds,
 8594                        content_origin,
 8595                        visible_row_range,
 8596                        line_layouts,
 8597                        line_height,
 8598                        scroll_pixel_position,
 8599                        newest_selection_head,
 8600                        target_display_point,
 8601                        window,
 8602                        cx,
 8603                    )
 8604                } else {
 8605                    self.render_edit_prediction_eager_jump_popover(
 8606                        text_bounds,
 8607                        content_origin,
 8608                        editor_snapshot,
 8609                        visible_row_range,
 8610                        scroll_top,
 8611                        scroll_bottom,
 8612                        line_height,
 8613                        scroll_pixel_position,
 8614                        target_display_point,
 8615                        editor_width,
 8616                        window,
 8617                        cx,
 8618                    )
 8619                }
 8620            }
 8621            EditPrediction::Edit {
 8622                display_mode: EditDisplayMode::Inline,
 8623                ..
 8624            } => None,
 8625            EditPrediction::Edit {
 8626                display_mode: EditDisplayMode::TabAccept,
 8627                edits,
 8628                ..
 8629            } => {
 8630                let range = &edits.first()?.0;
 8631                let target_display_point = range.end.to_display_point(editor_snapshot);
 8632
 8633                self.render_edit_prediction_end_of_line_popover(
 8634                    "Accept",
 8635                    editor_snapshot,
 8636                    visible_row_range,
 8637                    target_display_point,
 8638                    line_height,
 8639                    scroll_pixel_position,
 8640                    content_origin,
 8641                    editor_width,
 8642                    window,
 8643                    cx,
 8644                )
 8645            }
 8646            EditPrediction::Edit {
 8647                edits,
 8648                edit_preview,
 8649                display_mode: EditDisplayMode::DiffPopover,
 8650                snapshot,
 8651            } => self.render_edit_prediction_diff_popover(
 8652                text_bounds,
 8653                content_origin,
 8654                right_margin,
 8655                editor_snapshot,
 8656                visible_row_range,
 8657                line_layouts,
 8658                line_height,
 8659                scroll_pixel_position,
 8660                newest_selection_head,
 8661                editor_width,
 8662                style,
 8663                edits,
 8664                edit_preview,
 8665                snapshot,
 8666                window,
 8667                cx,
 8668            ),
 8669        }
 8670    }
 8671
 8672    fn render_edit_prediction_modifier_jump_popover(
 8673        &mut self,
 8674        text_bounds: &Bounds<Pixels>,
 8675        content_origin: gpui::Point<Pixels>,
 8676        visible_row_range: Range<DisplayRow>,
 8677        line_layouts: &[LineWithInvisibles],
 8678        line_height: Pixels,
 8679        scroll_pixel_position: gpui::Point<Pixels>,
 8680        newest_selection_head: Option<DisplayPoint>,
 8681        target_display_point: DisplayPoint,
 8682        window: &mut Window,
 8683        cx: &mut App,
 8684    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8685        let scrolled_content_origin =
 8686            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8687
 8688        const SCROLL_PADDING_Y: Pixels = px(12.);
 8689
 8690        if target_display_point.row() < visible_row_range.start {
 8691            return self.render_edit_prediction_scroll_popover(
 8692                |_| SCROLL_PADDING_Y,
 8693                IconName::ArrowUp,
 8694                visible_row_range,
 8695                line_layouts,
 8696                newest_selection_head,
 8697                scrolled_content_origin,
 8698                window,
 8699                cx,
 8700            );
 8701        } else if target_display_point.row() >= visible_row_range.end {
 8702            return self.render_edit_prediction_scroll_popover(
 8703                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8704                IconName::ArrowDown,
 8705                visible_row_range,
 8706                line_layouts,
 8707                newest_selection_head,
 8708                scrolled_content_origin,
 8709                window,
 8710                cx,
 8711            );
 8712        }
 8713
 8714        const POLE_WIDTH: Pixels = px(2.);
 8715
 8716        let line_layout =
 8717            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8718        let target_column = target_display_point.column() as usize;
 8719
 8720        let target_x = line_layout.x_for_index(target_column);
 8721        let target_y =
 8722            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8723
 8724        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8725
 8726        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8727        border_color.l += 0.001;
 8728
 8729        let mut element = v_flex()
 8730            .items_end()
 8731            .when(flag_on_right, |el| el.items_start())
 8732            .child(if flag_on_right {
 8733                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8734                    .rounded_bl(px(0.))
 8735                    .rounded_tl(px(0.))
 8736                    .border_l_2()
 8737                    .border_color(border_color)
 8738            } else {
 8739                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8740                    .rounded_br(px(0.))
 8741                    .rounded_tr(px(0.))
 8742                    .border_r_2()
 8743                    .border_color(border_color)
 8744            })
 8745            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8746            .into_any();
 8747
 8748        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8749
 8750        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8751            - point(
 8752                if flag_on_right {
 8753                    POLE_WIDTH
 8754                } else {
 8755                    size.width - POLE_WIDTH
 8756                },
 8757                size.height - line_height,
 8758            );
 8759
 8760        origin.x = origin.x.max(content_origin.x);
 8761
 8762        element.prepaint_at(origin, window, cx);
 8763
 8764        Some((element, origin))
 8765    }
 8766
 8767    fn render_edit_prediction_scroll_popover(
 8768        &mut self,
 8769        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8770        scroll_icon: IconName,
 8771        visible_row_range: Range<DisplayRow>,
 8772        line_layouts: &[LineWithInvisibles],
 8773        newest_selection_head: Option<DisplayPoint>,
 8774        scrolled_content_origin: gpui::Point<Pixels>,
 8775        window: &mut Window,
 8776        cx: &mut App,
 8777    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8778        let mut element = self
 8779            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8780            .into_any();
 8781
 8782        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8783
 8784        let cursor = newest_selection_head?;
 8785        let cursor_row_layout =
 8786            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8787        let cursor_column = cursor.column() as usize;
 8788
 8789        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8790
 8791        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8792
 8793        element.prepaint_at(origin, window, cx);
 8794        Some((element, origin))
 8795    }
 8796
 8797    fn render_edit_prediction_eager_jump_popover(
 8798        &mut self,
 8799        text_bounds: &Bounds<Pixels>,
 8800        content_origin: gpui::Point<Pixels>,
 8801        editor_snapshot: &EditorSnapshot,
 8802        visible_row_range: Range<DisplayRow>,
 8803        scroll_top: f32,
 8804        scroll_bottom: f32,
 8805        line_height: Pixels,
 8806        scroll_pixel_position: gpui::Point<Pixels>,
 8807        target_display_point: DisplayPoint,
 8808        editor_width: Pixels,
 8809        window: &mut Window,
 8810        cx: &mut App,
 8811    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8812        if target_display_point.row().as_f32() < scroll_top {
 8813            let mut element = self
 8814                .render_edit_prediction_line_popover(
 8815                    "Jump to Edit",
 8816                    Some(IconName::ArrowUp),
 8817                    window,
 8818                    cx,
 8819                )?
 8820                .into_any();
 8821
 8822            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8823            let offset = point(
 8824                (text_bounds.size.width - size.width) / 2.,
 8825                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8826            );
 8827
 8828            let origin = text_bounds.origin + offset;
 8829            element.prepaint_at(origin, window, cx);
 8830            Some((element, origin))
 8831        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8832            let mut element = self
 8833                .render_edit_prediction_line_popover(
 8834                    "Jump to Edit",
 8835                    Some(IconName::ArrowDown),
 8836                    window,
 8837                    cx,
 8838                )?
 8839                .into_any();
 8840
 8841            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8842            let offset = point(
 8843                (text_bounds.size.width - size.width) / 2.,
 8844                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8845            );
 8846
 8847            let origin = text_bounds.origin + offset;
 8848            element.prepaint_at(origin, window, cx);
 8849            Some((element, origin))
 8850        } else {
 8851            self.render_edit_prediction_end_of_line_popover(
 8852                "Jump to Edit",
 8853                editor_snapshot,
 8854                visible_row_range,
 8855                target_display_point,
 8856                line_height,
 8857                scroll_pixel_position,
 8858                content_origin,
 8859                editor_width,
 8860                window,
 8861                cx,
 8862            )
 8863        }
 8864    }
 8865
 8866    fn render_edit_prediction_end_of_line_popover(
 8867        self: &mut Editor,
 8868        label: &'static str,
 8869        editor_snapshot: &EditorSnapshot,
 8870        visible_row_range: Range<DisplayRow>,
 8871        target_display_point: DisplayPoint,
 8872        line_height: Pixels,
 8873        scroll_pixel_position: gpui::Point<Pixels>,
 8874        content_origin: gpui::Point<Pixels>,
 8875        editor_width: Pixels,
 8876        window: &mut Window,
 8877        cx: &mut App,
 8878    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8879        let target_line_end = DisplayPoint::new(
 8880            target_display_point.row(),
 8881            editor_snapshot.line_len(target_display_point.row()),
 8882        );
 8883
 8884        let mut element = self
 8885            .render_edit_prediction_line_popover(label, None, window, cx)?
 8886            .into_any();
 8887
 8888        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8889
 8890        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8891
 8892        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8893        let mut origin = start_point
 8894            + line_origin
 8895            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8896        origin.x = origin.x.max(content_origin.x);
 8897
 8898        let max_x = content_origin.x + editor_width - size.width;
 8899
 8900        if origin.x > max_x {
 8901            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8902
 8903            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8904                origin.y += offset;
 8905                IconName::ArrowUp
 8906            } else {
 8907                origin.y -= offset;
 8908                IconName::ArrowDown
 8909            };
 8910
 8911            element = self
 8912                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8913                .into_any();
 8914
 8915            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8916
 8917            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8918        }
 8919
 8920        element.prepaint_at(origin, window, cx);
 8921        Some((element, origin))
 8922    }
 8923
 8924    fn render_edit_prediction_diff_popover(
 8925        self: &Editor,
 8926        text_bounds: &Bounds<Pixels>,
 8927        content_origin: gpui::Point<Pixels>,
 8928        right_margin: Pixels,
 8929        editor_snapshot: &EditorSnapshot,
 8930        visible_row_range: Range<DisplayRow>,
 8931        line_layouts: &[LineWithInvisibles],
 8932        line_height: Pixels,
 8933        scroll_pixel_position: gpui::Point<Pixels>,
 8934        newest_selection_head: Option<DisplayPoint>,
 8935        editor_width: Pixels,
 8936        style: &EditorStyle,
 8937        edits: &Vec<(Range<Anchor>, String)>,
 8938        edit_preview: &Option<language::EditPreview>,
 8939        snapshot: &language::BufferSnapshot,
 8940        window: &mut Window,
 8941        cx: &mut App,
 8942    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8943        let edit_start = edits
 8944            .first()
 8945            .unwrap()
 8946            .0
 8947            .start
 8948            .to_display_point(editor_snapshot);
 8949        let edit_end = edits
 8950            .last()
 8951            .unwrap()
 8952            .0
 8953            .end
 8954            .to_display_point(editor_snapshot);
 8955
 8956        let is_visible = visible_row_range.contains(&edit_start.row())
 8957            || visible_row_range.contains(&edit_end.row());
 8958        if !is_visible {
 8959            return None;
 8960        }
 8961
 8962        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8963            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8964        } else {
 8965            // Fallback for providers without edit_preview
 8966            crate::edit_prediction_fallback_text(edits, cx)
 8967        };
 8968
 8969        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8970        let line_count = highlighted_edits.text.lines().count();
 8971
 8972        const BORDER_WIDTH: Pixels = px(1.);
 8973
 8974        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8975        let has_keybind = keybind.is_some();
 8976
 8977        let mut element = h_flex()
 8978            .items_start()
 8979            .child(
 8980                h_flex()
 8981                    .bg(cx.theme().colors().editor_background)
 8982                    .border(BORDER_WIDTH)
 8983                    .shadow_xs()
 8984                    .border_color(cx.theme().colors().border)
 8985                    .rounded_l_lg()
 8986                    .when(line_count > 1, |el| el.rounded_br_lg())
 8987                    .pr_1()
 8988                    .child(styled_text),
 8989            )
 8990            .child(
 8991                h_flex()
 8992                    .h(line_height + BORDER_WIDTH * 2.)
 8993                    .px_1p5()
 8994                    .gap_1()
 8995                    // Workaround: For some reason, there's a gap if we don't do this
 8996                    .ml(-BORDER_WIDTH)
 8997                    .shadow(vec![gpui::BoxShadow {
 8998                        color: gpui::black().opacity(0.05),
 8999                        offset: point(px(1.), px(1.)),
 9000                        blur_radius: px(2.),
 9001                        spread_radius: px(0.),
 9002                    }])
 9003                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9004                    .border(BORDER_WIDTH)
 9005                    .border_color(cx.theme().colors().border)
 9006                    .rounded_r_lg()
 9007                    .id("edit_prediction_diff_popover_keybind")
 9008                    .when(!has_keybind, |el| {
 9009                        let status_colors = cx.theme().status();
 9010
 9011                        el.bg(status_colors.error_background)
 9012                            .border_color(status_colors.error.opacity(0.6))
 9013                            .child(Icon::new(IconName::Info).color(Color::Error))
 9014                            .cursor_default()
 9015                            .hoverable_tooltip(move |_window, cx| {
 9016                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9017                            })
 9018                    })
 9019                    .children(keybind),
 9020            )
 9021            .into_any();
 9022
 9023        let longest_row =
 9024            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9025        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9026            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9027        } else {
 9028            layout_line(
 9029                longest_row,
 9030                editor_snapshot,
 9031                style,
 9032                editor_width,
 9033                |_| false,
 9034                window,
 9035                cx,
 9036            )
 9037            .width
 9038        };
 9039
 9040        let viewport_bounds =
 9041            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9042                right: -right_margin,
 9043                ..Default::default()
 9044            });
 9045
 9046        let x_after_longest =
 9047            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9048                - scroll_pixel_position.x;
 9049
 9050        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9051
 9052        // Fully visible if it can be displayed within the window (allow overlapping other
 9053        // panes). However, this is only allowed if the popover starts within text_bounds.
 9054        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9055            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9056
 9057        let mut origin = if can_position_to_the_right {
 9058            point(
 9059                x_after_longest,
 9060                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9061                    - scroll_pixel_position.y,
 9062            )
 9063        } else {
 9064            let cursor_row = newest_selection_head.map(|head| head.row());
 9065            let above_edit = edit_start
 9066                .row()
 9067                .0
 9068                .checked_sub(line_count as u32)
 9069                .map(DisplayRow);
 9070            let below_edit = Some(edit_end.row() + 1);
 9071            let above_cursor =
 9072                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9073            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9074
 9075            // Place the edit popover adjacent to the edit if there is a location
 9076            // available that is onscreen and does not obscure the cursor. Otherwise,
 9077            // place it adjacent to the cursor.
 9078            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9079                .into_iter()
 9080                .flatten()
 9081                .find(|&start_row| {
 9082                    let end_row = start_row + line_count as u32;
 9083                    visible_row_range.contains(&start_row)
 9084                        && visible_row_range.contains(&end_row)
 9085                        && cursor_row
 9086                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9087                })?;
 9088
 9089            content_origin
 9090                + point(
 9091                    -scroll_pixel_position.x,
 9092                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9093                )
 9094        };
 9095
 9096        origin.x -= BORDER_WIDTH;
 9097
 9098        window.defer_draw(element, origin, 1);
 9099
 9100        // Do not return an element, since it will already be drawn due to defer_draw.
 9101        None
 9102    }
 9103
 9104    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9105        px(30.)
 9106    }
 9107
 9108    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9109        if self.read_only(cx) {
 9110            cx.theme().players().read_only()
 9111        } else {
 9112            self.style.as_ref().unwrap().local_player
 9113        }
 9114    }
 9115
 9116    fn render_edit_prediction_accept_keybind(
 9117        &self,
 9118        window: &mut Window,
 9119        cx: &App,
 9120    ) -> Option<AnyElement> {
 9121        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9122        let accept_keystroke = accept_binding.keystroke()?;
 9123
 9124        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9125
 9126        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9127            Color::Accent
 9128        } else {
 9129            Color::Muted
 9130        };
 9131
 9132        h_flex()
 9133            .px_0p5()
 9134            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9135            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9136            .text_size(TextSize::XSmall.rems(cx))
 9137            .child(h_flex().children(ui::render_modifiers(
 9138                accept_keystroke.modifiers(),
 9139                PlatformStyle::platform(),
 9140                Some(modifiers_color),
 9141                Some(IconSize::XSmall.rems().into()),
 9142                true,
 9143            )))
 9144            .when(is_platform_style_mac, |parent| {
 9145                parent.child(accept_keystroke.key().to_string())
 9146            })
 9147            .when(!is_platform_style_mac, |parent| {
 9148                parent.child(
 9149                    Key::new(
 9150                        util::capitalize(accept_keystroke.key()),
 9151                        Some(Color::Default),
 9152                    )
 9153                    .size(Some(IconSize::XSmall.rems().into())),
 9154                )
 9155            })
 9156            .into_any()
 9157            .into()
 9158    }
 9159
 9160    fn render_edit_prediction_line_popover(
 9161        &self,
 9162        label: impl Into<SharedString>,
 9163        icon: Option<IconName>,
 9164        window: &mut Window,
 9165        cx: &App,
 9166    ) -> Option<Stateful<Div>> {
 9167        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9168
 9169        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9170        let has_keybind = keybind.is_some();
 9171
 9172        let result = h_flex()
 9173            .id("ep-line-popover")
 9174            .py_0p5()
 9175            .pl_1()
 9176            .pr(padding_right)
 9177            .gap_1()
 9178            .rounded_md()
 9179            .border_1()
 9180            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9181            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9182            .shadow_xs()
 9183            .when(!has_keybind, |el| {
 9184                let status_colors = cx.theme().status();
 9185
 9186                el.bg(status_colors.error_background)
 9187                    .border_color(status_colors.error.opacity(0.6))
 9188                    .pl_2()
 9189                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9190                    .cursor_default()
 9191                    .hoverable_tooltip(move |_window, cx| {
 9192                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9193                    })
 9194            })
 9195            .children(keybind)
 9196            .child(
 9197                Label::new(label)
 9198                    .size(LabelSize::Small)
 9199                    .when(!has_keybind, |el| {
 9200                        el.color(cx.theme().status().error.into()).strikethrough()
 9201                    }),
 9202            )
 9203            .when(!has_keybind, |el| {
 9204                el.child(
 9205                    h_flex().ml_1().child(
 9206                        Icon::new(IconName::Info)
 9207                            .size(IconSize::Small)
 9208                            .color(cx.theme().status().error.into()),
 9209                    ),
 9210                )
 9211            })
 9212            .when_some(icon, |element, icon| {
 9213                element.child(
 9214                    div()
 9215                        .mt(px(1.5))
 9216                        .child(Icon::new(icon).size(IconSize::Small)),
 9217                )
 9218            });
 9219
 9220        Some(result)
 9221    }
 9222
 9223    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9224        let accent_color = cx.theme().colors().text_accent;
 9225        let editor_bg_color = cx.theme().colors().editor_background;
 9226        editor_bg_color.blend(accent_color.opacity(0.1))
 9227    }
 9228
 9229    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9230        let accent_color = cx.theme().colors().text_accent;
 9231        let editor_bg_color = cx.theme().colors().editor_background;
 9232        editor_bg_color.blend(accent_color.opacity(0.6))
 9233    }
 9234    fn get_prediction_provider_icon_name(
 9235        provider: &Option<RegisteredEditPredictionProvider>,
 9236    ) -> IconName {
 9237        match provider {
 9238            Some(provider) => match provider.provider.name() {
 9239                "copilot" => IconName::Copilot,
 9240                "supermaven" => IconName::Supermaven,
 9241                _ => IconName::ZedPredict,
 9242            },
 9243            None => IconName::ZedPredict,
 9244        }
 9245    }
 9246
 9247    fn render_edit_prediction_cursor_popover(
 9248        &self,
 9249        min_width: Pixels,
 9250        max_width: Pixels,
 9251        cursor_point: Point,
 9252        style: &EditorStyle,
 9253        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9254        _window: &Window,
 9255        cx: &mut Context<Editor>,
 9256    ) -> Option<AnyElement> {
 9257        let provider = self.edit_prediction_provider.as_ref()?;
 9258        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9259
 9260        let is_refreshing = provider.provider.is_refreshing(cx);
 9261
 9262        fn pending_completion_container(icon: IconName) -> Div {
 9263            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9264        }
 9265
 9266        let completion = match &self.active_edit_prediction {
 9267            Some(prediction) => {
 9268                if !self.has_visible_completions_menu() {
 9269                    const RADIUS: Pixels = px(6.);
 9270                    const BORDER_WIDTH: Pixels = px(1.);
 9271
 9272                    return Some(
 9273                        h_flex()
 9274                            .elevation_2(cx)
 9275                            .border(BORDER_WIDTH)
 9276                            .border_color(cx.theme().colors().border)
 9277                            .when(accept_keystroke.is_none(), |el| {
 9278                                el.border_color(cx.theme().status().error)
 9279                            })
 9280                            .rounded(RADIUS)
 9281                            .rounded_tl(px(0.))
 9282                            .overflow_hidden()
 9283                            .child(div().px_1p5().child(match &prediction.completion {
 9284                                EditPrediction::Move { target, snapshot } => {
 9285                                    use text::ToPoint as _;
 9286                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9287                                    {
 9288                                        Icon::new(IconName::ZedPredictDown)
 9289                                    } else {
 9290                                        Icon::new(IconName::ZedPredictUp)
 9291                                    }
 9292                                }
 9293                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9294                            }))
 9295                            .child(
 9296                                h_flex()
 9297                                    .gap_1()
 9298                                    .py_1()
 9299                                    .px_2()
 9300                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9301                                    .border_l_1()
 9302                                    .border_color(cx.theme().colors().border)
 9303                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9304                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9305                                        el.child(
 9306                                            Label::new("Hold")
 9307                                                .size(LabelSize::Small)
 9308                                                .when(accept_keystroke.is_none(), |el| {
 9309                                                    el.strikethrough()
 9310                                                })
 9311                                                .line_height_style(LineHeightStyle::UiLabel),
 9312                                        )
 9313                                    })
 9314                                    .id("edit_prediction_cursor_popover_keybind")
 9315                                    .when(accept_keystroke.is_none(), |el| {
 9316                                        let status_colors = cx.theme().status();
 9317
 9318                                        el.bg(status_colors.error_background)
 9319                                            .border_color(status_colors.error.opacity(0.6))
 9320                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9321                                            .cursor_default()
 9322                                            .hoverable_tooltip(move |_window, cx| {
 9323                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9324                                                    .into()
 9325                                            })
 9326                                    })
 9327                                    .when_some(
 9328                                        accept_keystroke.as_ref(),
 9329                                        |el, accept_keystroke| {
 9330                                            el.child(h_flex().children(ui::render_modifiers(
 9331                                                accept_keystroke.modifiers(),
 9332                                                PlatformStyle::platform(),
 9333                                                Some(Color::Default),
 9334                                                Some(IconSize::XSmall.rems().into()),
 9335                                                false,
 9336                                            )))
 9337                                        },
 9338                                    ),
 9339                            )
 9340                            .into_any(),
 9341                    );
 9342                }
 9343
 9344                self.render_edit_prediction_cursor_popover_preview(
 9345                    prediction,
 9346                    cursor_point,
 9347                    style,
 9348                    cx,
 9349                )?
 9350            }
 9351
 9352            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9353                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9354                    stale_completion,
 9355                    cursor_point,
 9356                    style,
 9357                    cx,
 9358                )?,
 9359
 9360                None => pending_completion_container(provider_icon)
 9361                    .child(Label::new("...").size(LabelSize::Small)),
 9362            },
 9363
 9364            None => pending_completion_container(provider_icon)
 9365                .child(Label::new("...").size(LabelSize::Small)),
 9366        };
 9367
 9368        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9369            completion
 9370                .with_animation(
 9371                    "loading-completion",
 9372                    Animation::new(Duration::from_secs(2))
 9373                        .repeat()
 9374                        .with_easing(pulsating_between(0.4, 0.8)),
 9375                    |label, delta| label.opacity(delta),
 9376                )
 9377                .into_any_element()
 9378        } else {
 9379            completion.into_any_element()
 9380        };
 9381
 9382        let has_completion = self.active_edit_prediction.is_some();
 9383
 9384        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9385        Some(
 9386            h_flex()
 9387                .min_w(min_width)
 9388                .max_w(max_width)
 9389                .flex_1()
 9390                .elevation_2(cx)
 9391                .border_color(cx.theme().colors().border)
 9392                .child(
 9393                    div()
 9394                        .flex_1()
 9395                        .py_1()
 9396                        .px_2()
 9397                        .overflow_hidden()
 9398                        .child(completion),
 9399                )
 9400                .when_some(accept_keystroke, |el, accept_keystroke| {
 9401                    if !accept_keystroke.modifiers().modified() {
 9402                        return el;
 9403                    }
 9404
 9405                    el.child(
 9406                        h_flex()
 9407                            .h_full()
 9408                            .border_l_1()
 9409                            .rounded_r_lg()
 9410                            .border_color(cx.theme().colors().border)
 9411                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9412                            .gap_1()
 9413                            .py_1()
 9414                            .px_2()
 9415                            .child(
 9416                                h_flex()
 9417                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9418                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9419                                    .child(h_flex().children(ui::render_modifiers(
 9420                                        accept_keystroke.modifiers(),
 9421                                        PlatformStyle::platform(),
 9422                                        Some(if !has_completion {
 9423                                            Color::Muted
 9424                                        } else {
 9425                                            Color::Default
 9426                                        }),
 9427                                        None,
 9428                                        false,
 9429                                    ))),
 9430                            )
 9431                            .child(Label::new("Preview").into_any_element())
 9432                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9433                    )
 9434                })
 9435                .into_any(),
 9436        )
 9437    }
 9438
 9439    fn render_edit_prediction_cursor_popover_preview(
 9440        &self,
 9441        completion: &EditPredictionState,
 9442        cursor_point: Point,
 9443        style: &EditorStyle,
 9444        cx: &mut Context<Editor>,
 9445    ) -> Option<Div> {
 9446        use text::ToPoint as _;
 9447
 9448        fn render_relative_row_jump(
 9449            prefix: impl Into<String>,
 9450            current_row: u32,
 9451            target_row: u32,
 9452        ) -> Div {
 9453            let (row_diff, arrow) = if target_row < current_row {
 9454                (current_row - target_row, IconName::ArrowUp)
 9455            } else {
 9456                (target_row - current_row, IconName::ArrowDown)
 9457            };
 9458
 9459            h_flex()
 9460                .child(
 9461                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9462                        .color(Color::Muted)
 9463                        .size(LabelSize::Small),
 9464                )
 9465                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9466        }
 9467
 9468        let supports_jump = self
 9469            .edit_prediction_provider
 9470            .as_ref()
 9471            .map(|provider| provider.provider.supports_jump_to_edit())
 9472            .unwrap_or(true);
 9473
 9474        match &completion.completion {
 9475            EditPrediction::Move {
 9476                target, snapshot, ..
 9477            } => {
 9478                if !supports_jump {
 9479                    return None;
 9480                }
 9481
 9482                Some(
 9483                    h_flex()
 9484                        .px_2()
 9485                        .gap_2()
 9486                        .flex_1()
 9487                        .child(
 9488                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9489                                Icon::new(IconName::ZedPredictDown)
 9490                            } else {
 9491                                Icon::new(IconName::ZedPredictUp)
 9492                            },
 9493                        )
 9494                        .child(Label::new("Jump to Edit")),
 9495                )
 9496            }
 9497
 9498            EditPrediction::Edit {
 9499                edits,
 9500                edit_preview,
 9501                snapshot,
 9502                display_mode: _,
 9503            } => {
 9504                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9505
 9506                let (highlighted_edits, has_more_lines) =
 9507                    if let Some(edit_preview) = edit_preview.as_ref() {
 9508                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9509                            .first_line_preview()
 9510                    } else {
 9511                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9512                    };
 9513
 9514                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9515                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9516
 9517                let preview = h_flex()
 9518                    .gap_1()
 9519                    .min_w_16()
 9520                    .child(styled_text)
 9521                    .when(has_more_lines, |parent| parent.child(""));
 9522
 9523                let left = if supports_jump && first_edit_row != cursor_point.row {
 9524                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9525                        .into_any_element()
 9526                } else {
 9527                    let icon_name =
 9528                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9529                    Icon::new(icon_name).into_any_element()
 9530                };
 9531
 9532                Some(
 9533                    h_flex()
 9534                        .h_full()
 9535                        .flex_1()
 9536                        .gap_2()
 9537                        .pr_1()
 9538                        .overflow_x_hidden()
 9539                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9540                        .child(left)
 9541                        .child(preview),
 9542                )
 9543            }
 9544        }
 9545    }
 9546
 9547    pub fn render_context_menu(
 9548        &self,
 9549        style: &EditorStyle,
 9550        max_height_in_lines: u32,
 9551        window: &mut Window,
 9552        cx: &mut Context<Editor>,
 9553    ) -> Option<AnyElement> {
 9554        let menu = self.context_menu.borrow();
 9555        let menu = menu.as_ref()?;
 9556        if !menu.visible() {
 9557            return None;
 9558        };
 9559        Some(menu.render(style, max_height_in_lines, window, cx))
 9560    }
 9561
 9562    fn render_context_menu_aside(
 9563        &mut self,
 9564        max_size: Size<Pixels>,
 9565        window: &mut Window,
 9566        cx: &mut Context<Editor>,
 9567    ) -> Option<AnyElement> {
 9568        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9569            if menu.visible() {
 9570                menu.render_aside(max_size, window, cx)
 9571            } else {
 9572                None
 9573            }
 9574        })
 9575    }
 9576
 9577    fn hide_context_menu(
 9578        &mut self,
 9579        window: &mut Window,
 9580        cx: &mut Context<Self>,
 9581    ) -> Option<CodeContextMenu> {
 9582        cx.notify();
 9583        self.completion_tasks.clear();
 9584        let context_menu = self.context_menu.borrow_mut().take();
 9585        self.stale_edit_prediction_in_menu.take();
 9586        self.update_visible_edit_prediction(window, cx);
 9587        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9588            && let Some(completion_provider) = &self.completion_provider
 9589        {
 9590            completion_provider.selection_changed(None, window, cx);
 9591        }
 9592        context_menu
 9593    }
 9594
 9595    fn show_snippet_choices(
 9596        &mut self,
 9597        choices: &Vec<String>,
 9598        selection: Range<Anchor>,
 9599        cx: &mut Context<Self>,
 9600    ) {
 9601        let Some((_, buffer, _)) = self
 9602            .buffer()
 9603            .read(cx)
 9604            .excerpt_containing(selection.start, cx)
 9605        else {
 9606            return;
 9607        };
 9608        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9609        else {
 9610            return;
 9611        };
 9612        if buffer != end_buffer {
 9613            log::error!("expected anchor range to have matching buffer IDs");
 9614            return;
 9615        }
 9616
 9617        let id = post_inc(&mut self.next_completion_id);
 9618        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9619        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9620            CompletionsMenu::new_snippet_choices(
 9621                id,
 9622                true,
 9623                choices,
 9624                selection,
 9625                buffer,
 9626                snippet_sort_order,
 9627            ),
 9628        ));
 9629    }
 9630
 9631    pub fn insert_snippet(
 9632        &mut self,
 9633        insertion_ranges: &[Range<usize>],
 9634        snippet: Snippet,
 9635        window: &mut Window,
 9636        cx: &mut Context<Self>,
 9637    ) -> Result<()> {
 9638        struct Tabstop<T> {
 9639            is_end_tabstop: bool,
 9640            ranges: Vec<Range<T>>,
 9641            choices: Option<Vec<String>>,
 9642        }
 9643
 9644        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9645            let snippet_text: Arc<str> = snippet.text.clone().into();
 9646            let edits = insertion_ranges
 9647                .iter()
 9648                .cloned()
 9649                .map(|range| (range, snippet_text.clone()));
 9650            let autoindent_mode = AutoindentMode::Block {
 9651                original_indent_columns: Vec::new(),
 9652            };
 9653            buffer.edit(edits, Some(autoindent_mode), cx);
 9654
 9655            let snapshot = &*buffer.read(cx);
 9656            let snippet = &snippet;
 9657            snippet
 9658                .tabstops
 9659                .iter()
 9660                .map(|tabstop| {
 9661                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9662                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9663                    });
 9664                    let mut tabstop_ranges = tabstop
 9665                        .ranges
 9666                        .iter()
 9667                        .flat_map(|tabstop_range| {
 9668                            let mut delta = 0_isize;
 9669                            insertion_ranges.iter().map(move |insertion_range| {
 9670                                let insertion_start = insertion_range.start as isize + delta;
 9671                                delta +=
 9672                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9673
 9674                                let start = ((insertion_start + tabstop_range.start) as usize)
 9675                                    .min(snapshot.len());
 9676                                let end = ((insertion_start + tabstop_range.end) as usize)
 9677                                    .min(snapshot.len());
 9678                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9679                            })
 9680                        })
 9681                        .collect::<Vec<_>>();
 9682                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9683
 9684                    Tabstop {
 9685                        is_end_tabstop,
 9686                        ranges: tabstop_ranges,
 9687                        choices: tabstop.choices.clone(),
 9688                    }
 9689                })
 9690                .collect::<Vec<_>>()
 9691        });
 9692        if let Some(tabstop) = tabstops.first() {
 9693            self.change_selections(Default::default(), window, cx, |s| {
 9694                // Reverse order so that the first range is the newest created selection.
 9695                // Completions will use it and autoscroll will prioritize it.
 9696                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9697            });
 9698
 9699            if let Some(choices) = &tabstop.choices
 9700                && let Some(selection) = tabstop.ranges.first()
 9701            {
 9702                self.show_snippet_choices(choices, selection.clone(), cx)
 9703            }
 9704
 9705            // If we're already at the last tabstop and it's at the end of the snippet,
 9706            // we're done, we don't need to keep the state around.
 9707            if !tabstop.is_end_tabstop {
 9708                let choices = tabstops
 9709                    .iter()
 9710                    .map(|tabstop| tabstop.choices.clone())
 9711                    .collect();
 9712
 9713                let ranges = tabstops
 9714                    .into_iter()
 9715                    .map(|tabstop| tabstop.ranges)
 9716                    .collect::<Vec<_>>();
 9717
 9718                self.snippet_stack.push(SnippetState {
 9719                    active_index: 0,
 9720                    ranges,
 9721                    choices,
 9722                });
 9723            }
 9724
 9725            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9726            if self.autoclose_regions.is_empty() {
 9727                let snapshot = self.buffer.read(cx).snapshot(cx);
 9728                let mut all_selections = self.selections.all::<Point>(cx);
 9729                for selection in &mut all_selections {
 9730                    let selection_head = selection.head();
 9731                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9732                        continue;
 9733                    };
 9734
 9735                    let mut bracket_pair = None;
 9736                    let max_lookup_length = scope
 9737                        .brackets()
 9738                        .map(|(pair, _)| {
 9739                            pair.start
 9740                                .as_str()
 9741                                .chars()
 9742                                .count()
 9743                                .max(pair.end.as_str().chars().count())
 9744                        })
 9745                        .max();
 9746                    if let Some(max_lookup_length) = max_lookup_length {
 9747                        let next_text = snapshot
 9748                            .chars_at(selection_head)
 9749                            .take(max_lookup_length)
 9750                            .collect::<String>();
 9751                        let prev_text = snapshot
 9752                            .reversed_chars_at(selection_head)
 9753                            .take(max_lookup_length)
 9754                            .collect::<String>();
 9755
 9756                        for (pair, enabled) in scope.brackets() {
 9757                            if enabled
 9758                                && pair.close
 9759                                && prev_text.starts_with(pair.start.as_str())
 9760                                && next_text.starts_with(pair.end.as_str())
 9761                            {
 9762                                bracket_pair = Some(pair.clone());
 9763                                break;
 9764                            }
 9765                        }
 9766                    }
 9767
 9768                    if let Some(pair) = bracket_pair {
 9769                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9770                        let autoclose_enabled =
 9771                            self.use_autoclose && snapshot_settings.use_autoclose;
 9772                        if autoclose_enabled {
 9773                            let start = snapshot.anchor_after(selection_head);
 9774                            let end = snapshot.anchor_after(selection_head);
 9775                            self.autoclose_regions.push(AutocloseRegion {
 9776                                selection_id: selection.id,
 9777                                range: start..end,
 9778                                pair,
 9779                            });
 9780                        }
 9781                    }
 9782                }
 9783            }
 9784        }
 9785        Ok(())
 9786    }
 9787
 9788    pub fn move_to_next_snippet_tabstop(
 9789        &mut self,
 9790        window: &mut Window,
 9791        cx: &mut Context<Self>,
 9792    ) -> bool {
 9793        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9794    }
 9795
 9796    pub fn move_to_prev_snippet_tabstop(
 9797        &mut self,
 9798        window: &mut Window,
 9799        cx: &mut Context<Self>,
 9800    ) -> bool {
 9801        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9802    }
 9803
 9804    pub fn move_to_snippet_tabstop(
 9805        &mut self,
 9806        bias: Bias,
 9807        window: &mut Window,
 9808        cx: &mut Context<Self>,
 9809    ) -> bool {
 9810        if let Some(mut snippet) = self.snippet_stack.pop() {
 9811            match bias {
 9812                Bias::Left => {
 9813                    if snippet.active_index > 0 {
 9814                        snippet.active_index -= 1;
 9815                    } else {
 9816                        self.snippet_stack.push(snippet);
 9817                        return false;
 9818                    }
 9819                }
 9820                Bias::Right => {
 9821                    if snippet.active_index + 1 < snippet.ranges.len() {
 9822                        snippet.active_index += 1;
 9823                    } else {
 9824                        self.snippet_stack.push(snippet);
 9825                        return false;
 9826                    }
 9827                }
 9828            }
 9829            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9830                self.change_selections(Default::default(), window, cx, |s| {
 9831                    // Reverse order so that the first range is the newest created selection.
 9832                    // Completions will use it and autoscroll will prioritize it.
 9833                    s.select_ranges(current_ranges.iter().rev().cloned())
 9834                });
 9835
 9836                if let Some(choices) = &snippet.choices[snippet.active_index]
 9837                    && let Some(selection) = current_ranges.first()
 9838                {
 9839                    self.show_snippet_choices(choices, selection.clone(), cx);
 9840                }
 9841
 9842                // If snippet state is not at the last tabstop, push it back on the stack
 9843                if snippet.active_index + 1 < snippet.ranges.len() {
 9844                    self.snippet_stack.push(snippet);
 9845                }
 9846                return true;
 9847            }
 9848        }
 9849
 9850        false
 9851    }
 9852
 9853    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9854        self.transact(window, cx, |this, window, cx| {
 9855            this.select_all(&SelectAll, window, cx);
 9856            this.insert("", window, cx);
 9857        });
 9858    }
 9859
 9860    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9861        if self.read_only(cx) {
 9862            return;
 9863        }
 9864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9865        self.transact(window, cx, |this, window, cx| {
 9866            this.select_autoclose_pair(window, cx);
 9867            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9868            if !this.linked_edit_ranges.is_empty() {
 9869                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9870                let snapshot = this.buffer.read(cx).snapshot(cx);
 9871
 9872                for selection in selections.iter() {
 9873                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9874                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9875                    if selection_start.buffer_id != selection_end.buffer_id {
 9876                        continue;
 9877                    }
 9878                    if let Some(ranges) =
 9879                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9880                    {
 9881                        for (buffer, entries) in ranges {
 9882                            linked_ranges.entry(buffer).or_default().extend(entries);
 9883                        }
 9884                    }
 9885                }
 9886            }
 9887
 9888            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9889            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9890            for selection in &mut selections {
 9891                if selection.is_empty() {
 9892                    let old_head = selection.head();
 9893                    let mut new_head =
 9894                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9895                            .to_point(&display_map);
 9896                    if let Some((buffer, line_buffer_range)) = display_map
 9897                        .buffer_snapshot
 9898                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9899                    {
 9900                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9901                        let indent_len = match indent_size.kind {
 9902                            IndentKind::Space => {
 9903                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9904                            }
 9905                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9906                        };
 9907                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9908                            let indent_len = indent_len.get();
 9909                            new_head = cmp::min(
 9910                                new_head,
 9911                                MultiBufferPoint::new(
 9912                                    old_head.row,
 9913                                    ((old_head.column - 1) / indent_len) * indent_len,
 9914                                ),
 9915                            );
 9916                        }
 9917                    }
 9918
 9919                    selection.set_head(new_head, SelectionGoal::None);
 9920                }
 9921            }
 9922
 9923            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9924            this.insert("", window, cx);
 9925            let empty_str: Arc<str> = Arc::from("");
 9926            for (buffer, edits) in linked_ranges {
 9927                let snapshot = buffer.read(cx).snapshot();
 9928                use text::ToPoint as TP;
 9929
 9930                let edits = edits
 9931                    .into_iter()
 9932                    .map(|range| {
 9933                        let end_point = TP::to_point(&range.end, &snapshot);
 9934                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9935
 9936                        if end_point == start_point {
 9937                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9938                                .saturating_sub(1);
 9939                            start_point =
 9940                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9941                        };
 9942
 9943                        (start_point..end_point, empty_str.clone())
 9944                    })
 9945                    .sorted_by_key(|(range, _)| range.start)
 9946                    .collect::<Vec<_>>();
 9947                buffer.update(cx, |this, cx| {
 9948                    this.edit(edits, None, cx);
 9949                })
 9950            }
 9951            this.refresh_edit_prediction(true, false, window, cx);
 9952            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9953        });
 9954    }
 9955
 9956    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9957        if self.read_only(cx) {
 9958            return;
 9959        }
 9960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961        self.transact(window, cx, |this, window, cx| {
 9962            this.change_selections(Default::default(), window, cx, |s| {
 9963                s.move_with(|map, selection| {
 9964                    if selection.is_empty() {
 9965                        let cursor = movement::right(map, selection.head());
 9966                        selection.end = cursor;
 9967                        selection.reversed = true;
 9968                        selection.goal = SelectionGoal::None;
 9969                    }
 9970                })
 9971            });
 9972            this.insert("", window, cx);
 9973            this.refresh_edit_prediction(true, false, window, cx);
 9974        });
 9975    }
 9976
 9977    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9978        if self.mode.is_single_line() {
 9979            cx.propagate();
 9980            return;
 9981        }
 9982
 9983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9984        if self.move_to_prev_snippet_tabstop(window, cx) {
 9985            return;
 9986        }
 9987        self.outdent(&Outdent, window, cx);
 9988    }
 9989
 9990    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9991        if self.mode.is_single_line() {
 9992            cx.propagate();
 9993            return;
 9994        }
 9995
 9996        if self.move_to_next_snippet_tabstop(window, cx) {
 9997            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9998            return;
 9999        }
10000        if self.read_only(cx) {
10001            return;
10002        }
10003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10004        let mut selections = self.selections.all_adjusted(cx);
10005        let buffer = self.buffer.read(cx);
10006        let snapshot = buffer.snapshot(cx);
10007        let rows_iter = selections.iter().map(|s| s.head().row);
10008        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10009
10010        let has_some_cursor_in_whitespace = selections
10011            .iter()
10012            .filter(|selection| selection.is_empty())
10013            .any(|selection| {
10014                let cursor = selection.head();
10015                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10016                cursor.column < current_indent.len
10017            });
10018
10019        let mut edits = Vec::new();
10020        let mut prev_edited_row = 0;
10021        let mut row_delta = 0;
10022        for selection in &mut selections {
10023            if selection.start.row != prev_edited_row {
10024                row_delta = 0;
10025            }
10026            prev_edited_row = selection.end.row;
10027
10028            // If the selection is non-empty, then increase the indentation of the selected lines.
10029            if !selection.is_empty() {
10030                row_delta =
10031                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10032                continue;
10033            }
10034
10035            let cursor = selection.head();
10036            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10037            if let Some(suggested_indent) =
10038                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10039            {
10040                // Don't do anything if already at suggested indent
10041                // and there is any other cursor which is not
10042                if has_some_cursor_in_whitespace
10043                    && cursor.column == current_indent.len
10044                    && current_indent.len == suggested_indent.len
10045                {
10046                    continue;
10047                }
10048
10049                // Adjust line and move cursor to suggested indent
10050                // if cursor is not at suggested indent
10051                if cursor.column < suggested_indent.len
10052                    && cursor.column <= current_indent.len
10053                    && current_indent.len <= suggested_indent.len
10054                {
10055                    selection.start = Point::new(cursor.row, suggested_indent.len);
10056                    selection.end = selection.start;
10057                    if row_delta == 0 {
10058                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10059                            cursor.row,
10060                            current_indent,
10061                            suggested_indent,
10062                        ));
10063                        row_delta = suggested_indent.len - current_indent.len;
10064                    }
10065                    continue;
10066                }
10067
10068                // If current indent is more than suggested indent
10069                // only move cursor to current indent and skip indent
10070                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10071                    selection.start = Point::new(cursor.row, current_indent.len);
10072                    selection.end = selection.start;
10073                    continue;
10074                }
10075            }
10076
10077            // Otherwise, insert a hard or soft tab.
10078            let settings = buffer.language_settings_at(cursor, cx);
10079            let tab_size = if settings.hard_tabs {
10080                IndentSize::tab()
10081            } else {
10082                let tab_size = settings.tab_size.get();
10083                let indent_remainder = snapshot
10084                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10085                    .flat_map(str::chars)
10086                    .fold(row_delta % tab_size, |counter: u32, c| {
10087                        if c == '\t' {
10088                            0
10089                        } else {
10090                            (counter + 1) % tab_size
10091                        }
10092                    });
10093
10094                let chars_to_next_tab_stop = tab_size - indent_remainder;
10095                IndentSize::spaces(chars_to_next_tab_stop)
10096            };
10097            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10098            selection.end = selection.start;
10099            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10100            row_delta += tab_size.len;
10101        }
10102
10103        self.transact(window, cx, |this, window, cx| {
10104            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10105            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10106            this.refresh_edit_prediction(true, false, window, cx);
10107        });
10108    }
10109
10110    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10111        if self.read_only(cx) {
10112            return;
10113        }
10114        if self.mode.is_single_line() {
10115            cx.propagate();
10116            return;
10117        }
10118
10119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10120        let mut selections = self.selections.all::<Point>(cx);
10121        let mut prev_edited_row = 0;
10122        let mut row_delta = 0;
10123        let mut edits = Vec::new();
10124        let buffer = self.buffer.read(cx);
10125        let snapshot = buffer.snapshot(cx);
10126        for selection in &mut selections {
10127            if selection.start.row != prev_edited_row {
10128                row_delta = 0;
10129            }
10130            prev_edited_row = selection.end.row;
10131
10132            row_delta =
10133                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10134        }
10135
10136        self.transact(window, cx, |this, window, cx| {
10137            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10138            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10139        });
10140    }
10141
10142    fn indent_selection(
10143        buffer: &MultiBuffer,
10144        snapshot: &MultiBufferSnapshot,
10145        selection: &mut Selection<Point>,
10146        edits: &mut Vec<(Range<Point>, String)>,
10147        delta_for_start_row: u32,
10148        cx: &App,
10149    ) -> u32 {
10150        let settings = buffer.language_settings_at(selection.start, cx);
10151        let tab_size = settings.tab_size.get();
10152        let indent_kind = if settings.hard_tabs {
10153            IndentKind::Tab
10154        } else {
10155            IndentKind::Space
10156        };
10157        let mut start_row = selection.start.row;
10158        let mut end_row = selection.end.row + 1;
10159
10160        // If a selection ends at the beginning of a line, don't indent
10161        // that last line.
10162        if selection.end.column == 0 && selection.end.row > selection.start.row {
10163            end_row -= 1;
10164        }
10165
10166        // Avoid re-indenting a row that has already been indented by a
10167        // previous selection, but still update this selection's column
10168        // to reflect that indentation.
10169        if delta_for_start_row > 0 {
10170            start_row += 1;
10171            selection.start.column += delta_for_start_row;
10172            if selection.end.row == selection.start.row {
10173                selection.end.column += delta_for_start_row;
10174            }
10175        }
10176
10177        let mut delta_for_end_row = 0;
10178        let has_multiple_rows = start_row + 1 != end_row;
10179        for row in start_row..end_row {
10180            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10181            let indent_delta = match (current_indent.kind, indent_kind) {
10182                (IndentKind::Space, IndentKind::Space) => {
10183                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10184                    IndentSize::spaces(columns_to_next_tab_stop)
10185                }
10186                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10187                (_, IndentKind::Tab) => IndentSize::tab(),
10188            };
10189
10190            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10191                0
10192            } else {
10193                selection.start.column
10194            };
10195            let row_start = Point::new(row, start);
10196            edits.push((
10197                row_start..row_start,
10198                indent_delta.chars().collect::<String>(),
10199            ));
10200
10201            // Update this selection's endpoints to reflect the indentation.
10202            if row == selection.start.row {
10203                selection.start.column += indent_delta.len;
10204            }
10205            if row == selection.end.row {
10206                selection.end.column += indent_delta.len;
10207                delta_for_end_row = indent_delta.len;
10208            }
10209        }
10210
10211        if selection.start.row == selection.end.row {
10212            delta_for_start_row + delta_for_end_row
10213        } else {
10214            delta_for_end_row
10215        }
10216    }
10217
10218    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10219        if self.read_only(cx) {
10220            return;
10221        }
10222        if self.mode.is_single_line() {
10223            cx.propagate();
10224            return;
10225        }
10226
10227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10229        let selections = self.selections.all::<Point>(cx);
10230        let mut deletion_ranges = Vec::new();
10231        let mut last_outdent = None;
10232        {
10233            let buffer = self.buffer.read(cx);
10234            let snapshot = buffer.snapshot(cx);
10235            for selection in &selections {
10236                let settings = buffer.language_settings_at(selection.start, cx);
10237                let tab_size = settings.tab_size.get();
10238                let mut rows = selection.spanned_rows(false, &display_map);
10239
10240                // Avoid re-outdenting a row that has already been outdented by a
10241                // previous selection.
10242                if let Some(last_row) = last_outdent
10243                    && last_row == rows.start
10244                {
10245                    rows.start = rows.start.next_row();
10246                }
10247                let has_multiple_rows = rows.len() > 1;
10248                for row in rows.iter_rows() {
10249                    let indent_size = snapshot.indent_size_for_line(row);
10250                    if indent_size.len > 0 {
10251                        let deletion_len = match indent_size.kind {
10252                            IndentKind::Space => {
10253                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10254                                if columns_to_prev_tab_stop == 0 {
10255                                    tab_size
10256                                } else {
10257                                    columns_to_prev_tab_stop
10258                                }
10259                            }
10260                            IndentKind::Tab => 1,
10261                        };
10262                        let start = if has_multiple_rows
10263                            || deletion_len > selection.start.column
10264                            || indent_size.len < selection.start.column
10265                        {
10266                            0
10267                        } else {
10268                            selection.start.column - deletion_len
10269                        };
10270                        deletion_ranges.push(
10271                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10272                        );
10273                        last_outdent = Some(row);
10274                    }
10275                }
10276            }
10277        }
10278
10279        self.transact(window, cx, |this, window, cx| {
10280            this.buffer.update(cx, |buffer, cx| {
10281                let empty_str: Arc<str> = Arc::default();
10282                buffer.edit(
10283                    deletion_ranges
10284                        .into_iter()
10285                        .map(|range| (range, empty_str.clone())),
10286                    None,
10287                    cx,
10288                );
10289            });
10290            let selections = this.selections.all::<usize>(cx);
10291            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10292        });
10293    }
10294
10295    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10296        if self.read_only(cx) {
10297            return;
10298        }
10299        if self.mode.is_single_line() {
10300            cx.propagate();
10301            return;
10302        }
10303
10304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10305        let selections = self
10306            .selections
10307            .all::<usize>(cx)
10308            .into_iter()
10309            .map(|s| s.range());
10310
10311        self.transact(window, cx, |this, window, cx| {
10312            this.buffer.update(cx, |buffer, cx| {
10313                buffer.autoindent_ranges(selections, cx);
10314            });
10315            let selections = this.selections.all::<usize>(cx);
10316            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10317        });
10318    }
10319
10320    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10323        let selections = self.selections.all::<Point>(cx);
10324
10325        let mut new_cursors = Vec::new();
10326        let mut edit_ranges = Vec::new();
10327        let mut selections = selections.iter().peekable();
10328        while let Some(selection) = selections.next() {
10329            let mut rows = selection.spanned_rows(false, &display_map);
10330            let goal_display_column = selection.head().to_display_point(&display_map).column();
10331
10332            // Accumulate contiguous regions of rows that we want to delete.
10333            while let Some(next_selection) = selections.peek() {
10334                let next_rows = next_selection.spanned_rows(false, &display_map);
10335                if next_rows.start <= rows.end {
10336                    rows.end = next_rows.end;
10337                    selections.next().unwrap();
10338                } else {
10339                    break;
10340                }
10341            }
10342
10343            let buffer = &display_map.buffer_snapshot;
10344            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10345            let edit_end;
10346            let cursor_buffer_row;
10347            if buffer.max_point().row >= rows.end.0 {
10348                // If there's a line after the range, delete the \n from the end of the row range
10349                // and position the cursor on the next line.
10350                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10351                cursor_buffer_row = rows.end;
10352            } else {
10353                // If there isn't a line after the range, delete the \n from the line before the
10354                // start of the row range and position the cursor there.
10355                edit_start = edit_start.saturating_sub(1);
10356                edit_end = buffer.len();
10357                cursor_buffer_row = rows.start.previous_row();
10358            }
10359
10360            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10361            *cursor.column_mut() =
10362                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10363
10364            new_cursors.push((
10365                selection.id,
10366                buffer.anchor_after(cursor.to_point(&display_map)),
10367            ));
10368            edit_ranges.push(edit_start..edit_end);
10369        }
10370
10371        self.transact(window, cx, |this, window, cx| {
10372            let buffer = this.buffer.update(cx, |buffer, cx| {
10373                let empty_str: Arc<str> = Arc::default();
10374                buffer.edit(
10375                    edit_ranges
10376                        .into_iter()
10377                        .map(|range| (range, empty_str.clone())),
10378                    None,
10379                    cx,
10380                );
10381                buffer.snapshot(cx)
10382            });
10383            let new_selections = new_cursors
10384                .into_iter()
10385                .map(|(id, cursor)| {
10386                    let cursor = cursor.to_point(&buffer);
10387                    Selection {
10388                        id,
10389                        start: cursor,
10390                        end: cursor,
10391                        reversed: false,
10392                        goal: SelectionGoal::None,
10393                    }
10394                })
10395                .collect();
10396
10397            this.change_selections(Default::default(), window, cx, |s| {
10398                s.select(new_selections);
10399            });
10400        });
10401    }
10402
10403    pub fn join_lines_impl(
10404        &mut self,
10405        insert_whitespace: bool,
10406        window: &mut Window,
10407        cx: &mut Context<Self>,
10408    ) {
10409        if self.read_only(cx) {
10410            return;
10411        }
10412        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10413        for selection in self.selections.all::<Point>(cx) {
10414            let start = MultiBufferRow(selection.start.row);
10415            // Treat single line selections as if they include the next line. Otherwise this action
10416            // would do nothing for single line selections individual cursors.
10417            let end = if selection.start.row == selection.end.row {
10418                MultiBufferRow(selection.start.row + 1)
10419            } else {
10420                MultiBufferRow(selection.end.row)
10421            };
10422
10423            if let Some(last_row_range) = row_ranges.last_mut()
10424                && start <= last_row_range.end
10425            {
10426                last_row_range.end = end;
10427                continue;
10428            }
10429            row_ranges.push(start..end);
10430        }
10431
10432        let snapshot = self.buffer.read(cx).snapshot(cx);
10433        let mut cursor_positions = Vec::new();
10434        for row_range in &row_ranges {
10435            let anchor = snapshot.anchor_before(Point::new(
10436                row_range.end.previous_row().0,
10437                snapshot.line_len(row_range.end.previous_row()),
10438            ));
10439            cursor_positions.push(anchor..anchor);
10440        }
10441
10442        self.transact(window, cx, |this, window, cx| {
10443            for row_range in row_ranges.into_iter().rev() {
10444                for row in row_range.iter_rows().rev() {
10445                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10446                    let next_line_row = row.next_row();
10447                    let indent = snapshot.indent_size_for_line(next_line_row);
10448                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10449
10450                    let replace =
10451                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10452                            " "
10453                        } else {
10454                            ""
10455                        };
10456
10457                    this.buffer.update(cx, |buffer, cx| {
10458                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10459                    });
10460                }
10461            }
10462
10463            this.change_selections(Default::default(), window, cx, |s| {
10464                s.select_anchor_ranges(cursor_positions)
10465            });
10466        });
10467    }
10468
10469    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10470        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10471        self.join_lines_impl(true, window, cx);
10472    }
10473
10474    pub fn sort_lines_case_sensitive(
10475        &mut self,
10476        _: &SortLinesCaseSensitive,
10477        window: &mut Window,
10478        cx: &mut Context<Self>,
10479    ) {
10480        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10481    }
10482
10483    pub fn sort_lines_by_length(
10484        &mut self,
10485        _: &SortLinesByLength,
10486        window: &mut Window,
10487        cx: &mut Context<Self>,
10488    ) {
10489        self.manipulate_immutable_lines(window, cx, |lines| {
10490            lines.sort_by_key(|&line| line.chars().count())
10491        })
10492    }
10493
10494    pub fn sort_lines_case_insensitive(
10495        &mut self,
10496        _: &SortLinesCaseInsensitive,
10497        window: &mut Window,
10498        cx: &mut Context<Self>,
10499    ) {
10500        self.manipulate_immutable_lines(window, cx, |lines| {
10501            lines.sort_by_key(|line| line.to_lowercase())
10502        })
10503    }
10504
10505    pub fn unique_lines_case_insensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseInsensitive,
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.to_lowercase()));
10514        })
10515    }
10516
10517    pub fn unique_lines_case_sensitive(
10518        &mut self,
10519        _: &UniqueLinesCaseSensitive,
10520        window: &mut Window,
10521        cx: &mut Context<Self>,
10522    ) {
10523        self.manipulate_immutable_lines(window, cx, |lines| {
10524            let mut seen = HashSet::default();
10525            lines.retain(|line| seen.insert(*line));
10526        })
10527    }
10528
10529    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10530        let snapshot = self.buffer.read(cx).snapshot(cx);
10531        for selection in self.selections.disjoint_anchors_arc().iter() {
10532            if snapshot
10533                .language_at(selection.start)
10534                .and_then(|lang| lang.config().wrap_characters.as_ref())
10535                .is_some()
10536            {
10537                return true;
10538            }
10539        }
10540        false
10541    }
10542
10543    fn wrap_selections_in_tag(
10544        &mut self,
10545        _: &WrapSelectionsInTag,
10546        window: &mut Window,
10547        cx: &mut Context<Self>,
10548    ) {
10549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10550
10551        let snapshot = self.buffer.read(cx).snapshot(cx);
10552
10553        let mut edits = Vec::new();
10554        let mut boundaries = Vec::new();
10555
10556        for selection in self.selections.all::<Point>(cx).iter() {
10557            let Some(wrap_config) = snapshot
10558                .language_at(selection.start)
10559                .and_then(|lang| lang.config().wrap_characters.clone())
10560            else {
10561                continue;
10562            };
10563
10564            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10565            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10566
10567            let start_before = snapshot.anchor_before(selection.start);
10568            let end_after = snapshot.anchor_after(selection.end);
10569
10570            edits.push((start_before..start_before, open_tag));
10571            edits.push((end_after..end_after, close_tag));
10572
10573            boundaries.push((
10574                start_before,
10575                end_after,
10576                wrap_config.start_prefix.len(),
10577                wrap_config.end_suffix.len(),
10578            ));
10579        }
10580
10581        if edits.is_empty() {
10582            return;
10583        }
10584
10585        self.transact(window, cx, |this, window, cx| {
10586            let buffer = this.buffer.update(cx, |buffer, cx| {
10587                buffer.edit(edits, None, cx);
10588                buffer.snapshot(cx)
10589            });
10590
10591            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10592            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10593                boundaries.into_iter()
10594            {
10595                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10596                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10597                new_selections.push(open_offset..open_offset);
10598                new_selections.push(close_offset..close_offset);
10599            }
10600
10601            this.change_selections(Default::default(), window, cx, |s| {
10602                s.select_ranges(new_selections);
10603            });
10604
10605            this.request_autoscroll(Autoscroll::fit(), cx);
10606        });
10607    }
10608
10609    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10610        let Some(project) = self.project.clone() else {
10611            return;
10612        };
10613        self.reload(project, window, cx)
10614            .detach_and_notify_err(window, cx);
10615    }
10616
10617    pub fn restore_file(
10618        &mut self,
10619        _: &::git::RestoreFile,
10620        window: &mut Window,
10621        cx: &mut Context<Self>,
10622    ) {
10623        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10624        let mut buffer_ids = HashSet::default();
10625        let snapshot = self.buffer().read(cx).snapshot(cx);
10626        for selection in self.selections.all::<usize>(cx) {
10627            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10628        }
10629
10630        let buffer = self.buffer().read(cx);
10631        let ranges = buffer_ids
10632            .into_iter()
10633            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10634            .collect::<Vec<_>>();
10635
10636        self.restore_hunks_in_ranges(ranges, window, cx);
10637    }
10638
10639    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10641        let selections = self
10642            .selections
10643            .all(cx)
10644            .into_iter()
10645            .map(|s| s.range())
10646            .collect();
10647        self.restore_hunks_in_ranges(selections, window, cx);
10648    }
10649
10650    pub fn restore_hunks_in_ranges(
10651        &mut self,
10652        ranges: Vec<Range<Point>>,
10653        window: &mut Window,
10654        cx: &mut Context<Editor>,
10655    ) {
10656        let mut revert_changes = HashMap::default();
10657        let chunk_by = self
10658            .snapshot(window, cx)
10659            .hunks_for_ranges(ranges)
10660            .into_iter()
10661            .chunk_by(|hunk| hunk.buffer_id);
10662        for (buffer_id, hunks) in &chunk_by {
10663            let hunks = hunks.collect::<Vec<_>>();
10664            for hunk in &hunks {
10665                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10666            }
10667            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10668        }
10669        drop(chunk_by);
10670        if !revert_changes.is_empty() {
10671            self.transact(window, cx, |editor, window, cx| {
10672                editor.restore(revert_changes, window, cx);
10673            });
10674        }
10675    }
10676
10677    pub fn open_active_item_in_terminal(
10678        &mut self,
10679        _: &OpenInTerminal,
10680        window: &mut Window,
10681        cx: &mut Context<Self>,
10682    ) {
10683        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10684            let project_path = buffer.read(cx).project_path(cx)?;
10685            let project = self.project()?.read(cx);
10686            let entry = project.entry_for_path(&project_path, cx)?;
10687            let parent = match &entry.canonical_path {
10688                Some(canonical_path) => canonical_path.to_path_buf(),
10689                None => project.absolute_path(&project_path, cx)?,
10690            }
10691            .parent()?
10692            .to_path_buf();
10693            Some(parent)
10694        }) {
10695            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10696        }
10697    }
10698
10699    fn set_breakpoint_context_menu(
10700        &mut self,
10701        display_row: DisplayRow,
10702        position: Option<Anchor>,
10703        clicked_point: gpui::Point<Pixels>,
10704        window: &mut Window,
10705        cx: &mut Context<Self>,
10706    ) {
10707        let source = self
10708            .buffer
10709            .read(cx)
10710            .snapshot(cx)
10711            .anchor_before(Point::new(display_row.0, 0u32));
10712
10713        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10714
10715        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10716            self,
10717            source,
10718            clicked_point,
10719            context_menu,
10720            window,
10721            cx,
10722        );
10723    }
10724
10725    fn add_edit_breakpoint_block(
10726        &mut self,
10727        anchor: Anchor,
10728        breakpoint: &Breakpoint,
10729        edit_action: BreakpointPromptEditAction,
10730        window: &mut Window,
10731        cx: &mut Context<Self>,
10732    ) {
10733        let weak_editor = cx.weak_entity();
10734        let bp_prompt = cx.new(|cx| {
10735            BreakpointPromptEditor::new(
10736                weak_editor,
10737                anchor,
10738                breakpoint.clone(),
10739                edit_action,
10740                window,
10741                cx,
10742            )
10743        });
10744
10745        let height = bp_prompt.update(cx, |this, cx| {
10746            this.prompt
10747                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10748        });
10749        let cloned_prompt = bp_prompt.clone();
10750        let blocks = vec![BlockProperties {
10751            style: BlockStyle::Sticky,
10752            placement: BlockPlacement::Above(anchor),
10753            height: Some(height),
10754            render: Arc::new(move |cx| {
10755                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10756                cloned_prompt.clone().into_any_element()
10757            }),
10758            priority: 0,
10759        }];
10760
10761        let focus_handle = bp_prompt.focus_handle(cx);
10762        window.focus(&focus_handle);
10763
10764        let block_ids = self.insert_blocks(blocks, None, cx);
10765        bp_prompt.update(cx, |prompt, _| {
10766            prompt.add_block_ids(block_ids);
10767        });
10768    }
10769
10770    pub(crate) fn breakpoint_at_row(
10771        &self,
10772        row: u32,
10773        window: &mut Window,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let snapshot = self.snapshot(window, cx);
10777        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10778
10779        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10780    }
10781
10782    pub(crate) fn breakpoint_at_anchor(
10783        &self,
10784        breakpoint_position: Anchor,
10785        snapshot: &EditorSnapshot,
10786        cx: &mut Context<Self>,
10787    ) -> Option<(Anchor, Breakpoint)> {
10788        let buffer = self
10789            .buffer
10790            .read(cx)
10791            .buffer_for_anchor(breakpoint_position, cx)?;
10792
10793        let enclosing_excerpt = breakpoint_position.excerpt_id;
10794        let buffer_snapshot = buffer.read(cx).snapshot();
10795
10796        let row = buffer_snapshot
10797            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10798            .row;
10799
10800        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10801        let anchor_end = snapshot
10802            .buffer_snapshot
10803            .anchor_after(Point::new(row, line_len));
10804
10805        self.breakpoint_store
10806            .as_ref()?
10807            .read_with(cx, |breakpoint_store, cx| {
10808                breakpoint_store
10809                    .breakpoints(
10810                        &buffer,
10811                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10812                        &buffer_snapshot,
10813                        cx,
10814                    )
10815                    .next()
10816                    .and_then(|(bp, _)| {
10817                        let breakpoint_row = buffer_snapshot
10818                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10819                            .row;
10820
10821                        if breakpoint_row == row {
10822                            snapshot
10823                                .buffer_snapshot
10824                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10825                                .map(|position| (position, bp.bp.clone()))
10826                        } else {
10827                            None
10828                        }
10829                    })
10830            })
10831    }
10832
10833    pub fn edit_log_breakpoint(
10834        &mut self,
10835        _: &EditLogBreakpoint,
10836        window: &mut Window,
10837        cx: &mut Context<Self>,
10838    ) {
10839        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10840            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10841                message: None,
10842                state: BreakpointState::Enabled,
10843                condition: None,
10844                hit_condition: None,
10845            });
10846
10847            self.add_edit_breakpoint_block(
10848                anchor,
10849                &breakpoint,
10850                BreakpointPromptEditAction::Log,
10851                window,
10852                cx,
10853            );
10854        }
10855    }
10856
10857    fn breakpoints_at_cursors(
10858        &self,
10859        window: &mut Window,
10860        cx: &mut Context<Self>,
10861    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10862        let snapshot = self.snapshot(window, cx);
10863        let cursors = self
10864            .selections
10865            .disjoint_anchors_arc()
10866            .iter()
10867            .map(|selection| {
10868                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10869
10870                let breakpoint_position = self
10871                    .breakpoint_at_row(cursor_position.row, window, cx)
10872                    .map(|bp| bp.0)
10873                    .unwrap_or_else(|| {
10874                        snapshot
10875                            .display_snapshot
10876                            .buffer_snapshot
10877                            .anchor_after(Point::new(cursor_position.row, 0))
10878                    });
10879
10880                let breakpoint = self
10881                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10882                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10883
10884                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10885            })
10886            // 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.
10887            .collect::<HashMap<Anchor, _>>();
10888
10889        cursors.into_iter().collect()
10890    }
10891
10892    pub fn enable_breakpoint(
10893        &mut self,
10894        _: &crate::actions::EnableBreakpoint,
10895        window: &mut Window,
10896        cx: &mut Context<Self>,
10897    ) {
10898        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10899            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10900                continue;
10901            };
10902            self.edit_breakpoint_at_anchor(
10903                anchor,
10904                breakpoint,
10905                BreakpointEditAction::InvertState,
10906                cx,
10907            );
10908        }
10909    }
10910
10911    pub fn disable_breakpoint(
10912        &mut self,
10913        _: &crate::actions::DisableBreakpoint,
10914        window: &mut Window,
10915        cx: &mut Context<Self>,
10916    ) {
10917        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10918            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10919                continue;
10920            };
10921            self.edit_breakpoint_at_anchor(
10922                anchor,
10923                breakpoint,
10924                BreakpointEditAction::InvertState,
10925                cx,
10926            );
10927        }
10928    }
10929
10930    pub fn toggle_breakpoint(
10931        &mut self,
10932        _: &crate::actions::ToggleBreakpoint,
10933        window: &mut Window,
10934        cx: &mut Context<Self>,
10935    ) {
10936        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10937            if let Some(breakpoint) = breakpoint {
10938                self.edit_breakpoint_at_anchor(
10939                    anchor,
10940                    breakpoint,
10941                    BreakpointEditAction::Toggle,
10942                    cx,
10943                );
10944            } else {
10945                self.edit_breakpoint_at_anchor(
10946                    anchor,
10947                    Breakpoint::new_standard(),
10948                    BreakpointEditAction::Toggle,
10949                    cx,
10950                );
10951            }
10952        }
10953    }
10954
10955    pub fn edit_breakpoint_at_anchor(
10956        &mut self,
10957        breakpoint_position: Anchor,
10958        breakpoint: Breakpoint,
10959        edit_action: BreakpointEditAction,
10960        cx: &mut Context<Self>,
10961    ) {
10962        let Some(breakpoint_store) = &self.breakpoint_store else {
10963            return;
10964        };
10965
10966        let Some(buffer) = self
10967            .buffer
10968            .read(cx)
10969            .buffer_for_anchor(breakpoint_position, cx)
10970        else {
10971            return;
10972        };
10973
10974        breakpoint_store.update(cx, |breakpoint_store, cx| {
10975            breakpoint_store.toggle_breakpoint(
10976                buffer,
10977                BreakpointWithPosition {
10978                    position: breakpoint_position.text_anchor,
10979                    bp: breakpoint,
10980                },
10981                edit_action,
10982                cx,
10983            );
10984        });
10985
10986        cx.notify();
10987    }
10988
10989    #[cfg(any(test, feature = "test-support"))]
10990    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10991        self.breakpoint_store.clone()
10992    }
10993
10994    pub fn prepare_restore_change(
10995        &self,
10996        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10997        hunk: &MultiBufferDiffHunk,
10998        cx: &mut App,
10999    ) -> Option<()> {
11000        if hunk.is_created_file() {
11001            return None;
11002        }
11003        let buffer = self.buffer.read(cx);
11004        let diff = buffer.diff_for(hunk.buffer_id)?;
11005        let buffer = buffer.buffer(hunk.buffer_id)?;
11006        let buffer = buffer.read(cx);
11007        let original_text = diff
11008            .read(cx)
11009            .base_text()
11010            .as_rope()
11011            .slice(hunk.diff_base_byte_range.clone());
11012        let buffer_snapshot = buffer.snapshot();
11013        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11014        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11015            probe
11016                .0
11017                .start
11018                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11019                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11020        }) {
11021            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11022            Some(())
11023        } else {
11024            None
11025        }
11026    }
11027
11028    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11029        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11030    }
11031
11032    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11033        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11034    }
11035
11036    fn manipulate_lines<M>(
11037        &mut self,
11038        window: &mut Window,
11039        cx: &mut Context<Self>,
11040        mut manipulate: M,
11041    ) where
11042        M: FnMut(&str) -> LineManipulationResult,
11043    {
11044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11045
11046        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11047        let buffer = self.buffer.read(cx).snapshot(cx);
11048
11049        let mut edits = Vec::new();
11050
11051        let selections = self.selections.all::<Point>(cx);
11052        let mut selections = selections.iter().peekable();
11053        let mut contiguous_row_selections = Vec::new();
11054        let mut new_selections = Vec::new();
11055        let mut added_lines = 0;
11056        let mut removed_lines = 0;
11057
11058        while let Some(selection) = selections.next() {
11059            let (start_row, end_row) = consume_contiguous_rows(
11060                &mut contiguous_row_selections,
11061                selection,
11062                &display_map,
11063                &mut selections,
11064            );
11065
11066            let start_point = Point::new(start_row.0, 0);
11067            let end_point = Point::new(
11068                end_row.previous_row().0,
11069                buffer.line_len(end_row.previous_row()),
11070            );
11071            let text = buffer
11072                .text_for_range(start_point..end_point)
11073                .collect::<String>();
11074
11075            let LineManipulationResult {
11076                new_text,
11077                line_count_before,
11078                line_count_after,
11079            } = manipulate(&text);
11080
11081            edits.push((start_point..end_point, new_text));
11082
11083            // Selections must change based on added and removed line count
11084            let start_row =
11085                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11086            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11087            new_selections.push(Selection {
11088                id: selection.id,
11089                start: start_row,
11090                end: end_row,
11091                goal: SelectionGoal::None,
11092                reversed: selection.reversed,
11093            });
11094
11095            if line_count_after > line_count_before {
11096                added_lines += line_count_after - line_count_before;
11097            } else if line_count_before > line_count_after {
11098                removed_lines += line_count_before - line_count_after;
11099            }
11100        }
11101
11102        self.transact(window, cx, |this, window, cx| {
11103            let buffer = this.buffer.update(cx, |buffer, cx| {
11104                buffer.edit(edits, None, cx);
11105                buffer.snapshot(cx)
11106            });
11107
11108            // Recalculate offsets on newly edited buffer
11109            let new_selections = new_selections
11110                .iter()
11111                .map(|s| {
11112                    let start_point = Point::new(s.start.0, 0);
11113                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11114                    Selection {
11115                        id: s.id,
11116                        start: buffer.point_to_offset(start_point),
11117                        end: buffer.point_to_offset(end_point),
11118                        goal: s.goal,
11119                        reversed: s.reversed,
11120                    }
11121                })
11122                .collect();
11123
11124            this.change_selections(Default::default(), window, cx, |s| {
11125                s.select(new_selections);
11126            });
11127
11128            this.request_autoscroll(Autoscroll::fit(), cx);
11129        });
11130    }
11131
11132    fn manipulate_immutable_lines<Fn>(
11133        &mut self,
11134        window: &mut Window,
11135        cx: &mut Context<Self>,
11136        mut callback: Fn,
11137    ) where
11138        Fn: FnMut(&mut Vec<&str>),
11139    {
11140        self.manipulate_lines(window, cx, |text| {
11141            let mut lines: Vec<&str> = text.split('\n').collect();
11142            let line_count_before = lines.len();
11143
11144            callback(&mut lines);
11145
11146            LineManipulationResult {
11147                new_text: lines.join("\n"),
11148                line_count_before,
11149                line_count_after: lines.len(),
11150            }
11151        });
11152    }
11153
11154    fn manipulate_mutable_lines<Fn>(
11155        &mut self,
11156        window: &mut Window,
11157        cx: &mut Context<Self>,
11158        mut callback: Fn,
11159    ) where
11160        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11161    {
11162        self.manipulate_lines(window, cx, |text| {
11163            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11164            let line_count_before = lines.len();
11165
11166            callback(&mut lines);
11167
11168            LineManipulationResult {
11169                new_text: lines.join("\n"),
11170                line_count_before,
11171                line_count_after: lines.len(),
11172            }
11173        });
11174    }
11175
11176    pub fn convert_indentation_to_spaces(
11177        &mut self,
11178        _: &ConvertIndentationToSpaces,
11179        window: &mut Window,
11180        cx: &mut Context<Self>,
11181    ) {
11182        let settings = self.buffer.read(cx).language_settings(cx);
11183        let tab_size = settings.tab_size.get() as usize;
11184
11185        self.manipulate_mutable_lines(window, cx, |lines| {
11186            // Allocates a reasonably sized scratch buffer once for the whole loop
11187            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11188            // Avoids recomputing spaces that could be inserted many times
11189            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11190                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11191                .collect();
11192
11193            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11194                let mut chars = line.as_ref().chars();
11195                let mut col = 0;
11196                let mut changed = false;
11197
11198                for ch in chars.by_ref() {
11199                    match ch {
11200                        ' ' => {
11201                            reindented_line.push(' ');
11202                            col += 1;
11203                        }
11204                        '\t' => {
11205                            // \t are converted to spaces depending on the current column
11206                            let spaces_len = tab_size - (col % tab_size);
11207                            reindented_line.extend(&space_cache[spaces_len - 1]);
11208                            col += spaces_len;
11209                            changed = true;
11210                        }
11211                        _ => {
11212                            // If we dont append before break, the character is consumed
11213                            reindented_line.push(ch);
11214                            break;
11215                        }
11216                    }
11217                }
11218
11219                if !changed {
11220                    reindented_line.clear();
11221                    continue;
11222                }
11223                // Append the rest of the line and replace old reference with new one
11224                reindented_line.extend(chars);
11225                *line = Cow::Owned(reindented_line.clone());
11226                reindented_line.clear();
11227            }
11228        });
11229    }
11230
11231    pub fn convert_indentation_to_tabs(
11232        &mut self,
11233        _: &ConvertIndentationToTabs,
11234        window: &mut Window,
11235        cx: &mut Context<Self>,
11236    ) {
11237        let settings = self.buffer.read(cx).language_settings(cx);
11238        let tab_size = settings.tab_size.get() as usize;
11239
11240        self.manipulate_mutable_lines(window, cx, |lines| {
11241            // Allocates a reasonably sized buffer once for the whole loop
11242            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11243            // Avoids recomputing spaces that could be inserted many times
11244            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11245                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11246                .collect();
11247
11248            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11249                let mut chars = line.chars();
11250                let mut spaces_count = 0;
11251                let mut first_non_indent_char = None;
11252                let mut changed = false;
11253
11254                for ch in chars.by_ref() {
11255                    match ch {
11256                        ' ' => {
11257                            // Keep track of spaces. Append \t when we reach tab_size
11258                            spaces_count += 1;
11259                            changed = true;
11260                            if spaces_count == tab_size {
11261                                reindented_line.push('\t');
11262                                spaces_count = 0;
11263                            }
11264                        }
11265                        '\t' => {
11266                            reindented_line.push('\t');
11267                            spaces_count = 0;
11268                        }
11269                        _ => {
11270                            // Dont append it yet, we might have remaining spaces
11271                            first_non_indent_char = Some(ch);
11272                            break;
11273                        }
11274                    }
11275                }
11276
11277                if !changed {
11278                    reindented_line.clear();
11279                    continue;
11280                }
11281                // Remaining spaces that didn't make a full tab stop
11282                if spaces_count > 0 {
11283                    reindented_line.extend(&space_cache[spaces_count - 1]);
11284                }
11285                // If we consume an extra character that was not indentation, add it back
11286                if let Some(extra_char) = first_non_indent_char {
11287                    reindented_line.push(extra_char);
11288                }
11289                // Append the rest of the line and replace old reference with new one
11290                reindented_line.extend(chars);
11291                *line = Cow::Owned(reindented_line.clone());
11292                reindented_line.clear();
11293            }
11294        });
11295    }
11296
11297    pub fn convert_to_upper_case(
11298        &mut self,
11299        _: &ConvertToUpperCase,
11300        window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        self.manipulate_text(window, cx, |text| text.to_uppercase())
11304    }
11305
11306    pub fn convert_to_lower_case(
11307        &mut self,
11308        _: &ConvertToLowerCase,
11309        window: &mut Window,
11310        cx: &mut Context<Self>,
11311    ) {
11312        self.manipulate_text(window, cx, |text| text.to_lowercase())
11313    }
11314
11315    pub fn convert_to_title_case(
11316        &mut self,
11317        _: &ConvertToTitleCase,
11318        window: &mut Window,
11319        cx: &mut Context<Self>,
11320    ) {
11321        self.manipulate_text(window, cx, |text| {
11322            text.split('\n')
11323                .map(|line| line.to_case(Case::Title))
11324                .join("\n")
11325        })
11326    }
11327
11328    pub fn convert_to_snake_case(
11329        &mut self,
11330        _: &ConvertToSnakeCase,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333    ) {
11334        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11335    }
11336
11337    pub fn convert_to_kebab_case(
11338        &mut self,
11339        _: &ConvertToKebabCase,
11340        window: &mut Window,
11341        cx: &mut Context<Self>,
11342    ) {
11343        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11344    }
11345
11346    pub fn convert_to_upper_camel_case(
11347        &mut self,
11348        _: &ConvertToUpperCamelCase,
11349        window: &mut Window,
11350        cx: &mut Context<Self>,
11351    ) {
11352        self.manipulate_text(window, cx, |text| {
11353            text.split('\n')
11354                .map(|line| line.to_case(Case::UpperCamel))
11355                .join("\n")
11356        })
11357    }
11358
11359    pub fn convert_to_lower_camel_case(
11360        &mut self,
11361        _: &ConvertToLowerCamelCase,
11362        window: &mut Window,
11363        cx: &mut Context<Self>,
11364    ) {
11365        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11366    }
11367
11368    pub fn convert_to_opposite_case(
11369        &mut self,
11370        _: &ConvertToOppositeCase,
11371        window: &mut Window,
11372        cx: &mut Context<Self>,
11373    ) {
11374        self.manipulate_text(window, cx, |text| {
11375            text.chars()
11376                .fold(String::with_capacity(text.len()), |mut t, c| {
11377                    if c.is_uppercase() {
11378                        t.extend(c.to_lowercase());
11379                    } else {
11380                        t.extend(c.to_uppercase());
11381                    }
11382                    t
11383                })
11384        })
11385    }
11386
11387    pub fn convert_to_sentence_case(
11388        &mut self,
11389        _: &ConvertToSentenceCase,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11394    }
11395
11396    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11397        self.manipulate_text(window, cx, |text| {
11398            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11399            if has_upper_case_characters {
11400                text.to_lowercase()
11401            } else {
11402                text.to_uppercase()
11403            }
11404        })
11405    }
11406
11407    pub fn convert_to_rot13(
11408        &mut self,
11409        _: &ConvertToRot13,
11410        window: &mut Window,
11411        cx: &mut Context<Self>,
11412    ) {
11413        self.manipulate_text(window, cx, |text| {
11414            text.chars()
11415                .map(|c| match c {
11416                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11417                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11418                    _ => c,
11419                })
11420                .collect()
11421        })
11422    }
11423
11424    pub fn convert_to_rot47(
11425        &mut self,
11426        _: &ConvertToRot47,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        self.manipulate_text(window, cx, |text| {
11431            text.chars()
11432                .map(|c| {
11433                    let code_point = c as u32;
11434                    if code_point >= 33 && code_point <= 126 {
11435                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11436                    }
11437                    c
11438                })
11439                .collect()
11440        })
11441    }
11442
11443    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11444    where
11445        Fn: FnMut(&str) -> String,
11446    {
11447        let buffer = self.buffer.read(cx).snapshot(cx);
11448
11449        let mut new_selections = Vec::new();
11450        let mut edits = Vec::new();
11451        let mut selection_adjustment = 0i32;
11452
11453        for selection in self.selections.all_adjusted(cx) {
11454            let selection_is_empty = selection.is_empty();
11455
11456            let (start, end) = if selection_is_empty {
11457                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11458                (word_range.start, word_range.end)
11459            } else {
11460                (
11461                    buffer.point_to_offset(selection.start),
11462                    buffer.point_to_offset(selection.end),
11463                )
11464            };
11465
11466            let text = buffer.text_for_range(start..end).collect::<String>();
11467            let old_length = text.len() as i32;
11468            let text = callback(&text);
11469
11470            new_selections.push(Selection {
11471                start: (start as i32 - selection_adjustment) as usize,
11472                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11473                goal: SelectionGoal::None,
11474                id: selection.id,
11475                reversed: selection.reversed,
11476            });
11477
11478            selection_adjustment += old_length - text.len() as i32;
11479
11480            edits.push((start..end, text));
11481        }
11482
11483        self.transact(window, cx, |this, window, cx| {
11484            this.buffer.update(cx, |buffer, cx| {
11485                buffer.edit(edits, None, cx);
11486            });
11487
11488            this.change_selections(Default::default(), window, cx, |s| {
11489                s.select(new_selections);
11490            });
11491
11492            this.request_autoscroll(Autoscroll::fit(), cx);
11493        });
11494    }
11495
11496    pub fn move_selection_on_drop(
11497        &mut self,
11498        selection: &Selection<Anchor>,
11499        target: DisplayPoint,
11500        is_cut: bool,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11505        let buffer = &display_map.buffer_snapshot;
11506        let mut edits = Vec::new();
11507        let insert_point = display_map
11508            .clip_point(target, Bias::Left)
11509            .to_point(&display_map);
11510        let text = buffer
11511            .text_for_range(selection.start..selection.end)
11512            .collect::<String>();
11513        if is_cut {
11514            edits.push(((selection.start..selection.end), String::new()));
11515        }
11516        let insert_anchor = buffer.anchor_before(insert_point);
11517        edits.push(((insert_anchor..insert_anchor), text));
11518        let last_edit_start = insert_anchor.bias_left(buffer);
11519        let last_edit_end = insert_anchor.bias_right(buffer);
11520        self.transact(window, cx, |this, window, cx| {
11521            this.buffer.update(cx, |buffer, cx| {
11522                buffer.edit(edits, None, cx);
11523            });
11524            this.change_selections(Default::default(), window, cx, |s| {
11525                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11526            });
11527        });
11528    }
11529
11530    pub fn clear_selection_drag_state(&mut self) {
11531        self.selection_drag_state = SelectionDragState::None;
11532    }
11533
11534    pub fn duplicate(
11535        &mut self,
11536        upwards: bool,
11537        whole_lines: bool,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) {
11541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11542
11543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11544        let buffer = &display_map.buffer_snapshot;
11545        let selections = self.selections.all::<Point>(cx);
11546
11547        let mut edits = Vec::new();
11548        let mut selections_iter = selections.iter().peekable();
11549        while let Some(selection) = selections_iter.next() {
11550            let mut rows = selection.spanned_rows(false, &display_map);
11551            // duplicate line-wise
11552            if whole_lines || selection.start == selection.end {
11553                // Avoid duplicating the same lines twice.
11554                while let Some(next_selection) = selections_iter.peek() {
11555                    let next_rows = next_selection.spanned_rows(false, &display_map);
11556                    if next_rows.start < rows.end {
11557                        rows.end = next_rows.end;
11558                        selections_iter.next().unwrap();
11559                    } else {
11560                        break;
11561                    }
11562                }
11563
11564                // Copy the text from the selected row region and splice it either at the start
11565                // or end of the region.
11566                let start = Point::new(rows.start.0, 0);
11567                let end = Point::new(
11568                    rows.end.previous_row().0,
11569                    buffer.line_len(rows.end.previous_row()),
11570                );
11571                let text = buffer
11572                    .text_for_range(start..end)
11573                    .chain(Some("\n"))
11574                    .collect::<String>();
11575                let insert_location = if upwards {
11576                    Point::new(rows.end.0, 0)
11577                } else {
11578                    start
11579                };
11580                edits.push((insert_location..insert_location, text));
11581            } else {
11582                // duplicate character-wise
11583                let start = selection.start;
11584                let end = selection.end;
11585                let text = buffer.text_for_range(start..end).collect::<String>();
11586                edits.push((selection.end..selection.end, text));
11587            }
11588        }
11589
11590        self.transact(window, cx, |this, _, cx| {
11591            this.buffer.update(cx, |buffer, cx| {
11592                buffer.edit(edits, None, cx);
11593            });
11594
11595            this.request_autoscroll(Autoscroll::fit(), cx);
11596        });
11597    }
11598
11599    pub fn duplicate_line_up(
11600        &mut self,
11601        _: &DuplicateLineUp,
11602        window: &mut Window,
11603        cx: &mut Context<Self>,
11604    ) {
11605        self.duplicate(true, true, window, cx);
11606    }
11607
11608    pub fn duplicate_line_down(
11609        &mut self,
11610        _: &DuplicateLineDown,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        self.duplicate(false, true, window, cx);
11615    }
11616
11617    pub fn duplicate_selection(
11618        &mut self,
11619        _: &DuplicateSelection,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        self.duplicate(false, false, window, cx);
11624    }
11625
11626    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11628        if self.mode.is_single_line() {
11629            cx.propagate();
11630            return;
11631        }
11632
11633        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11634        let buffer = self.buffer.read(cx).snapshot(cx);
11635
11636        let mut edits = Vec::new();
11637        let mut unfold_ranges = Vec::new();
11638        let mut refold_creases = Vec::new();
11639
11640        let selections = self.selections.all::<Point>(cx);
11641        let mut selections = selections.iter().peekable();
11642        let mut contiguous_row_selections = Vec::new();
11643        let mut new_selections = Vec::new();
11644
11645        while let Some(selection) = selections.next() {
11646            // Find all the selections that span a contiguous row range
11647            let (start_row, end_row) = consume_contiguous_rows(
11648                &mut contiguous_row_selections,
11649                selection,
11650                &display_map,
11651                &mut selections,
11652            );
11653
11654            // Move the text spanned by the row range to be before the line preceding the row range
11655            if start_row.0 > 0 {
11656                let range_to_move = Point::new(
11657                    start_row.previous_row().0,
11658                    buffer.line_len(start_row.previous_row()),
11659                )
11660                    ..Point::new(
11661                        end_row.previous_row().0,
11662                        buffer.line_len(end_row.previous_row()),
11663                    );
11664                let insertion_point = display_map
11665                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11666                    .0;
11667
11668                // Don't move lines across excerpts
11669                if buffer
11670                    .excerpt_containing(insertion_point..range_to_move.end)
11671                    .is_some()
11672                {
11673                    let text = buffer
11674                        .text_for_range(range_to_move.clone())
11675                        .flat_map(|s| s.chars())
11676                        .skip(1)
11677                        .chain(['\n'])
11678                        .collect::<String>();
11679
11680                    edits.push((
11681                        buffer.anchor_after(range_to_move.start)
11682                            ..buffer.anchor_before(range_to_move.end),
11683                        String::new(),
11684                    ));
11685                    let insertion_anchor = buffer.anchor_after(insertion_point);
11686                    edits.push((insertion_anchor..insertion_anchor, text));
11687
11688                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11689
11690                    // Move selections up
11691                    new_selections.extend(contiguous_row_selections.drain(..).map(
11692                        |mut selection| {
11693                            selection.start.row -= row_delta;
11694                            selection.end.row -= row_delta;
11695                            selection
11696                        },
11697                    ));
11698
11699                    // Move folds up
11700                    unfold_ranges.push(range_to_move.clone());
11701                    for fold in display_map.folds_in_range(
11702                        buffer.anchor_before(range_to_move.start)
11703                            ..buffer.anchor_after(range_to_move.end),
11704                    ) {
11705                        let mut start = fold.range.start.to_point(&buffer);
11706                        let mut end = fold.range.end.to_point(&buffer);
11707                        start.row -= row_delta;
11708                        end.row -= row_delta;
11709                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11710                    }
11711                }
11712            }
11713
11714            // If we didn't move line(s), preserve the existing selections
11715            new_selections.append(&mut contiguous_row_selections);
11716        }
11717
11718        self.transact(window, cx, |this, window, cx| {
11719            this.unfold_ranges(&unfold_ranges, true, true, cx);
11720            this.buffer.update(cx, |buffer, cx| {
11721                for (range, text) in edits {
11722                    buffer.edit([(range, text)], None, cx);
11723                }
11724            });
11725            this.fold_creases(refold_creases, true, window, cx);
11726            this.change_selections(Default::default(), window, cx, |s| {
11727                s.select(new_selections);
11728            })
11729        });
11730    }
11731
11732    pub fn move_line_down(
11733        &mut self,
11734        _: &MoveLineDown,
11735        window: &mut Window,
11736        cx: &mut Context<Self>,
11737    ) {
11738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11739        if self.mode.is_single_line() {
11740            cx.propagate();
11741            return;
11742        }
11743
11744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11745        let buffer = self.buffer.read(cx).snapshot(cx);
11746
11747        let mut edits = Vec::new();
11748        let mut unfold_ranges = Vec::new();
11749        let mut refold_creases = Vec::new();
11750
11751        let selections = self.selections.all::<Point>(cx);
11752        let mut selections = selections.iter().peekable();
11753        let mut contiguous_row_selections = Vec::new();
11754        let mut new_selections = Vec::new();
11755
11756        while let Some(selection) = selections.next() {
11757            // Find all the selections that span a contiguous row range
11758            let (start_row, end_row) = consume_contiguous_rows(
11759                &mut contiguous_row_selections,
11760                selection,
11761                &display_map,
11762                &mut selections,
11763            );
11764
11765            // Move the text spanned by the row range to be after the last line of the row range
11766            if end_row.0 <= buffer.max_point().row {
11767                let range_to_move =
11768                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11769                let insertion_point = display_map
11770                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11771                    .0;
11772
11773                // Don't move lines across excerpt boundaries
11774                if buffer
11775                    .excerpt_containing(range_to_move.start..insertion_point)
11776                    .is_some()
11777                {
11778                    let mut text = String::from("\n");
11779                    text.extend(buffer.text_for_range(range_to_move.clone()));
11780                    text.pop(); // Drop trailing newline
11781                    edits.push((
11782                        buffer.anchor_after(range_to_move.start)
11783                            ..buffer.anchor_before(range_to_move.end),
11784                        String::new(),
11785                    ));
11786                    let insertion_anchor = buffer.anchor_after(insertion_point);
11787                    edits.push((insertion_anchor..insertion_anchor, text));
11788
11789                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11790
11791                    // Move selections down
11792                    new_selections.extend(contiguous_row_selections.drain(..).map(
11793                        |mut selection| {
11794                            selection.start.row += row_delta;
11795                            selection.end.row += row_delta;
11796                            selection
11797                        },
11798                    ));
11799
11800                    // Move folds down
11801                    unfold_ranges.push(range_to_move.clone());
11802                    for fold in display_map.folds_in_range(
11803                        buffer.anchor_before(range_to_move.start)
11804                            ..buffer.anchor_after(range_to_move.end),
11805                    ) {
11806                        let mut start = fold.range.start.to_point(&buffer);
11807                        let mut end = fold.range.end.to_point(&buffer);
11808                        start.row += row_delta;
11809                        end.row += row_delta;
11810                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11811                    }
11812                }
11813            }
11814
11815            // If we didn't move line(s), preserve the existing selections
11816            new_selections.append(&mut contiguous_row_selections);
11817        }
11818
11819        self.transact(window, cx, |this, window, cx| {
11820            this.unfold_ranges(&unfold_ranges, true, true, cx);
11821            this.buffer.update(cx, |buffer, cx| {
11822                for (range, text) in edits {
11823                    buffer.edit([(range, text)], None, cx);
11824                }
11825            });
11826            this.fold_creases(refold_creases, true, window, cx);
11827            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11828        });
11829    }
11830
11831    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11833        let text_layout_details = &self.text_layout_details(window);
11834        self.transact(window, cx, |this, window, cx| {
11835            let edits = this.change_selections(Default::default(), window, cx, |s| {
11836                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11837                s.move_with(|display_map, selection| {
11838                    if !selection.is_empty() {
11839                        return;
11840                    }
11841
11842                    let mut head = selection.head();
11843                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11844                    if head.column() == display_map.line_len(head.row()) {
11845                        transpose_offset = display_map
11846                            .buffer_snapshot
11847                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11848                    }
11849
11850                    if transpose_offset == 0 {
11851                        return;
11852                    }
11853
11854                    *head.column_mut() += 1;
11855                    head = display_map.clip_point(head, Bias::Right);
11856                    let goal = SelectionGoal::HorizontalPosition(
11857                        display_map
11858                            .x_for_display_point(head, text_layout_details)
11859                            .into(),
11860                    );
11861                    selection.collapse_to(head, goal);
11862
11863                    let transpose_start = display_map
11864                        .buffer_snapshot
11865                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11866                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11867                        let transpose_end = display_map
11868                            .buffer_snapshot
11869                            .clip_offset(transpose_offset + 1, Bias::Right);
11870                        if let Some(ch) =
11871                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11872                        {
11873                            edits.push((transpose_start..transpose_offset, String::new()));
11874                            edits.push((transpose_end..transpose_end, ch.to_string()));
11875                        }
11876                    }
11877                });
11878                edits
11879            });
11880            this.buffer
11881                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11882            let selections = this.selections.all::<usize>(cx);
11883            this.change_selections(Default::default(), window, cx, |s| {
11884                s.select(selections);
11885            });
11886        });
11887    }
11888
11889    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11891        if self.mode.is_single_line() {
11892            cx.propagate();
11893            return;
11894        }
11895
11896        self.rewrap_impl(RewrapOptions::default(), cx)
11897    }
11898
11899    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11900        let buffer = self.buffer.read(cx).snapshot(cx);
11901        let selections = self.selections.all::<Point>(cx);
11902
11903        #[derive(Clone, Debug, PartialEq)]
11904        enum CommentFormat {
11905            /// single line comment, with prefix for line
11906            Line(String),
11907            /// single line within a block comment, with prefix for line
11908            BlockLine(String),
11909            /// a single line of a block comment that includes the initial delimiter
11910            BlockCommentWithStart(BlockCommentConfig),
11911            /// a single line of a block comment that includes the ending delimiter
11912            BlockCommentWithEnd(BlockCommentConfig),
11913        }
11914
11915        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11916        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11917            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11918                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11919                .peekable();
11920
11921            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11922                row
11923            } else {
11924                return Vec::new();
11925            };
11926
11927            let language_settings = buffer.language_settings_at(selection.head(), cx);
11928            let language_scope = buffer.language_scope_at(selection.head());
11929
11930            let indent_and_prefix_for_row =
11931                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11932                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11933                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11934                        &language_scope
11935                    {
11936                        let indent_end = Point::new(row, indent.len);
11937                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11938                        let line_text_after_indent = buffer
11939                            .text_for_range(indent_end..line_end)
11940                            .collect::<String>();
11941
11942                        let is_within_comment_override = buffer
11943                            .language_scope_at(indent_end)
11944                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11945                        let comment_delimiters = if is_within_comment_override {
11946                            // we are within a comment syntax node, but we don't
11947                            // yet know what kind of comment: block, doc or line
11948                            match (
11949                                language_scope.documentation_comment(),
11950                                language_scope.block_comment(),
11951                            ) {
11952                                (Some(config), _) | (_, Some(config))
11953                                    if buffer.contains_str_at(indent_end, &config.start) =>
11954                                {
11955                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11956                                }
11957                                (Some(config), _) | (_, Some(config))
11958                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11959                                {
11960                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11961                                }
11962                                (Some(config), _) | (_, Some(config))
11963                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11964                                {
11965                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11966                                }
11967                                (_, _) => language_scope
11968                                    .line_comment_prefixes()
11969                                    .iter()
11970                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11971                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11972                            }
11973                        } else {
11974                            // we not in an overridden comment node, but we may
11975                            // be within a non-overridden line comment node
11976                            language_scope
11977                                .line_comment_prefixes()
11978                                .iter()
11979                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11980                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11981                        };
11982
11983                        let rewrap_prefix = language_scope
11984                            .rewrap_prefixes()
11985                            .iter()
11986                            .find_map(|prefix_regex| {
11987                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11988                                    if mat.start() == 0 {
11989                                        Some(mat.as_str().to_string())
11990                                    } else {
11991                                        None
11992                                    }
11993                                })
11994                            })
11995                            .flatten();
11996                        (comment_delimiters, rewrap_prefix)
11997                    } else {
11998                        (None, None)
11999                    };
12000                    (indent, comment_prefix, rewrap_prefix)
12001                };
12002
12003            let mut ranges = Vec::new();
12004            let from_empty_selection = selection.is_empty();
12005
12006            let mut current_range_start = first_row;
12007            let mut prev_row = first_row;
12008            let (
12009                mut current_range_indent,
12010                mut current_range_comment_delimiters,
12011                mut current_range_rewrap_prefix,
12012            ) = indent_and_prefix_for_row(first_row);
12013
12014            for row in non_blank_rows_iter.skip(1) {
12015                let has_paragraph_break = row > prev_row + 1;
12016
12017                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12018                    indent_and_prefix_for_row(row);
12019
12020                let has_indent_change = row_indent != current_range_indent;
12021                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12022
12023                let has_boundary_change = has_comment_change
12024                    || row_rewrap_prefix.is_some()
12025                    || (has_indent_change && current_range_comment_delimiters.is_some());
12026
12027                if has_paragraph_break || has_boundary_change {
12028                    ranges.push((
12029                        language_settings.clone(),
12030                        Point::new(current_range_start, 0)
12031                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12032                        current_range_indent,
12033                        current_range_comment_delimiters.clone(),
12034                        current_range_rewrap_prefix.clone(),
12035                        from_empty_selection,
12036                    ));
12037                    current_range_start = row;
12038                    current_range_indent = row_indent;
12039                    current_range_comment_delimiters = row_comment_delimiters;
12040                    current_range_rewrap_prefix = row_rewrap_prefix;
12041                }
12042                prev_row = row;
12043            }
12044
12045            ranges.push((
12046                language_settings.clone(),
12047                Point::new(current_range_start, 0)
12048                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12049                current_range_indent,
12050                current_range_comment_delimiters,
12051                current_range_rewrap_prefix,
12052                from_empty_selection,
12053            ));
12054
12055            ranges
12056        });
12057
12058        let mut edits = Vec::new();
12059        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12060
12061        for (
12062            language_settings,
12063            wrap_range,
12064            mut indent_size,
12065            comment_prefix,
12066            rewrap_prefix,
12067            from_empty_selection,
12068        ) in wrap_ranges
12069        {
12070            let mut start_row = wrap_range.start.row;
12071            let mut end_row = wrap_range.end.row;
12072
12073            // Skip selections that overlap with a range that has already been rewrapped.
12074            let selection_range = start_row..end_row;
12075            if rewrapped_row_ranges
12076                .iter()
12077                .any(|range| range.overlaps(&selection_range))
12078            {
12079                continue;
12080            }
12081
12082            let tab_size = language_settings.tab_size;
12083
12084            let (line_prefix, inside_comment) = match &comment_prefix {
12085                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12086                    (Some(prefix.as_str()), true)
12087                }
12088                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12089                    (Some(prefix.as_ref()), true)
12090                }
12091                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12092                    start: _,
12093                    end: _,
12094                    prefix,
12095                    tab_size,
12096                })) => {
12097                    indent_size.len += tab_size;
12098                    (Some(prefix.as_ref()), true)
12099                }
12100                None => (None, false),
12101            };
12102            let indent_prefix = indent_size.chars().collect::<String>();
12103            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12104
12105            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12106                RewrapBehavior::InComments => inside_comment,
12107                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12108                RewrapBehavior::Anywhere => true,
12109            };
12110
12111            let should_rewrap = options.override_language_settings
12112                || allow_rewrap_based_on_language
12113                || self.hard_wrap.is_some();
12114            if !should_rewrap {
12115                continue;
12116            }
12117
12118            if from_empty_selection {
12119                'expand_upwards: while start_row > 0 {
12120                    let prev_row = start_row - 1;
12121                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12122                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12123                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12124                    {
12125                        start_row = prev_row;
12126                    } else {
12127                        break 'expand_upwards;
12128                    }
12129                }
12130
12131                'expand_downwards: while end_row < buffer.max_point().row {
12132                    let next_row = end_row + 1;
12133                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12134                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12135                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12136                    {
12137                        end_row = next_row;
12138                    } else {
12139                        break 'expand_downwards;
12140                    }
12141                }
12142            }
12143
12144            let start = Point::new(start_row, 0);
12145            let start_offset = start.to_offset(&buffer);
12146            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12147            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12148            let mut first_line_delimiter = None;
12149            let mut last_line_delimiter = None;
12150            let Some(lines_without_prefixes) = selection_text
12151                .lines()
12152                .enumerate()
12153                .map(|(ix, line)| {
12154                    let line_trimmed = line.trim_start();
12155                    if rewrap_prefix.is_some() && ix > 0 {
12156                        Ok(line_trimmed)
12157                    } else if let Some(
12158                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12159                            start,
12160                            prefix,
12161                            end,
12162                            tab_size,
12163                        })
12164                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12165                            start,
12166                            prefix,
12167                            end,
12168                            tab_size,
12169                        }),
12170                    ) = &comment_prefix
12171                    {
12172                        let line_trimmed = line_trimmed
12173                            .strip_prefix(start.as_ref())
12174                            .map(|s| {
12175                                let mut indent_size = indent_size;
12176                                indent_size.len -= tab_size;
12177                                let indent_prefix: String = indent_size.chars().collect();
12178                                first_line_delimiter = Some((indent_prefix, start));
12179                                s.trim_start()
12180                            })
12181                            .unwrap_or(line_trimmed);
12182                        let line_trimmed = line_trimmed
12183                            .strip_suffix(end.as_ref())
12184                            .map(|s| {
12185                                last_line_delimiter = Some(end);
12186                                s.trim_end()
12187                            })
12188                            .unwrap_or(line_trimmed);
12189                        let line_trimmed = line_trimmed
12190                            .strip_prefix(prefix.as_ref())
12191                            .unwrap_or(line_trimmed);
12192                        Ok(line_trimmed)
12193                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12194                        line_trimmed.strip_prefix(prefix).with_context(|| {
12195                            format!("line did not start with prefix {prefix:?}: {line:?}")
12196                        })
12197                    } else {
12198                        line_trimmed
12199                            .strip_prefix(&line_prefix.trim_start())
12200                            .with_context(|| {
12201                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12202                            })
12203                    }
12204                })
12205                .collect::<Result<Vec<_>, _>>()
12206                .log_err()
12207            else {
12208                continue;
12209            };
12210
12211            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12212                buffer
12213                    .language_settings_at(Point::new(start_row, 0), cx)
12214                    .preferred_line_length as usize
12215            });
12216
12217            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12218                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12219            } else {
12220                line_prefix.clone()
12221            };
12222
12223            let wrapped_text = {
12224                let mut wrapped_text = wrap_with_prefix(
12225                    line_prefix,
12226                    subsequent_lines_prefix,
12227                    lines_without_prefixes.join("\n"),
12228                    wrap_column,
12229                    tab_size,
12230                    options.preserve_existing_whitespace,
12231                );
12232
12233                if let Some((indent, delimiter)) = first_line_delimiter {
12234                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12235                }
12236                if let Some(last_line) = last_line_delimiter {
12237                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12238                }
12239
12240                wrapped_text
12241            };
12242
12243            // TODO: should always use char-based diff while still supporting cursor behavior that
12244            // matches vim.
12245            let mut diff_options = DiffOptions::default();
12246            if options.override_language_settings {
12247                diff_options.max_word_diff_len = 0;
12248                diff_options.max_word_diff_line_count = 0;
12249            } else {
12250                diff_options.max_word_diff_len = usize::MAX;
12251                diff_options.max_word_diff_line_count = usize::MAX;
12252            }
12253
12254            for (old_range, new_text) in
12255                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12256            {
12257                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12258                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12259                edits.push((edit_start..edit_end, new_text));
12260            }
12261
12262            rewrapped_row_ranges.push(start_row..=end_row);
12263        }
12264
12265        self.buffer
12266            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12267    }
12268
12269    pub fn cut_common(
12270        &mut self,
12271        cut_no_selection_line: bool,
12272        window: &mut Window,
12273        cx: &mut Context<Self>,
12274    ) -> ClipboardItem {
12275        let mut text = String::new();
12276        let buffer = self.buffer.read(cx).snapshot(cx);
12277        let mut selections = self.selections.all::<Point>(cx);
12278        let mut clipboard_selections = Vec::with_capacity(selections.len());
12279        {
12280            let max_point = buffer.max_point();
12281            let mut is_first = true;
12282            for selection in &mut selections {
12283                let is_entire_line =
12284                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12285                if is_entire_line {
12286                    selection.start = Point::new(selection.start.row, 0);
12287                    if !selection.is_empty() && selection.end.column == 0 {
12288                        selection.end = cmp::min(max_point, selection.end);
12289                    } else {
12290                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12291                    }
12292                    selection.goal = SelectionGoal::None;
12293                }
12294                if is_first {
12295                    is_first = false;
12296                } else {
12297                    text += "\n";
12298                }
12299                let mut len = 0;
12300                for chunk in buffer.text_for_range(selection.start..selection.end) {
12301                    text.push_str(chunk);
12302                    len += chunk.len();
12303                }
12304                clipboard_selections.push(ClipboardSelection {
12305                    len,
12306                    is_entire_line,
12307                    first_line_indent: buffer
12308                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12309                        .len,
12310                });
12311            }
12312        }
12313
12314        self.transact(window, cx, |this, window, cx| {
12315            this.change_selections(Default::default(), window, cx, |s| {
12316                s.select(selections);
12317            });
12318            this.insert("", window, cx);
12319        });
12320        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12321    }
12322
12323    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12324        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12325        let item = self.cut_common(true, window, cx);
12326        cx.write_to_clipboard(item);
12327    }
12328
12329    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12330        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12331        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12332            s.move_with(|snapshot, sel| {
12333                if sel.is_empty() {
12334                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12335                }
12336                if sel.is_empty() {
12337                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12338                }
12339            });
12340        });
12341        let item = self.cut_common(false, window, cx);
12342        cx.set_global(KillRing(item))
12343    }
12344
12345    pub fn kill_ring_yank(
12346        &mut self,
12347        _: &KillRingYank,
12348        window: &mut Window,
12349        cx: &mut Context<Self>,
12350    ) {
12351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12352        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12353            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12354                (kill_ring.text().to_string(), kill_ring.metadata_json())
12355            } else {
12356                return;
12357            }
12358        } else {
12359            return;
12360        };
12361        self.do_paste(&text, metadata, false, window, cx);
12362    }
12363
12364    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12365        self.do_copy(true, cx);
12366    }
12367
12368    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12369        self.do_copy(false, cx);
12370    }
12371
12372    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12373        let selections = self.selections.all::<Point>(cx);
12374        let buffer = self.buffer.read(cx).read(cx);
12375        let mut text = String::new();
12376
12377        let mut clipboard_selections = Vec::with_capacity(selections.len());
12378        {
12379            let max_point = buffer.max_point();
12380            let mut is_first = true;
12381            for selection in &selections {
12382                let mut start = selection.start;
12383                let mut end = selection.end;
12384                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12385                if is_entire_line {
12386                    start = Point::new(start.row, 0);
12387                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12388                }
12389
12390                let mut trimmed_selections = Vec::new();
12391                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12392                    let row = MultiBufferRow(start.row);
12393                    let first_indent = buffer.indent_size_for_line(row);
12394                    if first_indent.len == 0 || start.column > first_indent.len {
12395                        trimmed_selections.push(start..end);
12396                    } else {
12397                        trimmed_selections.push(
12398                            Point::new(row.0, first_indent.len)
12399                                ..Point::new(row.0, buffer.line_len(row)),
12400                        );
12401                        for row in start.row + 1..=end.row {
12402                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12403                            if row == end.row {
12404                                line_len = end.column;
12405                            }
12406                            if line_len == 0 {
12407                                trimmed_selections
12408                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12409                                continue;
12410                            }
12411                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12412                            if row_indent_size.len >= first_indent.len {
12413                                trimmed_selections.push(
12414                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12415                                );
12416                            } else {
12417                                trimmed_selections.clear();
12418                                trimmed_selections.push(start..end);
12419                                break;
12420                            }
12421                        }
12422                    }
12423                } else {
12424                    trimmed_selections.push(start..end);
12425                }
12426
12427                for trimmed_range in trimmed_selections {
12428                    if is_first {
12429                        is_first = false;
12430                    } else {
12431                        text += "\n";
12432                    }
12433                    let mut len = 0;
12434                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12435                        text.push_str(chunk);
12436                        len += chunk.len();
12437                    }
12438                    clipboard_selections.push(ClipboardSelection {
12439                        len,
12440                        is_entire_line,
12441                        first_line_indent: buffer
12442                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12443                            .len,
12444                    });
12445                }
12446            }
12447        }
12448
12449        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12450            text,
12451            clipboard_selections,
12452        ));
12453    }
12454
12455    pub fn do_paste(
12456        &mut self,
12457        text: &String,
12458        clipboard_selections: Option<Vec<ClipboardSelection>>,
12459        handle_entire_lines: bool,
12460        window: &mut Window,
12461        cx: &mut Context<Self>,
12462    ) {
12463        if self.read_only(cx) {
12464            return;
12465        }
12466
12467        let clipboard_text = Cow::Borrowed(text.as_str());
12468
12469        self.transact(window, cx, |this, window, cx| {
12470            let had_active_edit_prediction = this.has_active_edit_prediction();
12471            let old_selections = this.selections.all::<usize>(cx);
12472            let cursor_offset = this.selections.last::<usize>(cx).head();
12473
12474            if let Some(mut clipboard_selections) = clipboard_selections {
12475                let all_selections_were_entire_line =
12476                    clipboard_selections.iter().all(|s| s.is_entire_line);
12477                let first_selection_indent_column =
12478                    clipboard_selections.first().map(|s| s.first_line_indent);
12479                if clipboard_selections.len() != old_selections.len() {
12480                    clipboard_selections.drain(..);
12481                }
12482                let mut auto_indent_on_paste = true;
12483
12484                this.buffer.update(cx, |buffer, cx| {
12485                    let snapshot = buffer.read(cx);
12486                    auto_indent_on_paste = snapshot
12487                        .language_settings_at(cursor_offset, cx)
12488                        .auto_indent_on_paste;
12489
12490                    let mut start_offset = 0;
12491                    let mut edits = Vec::new();
12492                    let mut original_indent_columns = Vec::new();
12493                    for (ix, selection) in old_selections.iter().enumerate() {
12494                        let to_insert;
12495                        let entire_line;
12496                        let original_indent_column;
12497                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12498                            let end_offset = start_offset + clipboard_selection.len;
12499                            to_insert = &clipboard_text[start_offset..end_offset];
12500                            entire_line = clipboard_selection.is_entire_line;
12501                            start_offset = end_offset + 1;
12502                            original_indent_column = Some(clipboard_selection.first_line_indent);
12503                        } else {
12504                            to_insert = &*clipboard_text;
12505                            entire_line = all_selections_were_entire_line;
12506                            original_indent_column = first_selection_indent_column
12507                        }
12508
12509                        let (range, to_insert) =
12510                            if selection.is_empty() && handle_entire_lines && entire_line {
12511                                // If the corresponding selection was empty when this slice of the
12512                                // clipboard text was written, then the entire line containing the
12513                                // selection was copied. If this selection is also currently empty,
12514                                // then paste the line before the current line of the buffer.
12515                                let column = selection.start.to_point(&snapshot).column as usize;
12516                                let line_start = selection.start - column;
12517                                (line_start..line_start, Cow::Borrowed(to_insert))
12518                            } else {
12519                                let language = snapshot.language_at(selection.head());
12520                                let range = selection.range();
12521                                if let Some(language) = language
12522                                    && language.name() == "Markdown".into()
12523                                {
12524                                    edit_for_markdown_paste(
12525                                        &snapshot,
12526                                        range,
12527                                        to_insert,
12528                                        url::Url::parse(to_insert).ok(),
12529                                    )
12530                                } else {
12531                                    (range, Cow::Borrowed(to_insert))
12532                                }
12533                            };
12534
12535                        edits.push((range, to_insert));
12536                        original_indent_columns.push(original_indent_column);
12537                    }
12538                    drop(snapshot);
12539
12540                    buffer.edit(
12541                        edits,
12542                        if auto_indent_on_paste {
12543                            Some(AutoindentMode::Block {
12544                                original_indent_columns,
12545                            })
12546                        } else {
12547                            None
12548                        },
12549                        cx,
12550                    );
12551                });
12552
12553                let selections = this.selections.all::<usize>(cx);
12554                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12555            } else {
12556                let url = url::Url::parse(&clipboard_text).ok();
12557
12558                let auto_indent_mode = if !clipboard_text.is_empty() {
12559                    Some(AutoindentMode::Block {
12560                        original_indent_columns: Vec::new(),
12561                    })
12562                } else {
12563                    None
12564                };
12565
12566                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12567                    let snapshot = buffer.snapshot(cx);
12568
12569                    let anchors = old_selections
12570                        .iter()
12571                        .map(|s| {
12572                            let anchor = snapshot.anchor_after(s.head());
12573                            s.map(|_| anchor)
12574                        })
12575                        .collect::<Vec<_>>();
12576
12577                    let mut edits = Vec::new();
12578
12579                    for selection in old_selections.iter() {
12580                        let language = snapshot.language_at(selection.head());
12581                        let range = selection.range();
12582
12583                        let (edit_range, edit_text) = if let Some(language) = language
12584                            && language.name() == "Markdown".into()
12585                        {
12586                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12587                        } else {
12588                            (range, clipboard_text.clone())
12589                        };
12590
12591                        edits.push((edit_range, edit_text));
12592                    }
12593
12594                    drop(snapshot);
12595                    buffer.edit(edits, auto_indent_mode, cx);
12596
12597                    anchors
12598                });
12599
12600                this.change_selections(Default::default(), window, cx, |s| {
12601                    s.select_anchors(selection_anchors);
12602                });
12603            }
12604
12605            let trigger_in_words =
12606                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12607
12608            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12609        });
12610    }
12611
12612    pub fn diff_clipboard_with_selection(
12613        &mut self,
12614        _: &DiffClipboardWithSelection,
12615        window: &mut Window,
12616        cx: &mut Context<Self>,
12617    ) {
12618        let selections = self.selections.all::<usize>(cx);
12619
12620        if selections.is_empty() {
12621            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12622            return;
12623        };
12624
12625        let clipboard_text = match cx.read_from_clipboard() {
12626            Some(item) => match item.entries().first() {
12627                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12628                _ => None,
12629            },
12630            None => None,
12631        };
12632
12633        let Some(clipboard_text) = clipboard_text else {
12634            log::warn!("Clipboard doesn't contain text.");
12635            return;
12636        };
12637
12638        window.dispatch_action(
12639            Box::new(DiffClipboardWithSelectionData {
12640                clipboard_text,
12641                editor: cx.entity(),
12642            }),
12643            cx,
12644        );
12645    }
12646
12647    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12649        if let Some(item) = cx.read_from_clipboard() {
12650            let entries = item.entries();
12651
12652            match entries.first() {
12653                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12654                // of all the pasted entries.
12655                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12656                    .do_paste(
12657                        clipboard_string.text(),
12658                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12659                        true,
12660                        window,
12661                        cx,
12662                    ),
12663                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12664            }
12665        }
12666    }
12667
12668    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12669        if self.read_only(cx) {
12670            return;
12671        }
12672
12673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12674
12675        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12676            if let Some((selections, _)) =
12677                self.selection_history.transaction(transaction_id).cloned()
12678            {
12679                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12680                    s.select_anchors(selections.to_vec());
12681                });
12682            } else {
12683                log::error!(
12684                    "No entry in selection_history found for undo. \
12685                     This may correspond to a bug where undo does not update the selection. \
12686                     If this is occurring, please add details to \
12687                     https://github.com/zed-industries/zed/issues/22692"
12688                );
12689            }
12690            self.request_autoscroll(Autoscroll::fit(), cx);
12691            self.unmark_text(window, cx);
12692            self.refresh_edit_prediction(true, false, window, cx);
12693            cx.emit(EditorEvent::Edited { transaction_id });
12694            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12695        }
12696    }
12697
12698    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12699        if self.read_only(cx) {
12700            return;
12701        }
12702
12703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12704
12705        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12706            if let Some((_, Some(selections))) =
12707                self.selection_history.transaction(transaction_id).cloned()
12708            {
12709                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12710                    s.select_anchors(selections.to_vec());
12711                });
12712            } else {
12713                log::error!(
12714                    "No entry in selection_history found for redo. \
12715                     This may correspond to a bug where undo does not update the selection. \
12716                     If this is occurring, please add details to \
12717                     https://github.com/zed-industries/zed/issues/22692"
12718                );
12719            }
12720            self.request_autoscroll(Autoscroll::fit(), cx);
12721            self.unmark_text(window, cx);
12722            self.refresh_edit_prediction(true, false, window, cx);
12723            cx.emit(EditorEvent::Edited { transaction_id });
12724        }
12725    }
12726
12727    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12728        self.buffer
12729            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12730    }
12731
12732    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12733        self.buffer
12734            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12735    }
12736
12737    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12738        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12739        self.change_selections(Default::default(), window, cx, |s| {
12740            s.move_with(|map, selection| {
12741                let cursor = if selection.is_empty() {
12742                    movement::left(map, selection.start)
12743                } else {
12744                    selection.start
12745                };
12746                selection.collapse_to(cursor, SelectionGoal::None);
12747            });
12748        })
12749    }
12750
12751    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12753        self.change_selections(Default::default(), window, cx, |s| {
12754            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12755        })
12756    }
12757
12758    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12760        self.change_selections(Default::default(), window, cx, |s| {
12761            s.move_with(|map, selection| {
12762                let cursor = if selection.is_empty() {
12763                    movement::right(map, selection.end)
12764                } else {
12765                    selection.end
12766                };
12767                selection.collapse_to(cursor, SelectionGoal::None)
12768            });
12769        })
12770    }
12771
12772    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12774        self.change_selections(Default::default(), window, cx, |s| {
12775            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12776        })
12777    }
12778
12779    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12780        if self.take_rename(true, window, cx).is_some() {
12781            return;
12782        }
12783
12784        if self.mode.is_single_line() {
12785            cx.propagate();
12786            return;
12787        }
12788
12789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12790
12791        let text_layout_details = &self.text_layout_details(window);
12792        let selection_count = self.selections.count();
12793        let first_selection = self.selections.first_anchor();
12794
12795        self.change_selections(Default::default(), window, cx, |s| {
12796            s.move_with(|map, selection| {
12797                if !selection.is_empty() {
12798                    selection.goal = SelectionGoal::None;
12799                }
12800                let (cursor, goal) = movement::up(
12801                    map,
12802                    selection.start,
12803                    selection.goal,
12804                    false,
12805                    text_layout_details,
12806                );
12807                selection.collapse_to(cursor, goal);
12808            });
12809        });
12810
12811        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12812        {
12813            cx.propagate();
12814        }
12815    }
12816
12817    pub fn move_up_by_lines(
12818        &mut self,
12819        action: &MoveUpByLines,
12820        window: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) {
12823        if self.take_rename(true, window, cx).is_some() {
12824            return;
12825        }
12826
12827        if self.mode.is_single_line() {
12828            cx.propagate();
12829            return;
12830        }
12831
12832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12833
12834        let text_layout_details = &self.text_layout_details(window);
12835
12836        self.change_selections(Default::default(), window, cx, |s| {
12837            s.move_with(|map, selection| {
12838                if !selection.is_empty() {
12839                    selection.goal = SelectionGoal::None;
12840                }
12841                let (cursor, goal) = movement::up_by_rows(
12842                    map,
12843                    selection.start,
12844                    action.lines,
12845                    selection.goal,
12846                    false,
12847                    text_layout_details,
12848                );
12849                selection.collapse_to(cursor, goal);
12850            });
12851        })
12852    }
12853
12854    pub fn move_down_by_lines(
12855        &mut self,
12856        action: &MoveDownByLines,
12857        window: &mut Window,
12858        cx: &mut Context<Self>,
12859    ) {
12860        if self.take_rename(true, window, cx).is_some() {
12861            return;
12862        }
12863
12864        if self.mode.is_single_line() {
12865            cx.propagate();
12866            return;
12867        }
12868
12869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12870
12871        let text_layout_details = &self.text_layout_details(window);
12872
12873        self.change_selections(Default::default(), window, cx, |s| {
12874            s.move_with(|map, selection| {
12875                if !selection.is_empty() {
12876                    selection.goal = SelectionGoal::None;
12877                }
12878                let (cursor, goal) = movement::down_by_rows(
12879                    map,
12880                    selection.start,
12881                    action.lines,
12882                    selection.goal,
12883                    false,
12884                    text_layout_details,
12885                );
12886                selection.collapse_to(cursor, goal);
12887            });
12888        })
12889    }
12890
12891    pub fn select_down_by_lines(
12892        &mut self,
12893        action: &SelectDownByLines,
12894        window: &mut Window,
12895        cx: &mut Context<Self>,
12896    ) {
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898        let text_layout_details = &self.text_layout_details(window);
12899        self.change_selections(Default::default(), window, cx, |s| {
12900            s.move_heads_with(|map, head, goal| {
12901                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12902            })
12903        })
12904    }
12905
12906    pub fn select_up_by_lines(
12907        &mut self,
12908        action: &SelectUpByLines,
12909        window: &mut Window,
12910        cx: &mut Context<Self>,
12911    ) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        let text_layout_details = &self.text_layout_details(window);
12914        self.change_selections(Default::default(), window, cx, |s| {
12915            s.move_heads_with(|map, head, goal| {
12916                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12917            })
12918        })
12919    }
12920
12921    pub fn select_page_up(
12922        &mut self,
12923        _: &SelectPageUp,
12924        window: &mut Window,
12925        cx: &mut Context<Self>,
12926    ) {
12927        let Some(row_count) = self.visible_row_count() else {
12928            return;
12929        };
12930
12931        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12932
12933        let text_layout_details = &self.text_layout_details(window);
12934
12935        self.change_selections(Default::default(), window, cx, |s| {
12936            s.move_heads_with(|map, head, goal| {
12937                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12938            })
12939        })
12940    }
12941
12942    pub fn move_page_up(
12943        &mut self,
12944        action: &MovePageUp,
12945        window: &mut Window,
12946        cx: &mut Context<Self>,
12947    ) {
12948        if self.take_rename(true, window, cx).is_some() {
12949            return;
12950        }
12951
12952        if self
12953            .context_menu
12954            .borrow_mut()
12955            .as_mut()
12956            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12957            .unwrap_or(false)
12958        {
12959            return;
12960        }
12961
12962        if matches!(self.mode, EditorMode::SingleLine) {
12963            cx.propagate();
12964            return;
12965        }
12966
12967        let Some(row_count) = self.visible_row_count() else {
12968            return;
12969        };
12970
12971        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12972
12973        let effects = if action.center_cursor {
12974            SelectionEffects::scroll(Autoscroll::center())
12975        } else {
12976            SelectionEffects::default()
12977        };
12978
12979        let text_layout_details = &self.text_layout_details(window);
12980
12981        self.change_selections(effects, window, cx, |s| {
12982            s.move_with(|map, selection| {
12983                if !selection.is_empty() {
12984                    selection.goal = SelectionGoal::None;
12985                }
12986                let (cursor, goal) = movement::up_by_rows(
12987                    map,
12988                    selection.end,
12989                    row_count,
12990                    selection.goal,
12991                    false,
12992                    text_layout_details,
12993                );
12994                selection.collapse_to(cursor, goal);
12995            });
12996        });
12997    }
12998
12999    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13001        let text_layout_details = &self.text_layout_details(window);
13002        self.change_selections(Default::default(), window, cx, |s| {
13003            s.move_heads_with(|map, head, goal| {
13004                movement::up(map, head, goal, false, text_layout_details)
13005            })
13006        })
13007    }
13008
13009    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13010        self.take_rename(true, window, cx);
13011
13012        if self.mode.is_single_line() {
13013            cx.propagate();
13014            return;
13015        }
13016
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13018
13019        let text_layout_details = &self.text_layout_details(window);
13020        let selection_count = self.selections.count();
13021        let first_selection = self.selections.first_anchor();
13022
13023        self.change_selections(Default::default(), window, cx, |s| {
13024            s.move_with(|map, selection| {
13025                if !selection.is_empty() {
13026                    selection.goal = SelectionGoal::None;
13027                }
13028                let (cursor, goal) = movement::down(
13029                    map,
13030                    selection.end,
13031                    selection.goal,
13032                    false,
13033                    text_layout_details,
13034                );
13035                selection.collapse_to(cursor, goal);
13036            });
13037        });
13038
13039        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13040        {
13041            cx.propagate();
13042        }
13043    }
13044
13045    pub fn select_page_down(
13046        &mut self,
13047        _: &SelectPageDown,
13048        window: &mut Window,
13049        cx: &mut Context<Self>,
13050    ) {
13051        let Some(row_count) = self.visible_row_count() else {
13052            return;
13053        };
13054
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13056
13057        let text_layout_details = &self.text_layout_details(window);
13058
13059        self.change_selections(Default::default(), window, cx, |s| {
13060            s.move_heads_with(|map, head, goal| {
13061                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13062            })
13063        })
13064    }
13065
13066    pub fn move_page_down(
13067        &mut self,
13068        action: &MovePageDown,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        if self.take_rename(true, window, cx).is_some() {
13073            return;
13074        }
13075
13076        if self
13077            .context_menu
13078            .borrow_mut()
13079            .as_mut()
13080            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13081            .unwrap_or(false)
13082        {
13083            return;
13084        }
13085
13086        if matches!(self.mode, EditorMode::SingleLine) {
13087            cx.propagate();
13088            return;
13089        }
13090
13091        let Some(row_count) = self.visible_row_count() else {
13092            return;
13093        };
13094
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13096
13097        let effects = if action.center_cursor {
13098            SelectionEffects::scroll(Autoscroll::center())
13099        } else {
13100            SelectionEffects::default()
13101        };
13102
13103        let text_layout_details = &self.text_layout_details(window);
13104        self.change_selections(effects, window, cx, |s| {
13105            s.move_with(|map, selection| {
13106                if !selection.is_empty() {
13107                    selection.goal = SelectionGoal::None;
13108                }
13109                let (cursor, goal) = movement::down_by_rows(
13110                    map,
13111                    selection.end,
13112                    row_count,
13113                    selection.goal,
13114                    false,
13115                    text_layout_details,
13116                );
13117                selection.collapse_to(cursor, goal);
13118            });
13119        });
13120    }
13121
13122    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13124        let text_layout_details = &self.text_layout_details(window);
13125        self.change_selections(Default::default(), window, cx, |s| {
13126            s.move_heads_with(|map, head, goal| {
13127                movement::down(map, head, goal, false, text_layout_details)
13128            })
13129        });
13130    }
13131
13132    pub fn context_menu_first(
13133        &mut self,
13134        _: &ContextMenuFirst,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13139            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13140        }
13141    }
13142
13143    pub fn context_menu_prev(
13144        &mut self,
13145        _: &ContextMenuPrevious,
13146        window: &mut Window,
13147        cx: &mut Context<Self>,
13148    ) {
13149        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13150            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13151        }
13152    }
13153
13154    pub fn context_menu_next(
13155        &mut self,
13156        _: &ContextMenuNext,
13157        window: &mut Window,
13158        cx: &mut Context<Self>,
13159    ) {
13160        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13161            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13162        }
13163    }
13164
13165    pub fn context_menu_last(
13166        &mut self,
13167        _: &ContextMenuLast,
13168        window: &mut Window,
13169        cx: &mut Context<Self>,
13170    ) {
13171        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13172            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13173        }
13174    }
13175
13176    pub fn signature_help_prev(
13177        &mut self,
13178        _: &SignatureHelpPrevious,
13179        _: &mut Window,
13180        cx: &mut Context<Self>,
13181    ) {
13182        if let Some(popover) = self.signature_help_state.popover_mut() {
13183            if popover.current_signature == 0 {
13184                popover.current_signature = popover.signatures.len() - 1;
13185            } else {
13186                popover.current_signature -= 1;
13187            }
13188            cx.notify();
13189        }
13190    }
13191
13192    pub fn signature_help_next(
13193        &mut self,
13194        _: &SignatureHelpNext,
13195        _: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        if let Some(popover) = self.signature_help_state.popover_mut() {
13199            if popover.current_signature + 1 == popover.signatures.len() {
13200                popover.current_signature = 0;
13201            } else {
13202                popover.current_signature += 1;
13203            }
13204            cx.notify();
13205        }
13206    }
13207
13208    pub fn move_to_previous_word_start(
13209        &mut self,
13210        _: &MoveToPreviousWordStart,
13211        window: &mut Window,
13212        cx: &mut Context<Self>,
13213    ) {
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13215        self.change_selections(Default::default(), window, cx, |s| {
13216            s.move_cursors_with(|map, head, _| {
13217                (
13218                    movement::previous_word_start(map, head),
13219                    SelectionGoal::None,
13220                )
13221            });
13222        })
13223    }
13224
13225    pub fn move_to_previous_subword_start(
13226        &mut self,
13227        _: &MoveToPreviousSubwordStart,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13232        self.change_selections(Default::default(), window, cx, |s| {
13233            s.move_cursors_with(|map, head, _| {
13234                (
13235                    movement::previous_subword_start(map, head),
13236                    SelectionGoal::None,
13237                )
13238            });
13239        })
13240    }
13241
13242    pub fn select_to_previous_word_start(
13243        &mut self,
13244        _: &SelectToPreviousWordStart,
13245        window: &mut Window,
13246        cx: &mut Context<Self>,
13247    ) {
13248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13249        self.change_selections(Default::default(), window, cx, |s| {
13250            s.move_heads_with(|map, head, _| {
13251                (
13252                    movement::previous_word_start(map, head),
13253                    SelectionGoal::None,
13254                )
13255            });
13256        })
13257    }
13258
13259    pub fn select_to_previous_subword_start(
13260        &mut self,
13261        _: &SelectToPreviousSubwordStart,
13262        window: &mut Window,
13263        cx: &mut Context<Self>,
13264    ) {
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266        self.change_selections(Default::default(), window, cx, |s| {
13267            s.move_heads_with(|map, head, _| {
13268                (
13269                    movement::previous_subword_start(map, head),
13270                    SelectionGoal::None,
13271                )
13272            });
13273        })
13274    }
13275
13276    pub fn delete_to_previous_word_start(
13277        &mut self,
13278        action: &DeleteToPreviousWordStart,
13279        window: &mut Window,
13280        cx: &mut Context<Self>,
13281    ) {
13282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13283        self.transact(window, cx, |this, window, cx| {
13284            this.select_autoclose_pair(window, cx);
13285            this.change_selections(Default::default(), window, cx, |s| {
13286                s.move_with(|map, selection| {
13287                    if selection.is_empty() {
13288                        let mut cursor = if action.ignore_newlines {
13289                            movement::previous_word_start(map, selection.head())
13290                        } else {
13291                            movement::previous_word_start_or_newline(map, selection.head())
13292                        };
13293                        cursor = movement::adjust_greedy_deletion(
13294                            map,
13295                            selection.head(),
13296                            cursor,
13297                            action.ignore_brackets,
13298                        );
13299                        selection.set_head(cursor, SelectionGoal::None);
13300                    }
13301                });
13302            });
13303            this.insert("", window, cx);
13304        });
13305    }
13306
13307    pub fn delete_to_previous_subword_start(
13308        &mut self,
13309        _: &DeleteToPreviousSubwordStart,
13310        window: &mut Window,
13311        cx: &mut Context<Self>,
13312    ) {
13313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13314        self.transact(window, cx, |this, window, cx| {
13315            this.select_autoclose_pair(window, cx);
13316            this.change_selections(Default::default(), window, cx, |s| {
13317                s.move_with(|map, selection| {
13318                    if selection.is_empty() {
13319                        let mut cursor = movement::previous_subword_start(map, selection.head());
13320                        cursor =
13321                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13322                        selection.set_head(cursor, SelectionGoal::None);
13323                    }
13324                });
13325            });
13326            this.insert("", window, cx);
13327        });
13328    }
13329
13330    pub fn move_to_next_word_end(
13331        &mut self,
13332        _: &MoveToNextWordEnd,
13333        window: &mut Window,
13334        cx: &mut Context<Self>,
13335    ) {
13336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13337        self.change_selections(Default::default(), window, cx, |s| {
13338            s.move_cursors_with(|map, head, _| {
13339                (movement::next_word_end(map, head), SelectionGoal::None)
13340            });
13341        })
13342    }
13343
13344    pub fn move_to_next_subword_end(
13345        &mut self,
13346        _: &MoveToNextSubwordEnd,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13351        self.change_selections(Default::default(), window, cx, |s| {
13352            s.move_cursors_with(|map, head, _| {
13353                (movement::next_subword_end(map, head), SelectionGoal::None)
13354            });
13355        })
13356    }
13357
13358    pub fn select_to_next_word_end(
13359        &mut self,
13360        _: &SelectToNextWordEnd,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13365        self.change_selections(Default::default(), window, cx, |s| {
13366            s.move_heads_with(|map, head, _| {
13367                (movement::next_word_end(map, head), SelectionGoal::None)
13368            });
13369        })
13370    }
13371
13372    pub fn select_to_next_subword_end(
13373        &mut self,
13374        _: &SelectToNextSubwordEnd,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.move_heads_with(|map, head, _| {
13381                (movement::next_subword_end(map, head), SelectionGoal::None)
13382            });
13383        })
13384    }
13385
13386    pub fn delete_to_next_word_end(
13387        &mut self,
13388        action: &DeleteToNextWordEnd,
13389        window: &mut Window,
13390        cx: &mut Context<Self>,
13391    ) {
13392        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13393        self.transact(window, cx, |this, window, cx| {
13394            this.change_selections(Default::default(), window, cx, |s| {
13395                s.move_with(|map, selection| {
13396                    if selection.is_empty() {
13397                        let mut cursor = if action.ignore_newlines {
13398                            movement::next_word_end(map, selection.head())
13399                        } else {
13400                            movement::next_word_end_or_newline(map, selection.head())
13401                        };
13402                        cursor = movement::adjust_greedy_deletion(
13403                            map,
13404                            selection.head(),
13405                            cursor,
13406                            action.ignore_brackets,
13407                        );
13408                        selection.set_head(cursor, SelectionGoal::None);
13409                    }
13410                });
13411            });
13412            this.insert("", window, cx);
13413        });
13414    }
13415
13416    pub fn delete_to_next_subword_end(
13417        &mut self,
13418        _: &DeleteToNextSubwordEnd,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13423        self.transact(window, cx, |this, window, cx| {
13424            this.change_selections(Default::default(), window, cx, |s| {
13425                s.move_with(|map, selection| {
13426                    if selection.is_empty() {
13427                        let mut cursor = movement::next_subword_end(map, selection.head());
13428                        cursor =
13429                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13430                        selection.set_head(cursor, SelectionGoal::None);
13431                    }
13432                });
13433            });
13434            this.insert("", window, cx);
13435        });
13436    }
13437
13438    pub fn move_to_beginning_of_line(
13439        &mut self,
13440        action: &MoveToBeginningOfLine,
13441        window: &mut Window,
13442        cx: &mut Context<Self>,
13443    ) {
13444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13445        self.change_selections(Default::default(), window, cx, |s| {
13446            s.move_cursors_with(|map, head, _| {
13447                (
13448                    movement::indented_line_beginning(
13449                        map,
13450                        head,
13451                        action.stop_at_soft_wraps,
13452                        action.stop_at_indent,
13453                    ),
13454                    SelectionGoal::None,
13455                )
13456            });
13457        })
13458    }
13459
13460    pub fn select_to_beginning_of_line(
13461        &mut self,
13462        action: &SelectToBeginningOfLine,
13463        window: &mut Window,
13464        cx: &mut Context<Self>,
13465    ) {
13466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13467        self.change_selections(Default::default(), window, cx, |s| {
13468            s.move_heads_with(|map, head, _| {
13469                (
13470                    movement::indented_line_beginning(
13471                        map,
13472                        head,
13473                        action.stop_at_soft_wraps,
13474                        action.stop_at_indent,
13475                    ),
13476                    SelectionGoal::None,
13477                )
13478            });
13479        });
13480    }
13481
13482    pub fn delete_to_beginning_of_line(
13483        &mut self,
13484        action: &DeleteToBeginningOfLine,
13485        window: &mut Window,
13486        cx: &mut Context<Self>,
13487    ) {
13488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13489        self.transact(window, cx, |this, window, cx| {
13490            this.change_selections(Default::default(), window, cx, |s| {
13491                s.move_with(|_, selection| {
13492                    selection.reversed = true;
13493                });
13494            });
13495
13496            this.select_to_beginning_of_line(
13497                &SelectToBeginningOfLine {
13498                    stop_at_soft_wraps: false,
13499                    stop_at_indent: action.stop_at_indent,
13500                },
13501                window,
13502                cx,
13503            );
13504            this.backspace(&Backspace, window, cx);
13505        });
13506    }
13507
13508    pub fn move_to_end_of_line(
13509        &mut self,
13510        action: &MoveToEndOfLine,
13511        window: &mut Window,
13512        cx: &mut Context<Self>,
13513    ) {
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13515        self.change_selections(Default::default(), window, cx, |s| {
13516            s.move_cursors_with(|map, head, _| {
13517                (
13518                    movement::line_end(map, head, action.stop_at_soft_wraps),
13519                    SelectionGoal::None,
13520                )
13521            });
13522        })
13523    }
13524
13525    pub fn select_to_end_of_line(
13526        &mut self,
13527        action: &SelectToEndOfLine,
13528        window: &mut Window,
13529        cx: &mut Context<Self>,
13530    ) {
13531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13532        self.change_selections(Default::default(), window, cx, |s| {
13533            s.move_heads_with(|map, head, _| {
13534                (
13535                    movement::line_end(map, head, action.stop_at_soft_wraps),
13536                    SelectionGoal::None,
13537                )
13538            });
13539        })
13540    }
13541
13542    pub fn delete_to_end_of_line(
13543        &mut self,
13544        _: &DeleteToEndOfLine,
13545        window: &mut Window,
13546        cx: &mut Context<Self>,
13547    ) {
13548        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13549        self.transact(window, cx, |this, window, cx| {
13550            this.select_to_end_of_line(
13551                &SelectToEndOfLine {
13552                    stop_at_soft_wraps: false,
13553                },
13554                window,
13555                cx,
13556            );
13557            this.delete(&Delete, window, cx);
13558        });
13559    }
13560
13561    pub fn cut_to_end_of_line(
13562        &mut self,
13563        action: &CutToEndOfLine,
13564        window: &mut Window,
13565        cx: &mut Context<Self>,
13566    ) {
13567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13568        self.transact(window, cx, |this, window, cx| {
13569            this.select_to_end_of_line(
13570                &SelectToEndOfLine {
13571                    stop_at_soft_wraps: false,
13572                },
13573                window,
13574                cx,
13575            );
13576            if !action.stop_at_newlines {
13577                this.change_selections(Default::default(), window, cx, |s| {
13578                    s.move_with(|_, sel| {
13579                        if sel.is_empty() {
13580                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13581                        }
13582                    });
13583                });
13584            }
13585            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13586            let item = this.cut_common(false, window, cx);
13587            cx.write_to_clipboard(item);
13588        });
13589    }
13590
13591    pub fn move_to_start_of_paragraph(
13592        &mut self,
13593        _: &MoveToStartOfParagraph,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        if matches!(self.mode, EditorMode::SingleLine) {
13598            cx.propagate();
13599            return;
13600        }
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602        self.change_selections(Default::default(), window, cx, |s| {
13603            s.move_with(|map, selection| {
13604                selection.collapse_to(
13605                    movement::start_of_paragraph(map, selection.head(), 1),
13606                    SelectionGoal::None,
13607                )
13608            });
13609        })
13610    }
13611
13612    pub fn move_to_end_of_paragraph(
13613        &mut self,
13614        _: &MoveToEndOfParagraph,
13615        window: &mut Window,
13616        cx: &mut Context<Self>,
13617    ) {
13618        if matches!(self.mode, EditorMode::SingleLine) {
13619            cx.propagate();
13620            return;
13621        }
13622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13623        self.change_selections(Default::default(), window, cx, |s| {
13624            s.move_with(|map, selection| {
13625                selection.collapse_to(
13626                    movement::end_of_paragraph(map, selection.head(), 1),
13627                    SelectionGoal::None,
13628                )
13629            });
13630        })
13631    }
13632
13633    pub fn select_to_start_of_paragraph(
13634        &mut self,
13635        _: &SelectToStartOfParagraph,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        if matches!(self.mode, EditorMode::SingleLine) {
13640            cx.propagate();
13641            return;
13642        }
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_heads_with(|map, head, _| {
13646                (
13647                    movement::start_of_paragraph(map, head, 1),
13648                    SelectionGoal::None,
13649                )
13650            });
13651        })
13652    }
13653
13654    pub fn select_to_end_of_paragraph(
13655        &mut self,
13656        _: &SelectToEndOfParagraph,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        if matches!(self.mode, EditorMode::SingleLine) {
13661            cx.propagate();
13662            return;
13663        }
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13665        self.change_selections(Default::default(), window, cx, |s| {
13666            s.move_heads_with(|map, head, _| {
13667                (
13668                    movement::end_of_paragraph(map, head, 1),
13669                    SelectionGoal::None,
13670                )
13671            });
13672        })
13673    }
13674
13675    pub fn move_to_start_of_excerpt(
13676        &mut self,
13677        _: &MoveToStartOfExcerpt,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        if matches!(self.mode, EditorMode::SingleLine) {
13682            cx.propagate();
13683            return;
13684        }
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686        self.change_selections(Default::default(), window, cx, |s| {
13687            s.move_with(|map, selection| {
13688                selection.collapse_to(
13689                    movement::start_of_excerpt(
13690                        map,
13691                        selection.head(),
13692                        workspace::searchable::Direction::Prev,
13693                    ),
13694                    SelectionGoal::None,
13695                )
13696            });
13697        })
13698    }
13699
13700    pub fn move_to_start_of_next_excerpt(
13701        &mut self,
13702        _: &MoveToStartOfNextExcerpt,
13703        window: &mut Window,
13704        cx: &mut Context<Self>,
13705    ) {
13706        if matches!(self.mode, EditorMode::SingleLine) {
13707            cx.propagate();
13708            return;
13709        }
13710
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_with(|map, selection| {
13713                selection.collapse_to(
13714                    movement::start_of_excerpt(
13715                        map,
13716                        selection.head(),
13717                        workspace::searchable::Direction::Next,
13718                    ),
13719                    SelectionGoal::None,
13720                )
13721            });
13722        })
13723    }
13724
13725    pub fn move_to_end_of_excerpt(
13726        &mut self,
13727        _: &MoveToEndOfExcerpt,
13728        window: &mut Window,
13729        cx: &mut Context<Self>,
13730    ) {
13731        if matches!(self.mode, EditorMode::SingleLine) {
13732            cx.propagate();
13733            return;
13734        }
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_with(|map, selection| {
13738                selection.collapse_to(
13739                    movement::end_of_excerpt(
13740                        map,
13741                        selection.head(),
13742                        workspace::searchable::Direction::Next,
13743                    ),
13744                    SelectionGoal::None,
13745                )
13746            });
13747        })
13748    }
13749
13750    pub fn move_to_end_of_previous_excerpt(
13751        &mut self,
13752        _: &MoveToEndOfPreviousExcerpt,
13753        window: &mut Window,
13754        cx: &mut Context<Self>,
13755    ) {
13756        if matches!(self.mode, EditorMode::SingleLine) {
13757            cx.propagate();
13758            return;
13759        }
13760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13761        self.change_selections(Default::default(), window, cx, |s| {
13762            s.move_with(|map, selection| {
13763                selection.collapse_to(
13764                    movement::end_of_excerpt(
13765                        map,
13766                        selection.head(),
13767                        workspace::searchable::Direction::Prev,
13768                    ),
13769                    SelectionGoal::None,
13770                )
13771            });
13772        })
13773    }
13774
13775    pub fn select_to_start_of_excerpt(
13776        &mut self,
13777        _: &SelectToStartOfExcerpt,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        if matches!(self.mode, EditorMode::SingleLine) {
13782            cx.propagate();
13783            return;
13784        }
13785        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13786        self.change_selections(Default::default(), window, cx, |s| {
13787            s.move_heads_with(|map, head, _| {
13788                (
13789                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13790                    SelectionGoal::None,
13791                )
13792            });
13793        })
13794    }
13795
13796    pub fn select_to_start_of_next_excerpt(
13797        &mut self,
13798        _: &SelectToStartOfNextExcerpt,
13799        window: &mut Window,
13800        cx: &mut Context<Self>,
13801    ) {
13802        if matches!(self.mode, EditorMode::SingleLine) {
13803            cx.propagate();
13804            return;
13805        }
13806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13807        self.change_selections(Default::default(), window, cx, |s| {
13808            s.move_heads_with(|map, head, _| {
13809                (
13810                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13811                    SelectionGoal::None,
13812                )
13813            });
13814        })
13815    }
13816
13817    pub fn select_to_end_of_excerpt(
13818        &mut self,
13819        _: &SelectToEndOfExcerpt,
13820        window: &mut Window,
13821        cx: &mut Context<Self>,
13822    ) {
13823        if matches!(self.mode, EditorMode::SingleLine) {
13824            cx.propagate();
13825            return;
13826        }
13827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13828        self.change_selections(Default::default(), window, cx, |s| {
13829            s.move_heads_with(|map, head, _| {
13830                (
13831                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13832                    SelectionGoal::None,
13833                )
13834            });
13835        })
13836    }
13837
13838    pub fn select_to_end_of_previous_excerpt(
13839        &mut self,
13840        _: &SelectToEndOfPreviousExcerpt,
13841        window: &mut Window,
13842        cx: &mut Context<Self>,
13843    ) {
13844        if matches!(self.mode, EditorMode::SingleLine) {
13845            cx.propagate();
13846            return;
13847        }
13848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13849        self.change_selections(Default::default(), window, cx, |s| {
13850            s.move_heads_with(|map, head, _| {
13851                (
13852                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13853                    SelectionGoal::None,
13854                )
13855            });
13856        })
13857    }
13858
13859    pub fn move_to_beginning(
13860        &mut self,
13861        _: &MoveToBeginning,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) {
13865        if matches!(self.mode, EditorMode::SingleLine) {
13866            cx.propagate();
13867            return;
13868        }
13869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13870        self.change_selections(Default::default(), window, cx, |s| {
13871            s.select_ranges(vec![0..0]);
13872        });
13873    }
13874
13875    pub fn select_to_beginning(
13876        &mut self,
13877        _: &SelectToBeginning,
13878        window: &mut Window,
13879        cx: &mut Context<Self>,
13880    ) {
13881        let mut selection = self.selections.last::<Point>(cx);
13882        selection.set_head(Point::zero(), SelectionGoal::None);
13883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.select(vec![selection]);
13886        });
13887    }
13888
13889    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13890        if matches!(self.mode, EditorMode::SingleLine) {
13891            cx.propagate();
13892            return;
13893        }
13894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13895        let cursor = self.buffer.read(cx).read(cx).len();
13896        self.change_selections(Default::default(), window, cx, |s| {
13897            s.select_ranges(vec![cursor..cursor])
13898        });
13899    }
13900
13901    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13902        self.nav_history = nav_history;
13903    }
13904
13905    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13906        self.nav_history.as_ref()
13907    }
13908
13909    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13910        self.push_to_nav_history(
13911            self.selections.newest_anchor().head(),
13912            None,
13913            false,
13914            true,
13915            cx,
13916        );
13917    }
13918
13919    fn push_to_nav_history(
13920        &mut self,
13921        cursor_anchor: Anchor,
13922        new_position: Option<Point>,
13923        is_deactivate: bool,
13924        always: bool,
13925        cx: &mut Context<Self>,
13926    ) {
13927        if let Some(nav_history) = self.nav_history.as_mut() {
13928            let buffer = self.buffer.read(cx).read(cx);
13929            let cursor_position = cursor_anchor.to_point(&buffer);
13930            let scroll_state = self.scroll_manager.anchor();
13931            let scroll_top_row = scroll_state.top_row(&buffer);
13932            drop(buffer);
13933
13934            if let Some(new_position) = new_position {
13935                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13936                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13937                    return;
13938                }
13939            }
13940
13941            nav_history.push(
13942                Some(NavigationData {
13943                    cursor_anchor,
13944                    cursor_position,
13945                    scroll_anchor: scroll_state,
13946                    scroll_top_row,
13947                }),
13948                cx,
13949            );
13950            cx.emit(EditorEvent::PushedToNavHistory {
13951                anchor: cursor_anchor,
13952                is_deactivate,
13953            })
13954        }
13955    }
13956
13957    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13959        let buffer = self.buffer.read(cx).snapshot(cx);
13960        let mut selection = self.selections.first::<usize>(cx);
13961        selection.set_head(buffer.len(), SelectionGoal::None);
13962        self.change_selections(Default::default(), window, cx, |s| {
13963            s.select(vec![selection]);
13964        });
13965    }
13966
13967    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        let end = self.buffer.read(cx).read(cx).len();
13970        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13971            s.select_ranges(vec![0..end]);
13972        });
13973    }
13974
13975    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13977        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13978        let mut selections = self.selections.all::<Point>(cx);
13979        let max_point = display_map.buffer_snapshot.max_point();
13980        for selection in &mut selections {
13981            let rows = selection.spanned_rows(true, &display_map);
13982            selection.start = Point::new(rows.start.0, 0);
13983            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13984            selection.reversed = false;
13985        }
13986        self.change_selections(Default::default(), window, cx, |s| {
13987            s.select(selections);
13988        });
13989    }
13990
13991    pub fn split_selection_into_lines(
13992        &mut self,
13993        action: &SplitSelectionIntoLines,
13994        window: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) {
13997        let selections = self
13998            .selections
13999            .all::<Point>(cx)
14000            .into_iter()
14001            .map(|selection| selection.start..selection.end)
14002            .collect::<Vec<_>>();
14003        self.unfold_ranges(&selections, true, true, cx);
14004
14005        let mut new_selection_ranges = Vec::new();
14006        {
14007            let buffer = self.buffer.read(cx).read(cx);
14008            for selection in selections {
14009                for row in selection.start.row..selection.end.row {
14010                    let line_start = Point::new(row, 0);
14011                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14012
14013                    if action.keep_selections {
14014                        // Keep the selection range for each line
14015                        let selection_start = if row == selection.start.row {
14016                            selection.start
14017                        } else {
14018                            line_start
14019                        };
14020                        new_selection_ranges.push(selection_start..line_end);
14021                    } else {
14022                        // Collapse to cursor at end of line
14023                        new_selection_ranges.push(line_end..line_end);
14024                    }
14025                }
14026
14027                let is_multiline_selection = selection.start.row != selection.end.row;
14028                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14029                // so this action feels more ergonomic when paired with other selection operations
14030                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14031                if !should_skip_last {
14032                    if action.keep_selections {
14033                        if is_multiline_selection {
14034                            let line_start = Point::new(selection.end.row, 0);
14035                            new_selection_ranges.push(line_start..selection.end);
14036                        } else {
14037                            new_selection_ranges.push(selection.start..selection.end);
14038                        }
14039                    } else {
14040                        new_selection_ranges.push(selection.end..selection.end);
14041                    }
14042                }
14043            }
14044        }
14045        self.change_selections(Default::default(), window, cx, |s| {
14046            s.select_ranges(new_selection_ranges);
14047        });
14048    }
14049
14050    pub fn add_selection_above(
14051        &mut self,
14052        _: &AddSelectionAbove,
14053        window: &mut Window,
14054        cx: &mut Context<Self>,
14055    ) {
14056        self.add_selection(true, window, cx);
14057    }
14058
14059    pub fn add_selection_below(
14060        &mut self,
14061        _: &AddSelectionBelow,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        self.add_selection(false, window, cx);
14066    }
14067
14068    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070
14071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14072        let all_selections = self.selections.all::<Point>(cx);
14073        let text_layout_details = self.text_layout_details(window);
14074
14075        let (mut columnar_selections, new_selections_to_columnarize) = {
14076            if let Some(state) = self.add_selections_state.as_ref() {
14077                let columnar_selection_ids: HashSet<_> = state
14078                    .groups
14079                    .iter()
14080                    .flat_map(|group| group.stack.iter())
14081                    .copied()
14082                    .collect();
14083
14084                all_selections
14085                    .into_iter()
14086                    .partition(|s| columnar_selection_ids.contains(&s.id))
14087            } else {
14088                (Vec::new(), all_selections)
14089            }
14090        };
14091
14092        let mut state = self
14093            .add_selections_state
14094            .take()
14095            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14096
14097        for selection in new_selections_to_columnarize {
14098            let range = selection.display_range(&display_map).sorted();
14099            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14100            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14101            let positions = start_x.min(end_x)..start_x.max(end_x);
14102            let mut stack = Vec::new();
14103            for row in range.start.row().0..=range.end.row().0 {
14104                if let Some(selection) = self.selections.build_columnar_selection(
14105                    &display_map,
14106                    DisplayRow(row),
14107                    &positions,
14108                    selection.reversed,
14109                    &text_layout_details,
14110                ) {
14111                    stack.push(selection.id);
14112                    columnar_selections.push(selection);
14113                }
14114            }
14115            if !stack.is_empty() {
14116                if above {
14117                    stack.reverse();
14118                }
14119                state.groups.push(AddSelectionsGroup { above, stack });
14120            }
14121        }
14122
14123        let mut final_selections = Vec::new();
14124        let end_row = if above {
14125            DisplayRow(0)
14126        } else {
14127            display_map.max_point().row()
14128        };
14129
14130        let mut last_added_item_per_group = HashMap::default();
14131        for group in state.groups.iter_mut() {
14132            if let Some(last_id) = group.stack.last() {
14133                last_added_item_per_group.insert(*last_id, group);
14134            }
14135        }
14136
14137        for selection in columnar_selections {
14138            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14139                if above == group.above {
14140                    let range = selection.display_range(&display_map).sorted();
14141                    debug_assert_eq!(range.start.row(), range.end.row());
14142                    let mut row = range.start.row();
14143                    let positions =
14144                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14145                            px(start)..px(end)
14146                        } else {
14147                            let start_x =
14148                                display_map.x_for_display_point(range.start, &text_layout_details);
14149                            let end_x =
14150                                display_map.x_for_display_point(range.end, &text_layout_details);
14151                            start_x.min(end_x)..start_x.max(end_x)
14152                        };
14153
14154                    let mut maybe_new_selection = None;
14155                    while row != end_row {
14156                        if above {
14157                            row.0 -= 1;
14158                        } else {
14159                            row.0 += 1;
14160                        }
14161                        if let Some(new_selection) = self.selections.build_columnar_selection(
14162                            &display_map,
14163                            row,
14164                            &positions,
14165                            selection.reversed,
14166                            &text_layout_details,
14167                        ) {
14168                            maybe_new_selection = Some(new_selection);
14169                            break;
14170                        }
14171                    }
14172
14173                    if let Some(new_selection) = maybe_new_selection {
14174                        group.stack.push(new_selection.id);
14175                        if above {
14176                            final_selections.push(new_selection);
14177                            final_selections.push(selection);
14178                        } else {
14179                            final_selections.push(selection);
14180                            final_selections.push(new_selection);
14181                        }
14182                    } else {
14183                        final_selections.push(selection);
14184                    }
14185                } else {
14186                    group.stack.pop();
14187                }
14188            } else {
14189                final_selections.push(selection);
14190            }
14191        }
14192
14193        self.change_selections(Default::default(), window, cx, |s| {
14194            s.select(final_selections);
14195        });
14196
14197        let final_selection_ids: HashSet<_> = self
14198            .selections
14199            .all::<Point>(cx)
14200            .iter()
14201            .map(|s| s.id)
14202            .collect();
14203        state.groups.retain_mut(|group| {
14204            // selections might get merged above so we remove invalid items from stacks
14205            group.stack.retain(|id| final_selection_ids.contains(id));
14206
14207            // single selection in stack can be treated as initial state
14208            group.stack.len() > 1
14209        });
14210
14211        if !state.groups.is_empty() {
14212            self.add_selections_state = Some(state);
14213        }
14214    }
14215
14216    fn select_match_ranges(
14217        &mut self,
14218        range: Range<usize>,
14219        reversed: bool,
14220        replace_newest: bool,
14221        auto_scroll: Option<Autoscroll>,
14222        window: &mut Window,
14223        cx: &mut Context<Editor>,
14224    ) {
14225        self.unfold_ranges(
14226            std::slice::from_ref(&range),
14227            false,
14228            auto_scroll.is_some(),
14229            cx,
14230        );
14231        let effects = if let Some(scroll) = auto_scroll {
14232            SelectionEffects::scroll(scroll)
14233        } else {
14234            SelectionEffects::no_scroll()
14235        };
14236        self.change_selections(effects, window, cx, |s| {
14237            if replace_newest {
14238                s.delete(s.newest_anchor().id);
14239            }
14240            if reversed {
14241                s.insert_range(range.end..range.start);
14242            } else {
14243                s.insert_range(range);
14244            }
14245        });
14246    }
14247
14248    pub fn select_next_match_internal(
14249        &mut self,
14250        display_map: &DisplaySnapshot,
14251        replace_newest: bool,
14252        autoscroll: Option<Autoscroll>,
14253        window: &mut Window,
14254        cx: &mut Context<Self>,
14255    ) -> Result<()> {
14256        let buffer = &display_map.buffer_snapshot;
14257        let mut selections = self.selections.all::<usize>(cx);
14258        if let Some(mut select_next_state) = self.select_next_state.take() {
14259            let query = &select_next_state.query;
14260            if !select_next_state.done {
14261                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14262                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14263                let mut next_selected_range = None;
14264
14265                let bytes_after_last_selection =
14266                    buffer.bytes_in_range(last_selection.end..buffer.len());
14267                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14268                let query_matches = query
14269                    .stream_find_iter(bytes_after_last_selection)
14270                    .map(|result| (last_selection.end, result))
14271                    .chain(
14272                        query
14273                            .stream_find_iter(bytes_before_first_selection)
14274                            .map(|result| (0, result)),
14275                    );
14276
14277                for (start_offset, query_match) in query_matches {
14278                    let query_match = query_match.unwrap(); // can only fail due to I/O
14279                    let offset_range =
14280                        start_offset + query_match.start()..start_offset + query_match.end();
14281
14282                    if !select_next_state.wordwise
14283                        || (!buffer.is_inside_word(offset_range.start, None)
14284                            && !buffer.is_inside_word(offset_range.end, None))
14285                    {
14286                        // TODO: This is n^2, because we might check all the selections
14287                        if !selections
14288                            .iter()
14289                            .any(|selection| selection.range().overlaps(&offset_range))
14290                        {
14291                            next_selected_range = Some(offset_range);
14292                            break;
14293                        }
14294                    }
14295                }
14296
14297                if let Some(next_selected_range) = next_selected_range {
14298                    self.select_match_ranges(
14299                        next_selected_range,
14300                        last_selection.reversed,
14301                        replace_newest,
14302                        autoscroll,
14303                        window,
14304                        cx,
14305                    );
14306                } else {
14307                    select_next_state.done = true;
14308                }
14309            }
14310
14311            self.select_next_state = Some(select_next_state);
14312        } else {
14313            let mut only_carets = true;
14314            let mut same_text_selected = true;
14315            let mut selected_text = None;
14316
14317            let mut selections_iter = selections.iter().peekable();
14318            while let Some(selection) = selections_iter.next() {
14319                if selection.start != selection.end {
14320                    only_carets = false;
14321                }
14322
14323                if same_text_selected {
14324                    if selected_text.is_none() {
14325                        selected_text =
14326                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14327                    }
14328
14329                    if let Some(next_selection) = selections_iter.peek() {
14330                        if next_selection.range().len() == selection.range().len() {
14331                            let next_selected_text = buffer
14332                                .text_for_range(next_selection.range())
14333                                .collect::<String>();
14334                            if Some(next_selected_text) != selected_text {
14335                                same_text_selected = false;
14336                                selected_text = None;
14337                            }
14338                        } else {
14339                            same_text_selected = false;
14340                            selected_text = None;
14341                        }
14342                    }
14343                }
14344            }
14345
14346            if only_carets {
14347                for selection in &mut selections {
14348                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14349                    selection.start = word_range.start;
14350                    selection.end = word_range.end;
14351                    selection.goal = SelectionGoal::None;
14352                    selection.reversed = false;
14353                    self.select_match_ranges(
14354                        selection.start..selection.end,
14355                        selection.reversed,
14356                        replace_newest,
14357                        autoscroll,
14358                        window,
14359                        cx,
14360                    );
14361                }
14362
14363                if selections.len() == 1 {
14364                    let selection = selections
14365                        .last()
14366                        .expect("ensured that there's only one selection");
14367                    let query = buffer
14368                        .text_for_range(selection.start..selection.end)
14369                        .collect::<String>();
14370                    let is_empty = query.is_empty();
14371                    let select_state = SelectNextState {
14372                        query: AhoCorasick::new(&[query])?,
14373                        wordwise: true,
14374                        done: is_empty,
14375                    };
14376                    self.select_next_state = Some(select_state);
14377                } else {
14378                    self.select_next_state = None;
14379                }
14380            } else if let Some(selected_text) = selected_text {
14381                self.select_next_state = Some(SelectNextState {
14382                    query: AhoCorasick::new(&[selected_text])?,
14383                    wordwise: false,
14384                    done: false,
14385                });
14386                self.select_next_match_internal(
14387                    display_map,
14388                    replace_newest,
14389                    autoscroll,
14390                    window,
14391                    cx,
14392                )?;
14393            }
14394        }
14395        Ok(())
14396    }
14397
14398    pub fn select_all_matches(
14399        &mut self,
14400        _action: &SelectAllMatches,
14401        window: &mut Window,
14402        cx: &mut Context<Self>,
14403    ) -> Result<()> {
14404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14405
14406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14407
14408        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14409        let Some(select_next_state) = self.select_next_state.as_mut() else {
14410            return Ok(());
14411        };
14412        if select_next_state.done {
14413            return Ok(());
14414        }
14415
14416        let mut new_selections = Vec::new();
14417
14418        let reversed = self.selections.oldest::<usize>(cx).reversed;
14419        let buffer = &display_map.buffer_snapshot;
14420        let query_matches = select_next_state
14421            .query
14422            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14423
14424        for query_match in query_matches.into_iter() {
14425            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14426            let offset_range = if reversed {
14427                query_match.end()..query_match.start()
14428            } else {
14429                query_match.start()..query_match.end()
14430            };
14431
14432            if !select_next_state.wordwise
14433                || (!buffer.is_inside_word(offset_range.start, None)
14434                    && !buffer.is_inside_word(offset_range.end, None))
14435            {
14436                new_selections.push(offset_range.start..offset_range.end);
14437            }
14438        }
14439
14440        select_next_state.done = true;
14441
14442        if new_selections.is_empty() {
14443            log::error!("bug: new_selections is empty in select_all_matches");
14444            return Ok(());
14445        }
14446
14447        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14448        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14449            selections.select_ranges(new_selections)
14450        });
14451
14452        Ok(())
14453    }
14454
14455    pub fn select_next(
14456        &mut self,
14457        action: &SelectNext,
14458        window: &mut Window,
14459        cx: &mut Context<Self>,
14460    ) -> Result<()> {
14461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14463        self.select_next_match_internal(
14464            &display_map,
14465            action.replace_newest,
14466            Some(Autoscroll::newest()),
14467            window,
14468            cx,
14469        )?;
14470        Ok(())
14471    }
14472
14473    pub fn select_previous(
14474        &mut self,
14475        action: &SelectPrevious,
14476        window: &mut Window,
14477        cx: &mut Context<Self>,
14478    ) -> Result<()> {
14479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14481        let buffer = &display_map.buffer_snapshot;
14482        let mut selections = self.selections.all::<usize>(cx);
14483        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14484            let query = &select_prev_state.query;
14485            if !select_prev_state.done {
14486                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14487                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14488                let mut next_selected_range = None;
14489                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14490                let bytes_before_last_selection =
14491                    buffer.reversed_bytes_in_range(0..last_selection.start);
14492                let bytes_after_first_selection =
14493                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14494                let query_matches = query
14495                    .stream_find_iter(bytes_before_last_selection)
14496                    .map(|result| (last_selection.start, result))
14497                    .chain(
14498                        query
14499                            .stream_find_iter(bytes_after_first_selection)
14500                            .map(|result| (buffer.len(), result)),
14501                    );
14502                for (end_offset, query_match) in query_matches {
14503                    let query_match = query_match.unwrap(); // can only fail due to I/O
14504                    let offset_range =
14505                        end_offset - query_match.end()..end_offset - query_match.start();
14506
14507                    if !select_prev_state.wordwise
14508                        || (!buffer.is_inside_word(offset_range.start, None)
14509                            && !buffer.is_inside_word(offset_range.end, None))
14510                    {
14511                        next_selected_range = Some(offset_range);
14512                        break;
14513                    }
14514                }
14515
14516                if let Some(next_selected_range) = next_selected_range {
14517                    self.select_match_ranges(
14518                        next_selected_range,
14519                        last_selection.reversed,
14520                        action.replace_newest,
14521                        Some(Autoscroll::newest()),
14522                        window,
14523                        cx,
14524                    );
14525                } else {
14526                    select_prev_state.done = true;
14527                }
14528            }
14529
14530            self.select_prev_state = Some(select_prev_state);
14531        } else {
14532            let mut only_carets = true;
14533            let mut same_text_selected = true;
14534            let mut selected_text = None;
14535
14536            let mut selections_iter = selections.iter().peekable();
14537            while let Some(selection) = selections_iter.next() {
14538                if selection.start != selection.end {
14539                    only_carets = false;
14540                }
14541
14542                if same_text_selected {
14543                    if selected_text.is_none() {
14544                        selected_text =
14545                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14546                    }
14547
14548                    if let Some(next_selection) = selections_iter.peek() {
14549                        if next_selection.range().len() == selection.range().len() {
14550                            let next_selected_text = buffer
14551                                .text_for_range(next_selection.range())
14552                                .collect::<String>();
14553                            if Some(next_selected_text) != selected_text {
14554                                same_text_selected = false;
14555                                selected_text = None;
14556                            }
14557                        } else {
14558                            same_text_selected = false;
14559                            selected_text = None;
14560                        }
14561                    }
14562                }
14563            }
14564
14565            if only_carets {
14566                for selection in &mut selections {
14567                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14568                    selection.start = word_range.start;
14569                    selection.end = word_range.end;
14570                    selection.goal = SelectionGoal::None;
14571                    selection.reversed = false;
14572                    self.select_match_ranges(
14573                        selection.start..selection.end,
14574                        selection.reversed,
14575                        action.replace_newest,
14576                        Some(Autoscroll::newest()),
14577                        window,
14578                        cx,
14579                    );
14580                }
14581                if selections.len() == 1 {
14582                    let selection = selections
14583                        .last()
14584                        .expect("ensured that there's only one selection");
14585                    let query = buffer
14586                        .text_for_range(selection.start..selection.end)
14587                        .collect::<String>();
14588                    let is_empty = query.is_empty();
14589                    let select_state = SelectNextState {
14590                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14591                        wordwise: true,
14592                        done: is_empty,
14593                    };
14594                    self.select_prev_state = Some(select_state);
14595                } else {
14596                    self.select_prev_state = None;
14597                }
14598            } else if let Some(selected_text) = selected_text {
14599                self.select_prev_state = Some(SelectNextState {
14600                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14601                    wordwise: false,
14602                    done: false,
14603                });
14604                self.select_previous(action, window, cx)?;
14605            }
14606        }
14607        Ok(())
14608    }
14609
14610    pub fn find_next_match(
14611        &mut self,
14612        _: &FindNextMatch,
14613        window: &mut Window,
14614        cx: &mut Context<Self>,
14615    ) -> Result<()> {
14616        let selections = self.selections.disjoint_anchors_arc();
14617        match selections.first() {
14618            Some(first) if selections.len() >= 2 => {
14619                self.change_selections(Default::default(), window, cx, |s| {
14620                    s.select_ranges([first.range()]);
14621                });
14622            }
14623            _ => self.select_next(
14624                &SelectNext {
14625                    replace_newest: true,
14626                },
14627                window,
14628                cx,
14629            )?,
14630        }
14631        Ok(())
14632    }
14633
14634    pub fn find_previous_match(
14635        &mut self,
14636        _: &FindPreviousMatch,
14637        window: &mut Window,
14638        cx: &mut Context<Self>,
14639    ) -> Result<()> {
14640        let selections = self.selections.disjoint_anchors_arc();
14641        match selections.last() {
14642            Some(last) if selections.len() >= 2 => {
14643                self.change_selections(Default::default(), window, cx, |s| {
14644                    s.select_ranges([last.range()]);
14645                });
14646            }
14647            _ => self.select_previous(
14648                &SelectPrevious {
14649                    replace_newest: true,
14650                },
14651                window,
14652                cx,
14653            )?,
14654        }
14655        Ok(())
14656    }
14657
14658    pub fn toggle_comments(
14659        &mut self,
14660        action: &ToggleComments,
14661        window: &mut Window,
14662        cx: &mut Context<Self>,
14663    ) {
14664        if self.read_only(cx) {
14665            return;
14666        }
14667        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14668        let text_layout_details = &self.text_layout_details(window);
14669        self.transact(window, cx, |this, window, cx| {
14670            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14671            let mut edits = Vec::new();
14672            let mut selection_edit_ranges = Vec::new();
14673            let mut last_toggled_row = None;
14674            let snapshot = this.buffer.read(cx).read(cx);
14675            let empty_str: Arc<str> = Arc::default();
14676            let mut suffixes_inserted = Vec::new();
14677            let ignore_indent = action.ignore_indent;
14678
14679            fn comment_prefix_range(
14680                snapshot: &MultiBufferSnapshot,
14681                row: MultiBufferRow,
14682                comment_prefix: &str,
14683                comment_prefix_whitespace: &str,
14684                ignore_indent: bool,
14685            ) -> Range<Point> {
14686                let indent_size = if ignore_indent {
14687                    0
14688                } else {
14689                    snapshot.indent_size_for_line(row).len
14690                };
14691
14692                let start = Point::new(row.0, indent_size);
14693
14694                let mut line_bytes = snapshot
14695                    .bytes_in_range(start..snapshot.max_point())
14696                    .flatten()
14697                    .copied();
14698
14699                // If this line currently begins with the line comment prefix, then record
14700                // the range containing the prefix.
14701                if line_bytes
14702                    .by_ref()
14703                    .take(comment_prefix.len())
14704                    .eq(comment_prefix.bytes())
14705                {
14706                    // Include any whitespace that matches the comment prefix.
14707                    let matching_whitespace_len = line_bytes
14708                        .zip(comment_prefix_whitespace.bytes())
14709                        .take_while(|(a, b)| a == b)
14710                        .count() as u32;
14711                    let end = Point::new(
14712                        start.row,
14713                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14714                    );
14715                    start..end
14716                } else {
14717                    start..start
14718                }
14719            }
14720
14721            fn comment_suffix_range(
14722                snapshot: &MultiBufferSnapshot,
14723                row: MultiBufferRow,
14724                comment_suffix: &str,
14725                comment_suffix_has_leading_space: bool,
14726            ) -> Range<Point> {
14727                let end = Point::new(row.0, snapshot.line_len(row));
14728                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14729
14730                let mut line_end_bytes = snapshot
14731                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14732                    .flatten()
14733                    .copied();
14734
14735                let leading_space_len = if suffix_start_column > 0
14736                    && line_end_bytes.next() == Some(b' ')
14737                    && comment_suffix_has_leading_space
14738                {
14739                    1
14740                } else {
14741                    0
14742                };
14743
14744                // If this line currently begins with the line comment prefix, then record
14745                // the range containing the prefix.
14746                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14747                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14748                    start..end
14749                } else {
14750                    end..end
14751                }
14752            }
14753
14754            // TODO: Handle selections that cross excerpts
14755            for selection in &mut selections {
14756                let start_column = snapshot
14757                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14758                    .len;
14759                let language = if let Some(language) =
14760                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14761                {
14762                    language
14763                } else {
14764                    continue;
14765                };
14766
14767                selection_edit_ranges.clear();
14768
14769                // If multiple selections contain a given row, avoid processing that
14770                // row more than once.
14771                let mut start_row = MultiBufferRow(selection.start.row);
14772                if last_toggled_row == Some(start_row) {
14773                    start_row = start_row.next_row();
14774                }
14775                let end_row =
14776                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14777                        MultiBufferRow(selection.end.row - 1)
14778                    } else {
14779                        MultiBufferRow(selection.end.row)
14780                    };
14781                last_toggled_row = Some(end_row);
14782
14783                if start_row > end_row {
14784                    continue;
14785                }
14786
14787                // If the language has line comments, toggle those.
14788                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14789
14790                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14791                if ignore_indent {
14792                    full_comment_prefixes = full_comment_prefixes
14793                        .into_iter()
14794                        .map(|s| Arc::from(s.trim_end()))
14795                        .collect();
14796                }
14797
14798                if !full_comment_prefixes.is_empty() {
14799                    let first_prefix = full_comment_prefixes
14800                        .first()
14801                        .expect("prefixes is non-empty");
14802                    let prefix_trimmed_lengths = full_comment_prefixes
14803                        .iter()
14804                        .map(|p| p.trim_end_matches(' ').len())
14805                        .collect::<SmallVec<[usize; 4]>>();
14806
14807                    let mut all_selection_lines_are_comments = true;
14808
14809                    for row in start_row.0..=end_row.0 {
14810                        let row = MultiBufferRow(row);
14811                        if start_row < end_row && snapshot.is_line_blank(row) {
14812                            continue;
14813                        }
14814
14815                        let prefix_range = full_comment_prefixes
14816                            .iter()
14817                            .zip(prefix_trimmed_lengths.iter().copied())
14818                            .map(|(prefix, trimmed_prefix_len)| {
14819                                comment_prefix_range(
14820                                    snapshot.deref(),
14821                                    row,
14822                                    &prefix[..trimmed_prefix_len],
14823                                    &prefix[trimmed_prefix_len..],
14824                                    ignore_indent,
14825                                )
14826                            })
14827                            .max_by_key(|range| range.end.column - range.start.column)
14828                            .expect("prefixes is non-empty");
14829
14830                        if prefix_range.is_empty() {
14831                            all_selection_lines_are_comments = false;
14832                        }
14833
14834                        selection_edit_ranges.push(prefix_range);
14835                    }
14836
14837                    if all_selection_lines_are_comments {
14838                        edits.extend(
14839                            selection_edit_ranges
14840                                .iter()
14841                                .cloned()
14842                                .map(|range| (range, empty_str.clone())),
14843                        );
14844                    } else {
14845                        let min_column = selection_edit_ranges
14846                            .iter()
14847                            .map(|range| range.start.column)
14848                            .min()
14849                            .unwrap_or(0);
14850                        edits.extend(selection_edit_ranges.iter().map(|range| {
14851                            let position = Point::new(range.start.row, min_column);
14852                            (position..position, first_prefix.clone())
14853                        }));
14854                    }
14855                } else if let Some(BlockCommentConfig {
14856                    start: full_comment_prefix,
14857                    end: comment_suffix,
14858                    ..
14859                }) = language.block_comment()
14860                {
14861                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14862                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14863                    let prefix_range = comment_prefix_range(
14864                        snapshot.deref(),
14865                        start_row,
14866                        comment_prefix,
14867                        comment_prefix_whitespace,
14868                        ignore_indent,
14869                    );
14870                    let suffix_range = comment_suffix_range(
14871                        snapshot.deref(),
14872                        end_row,
14873                        comment_suffix.trim_start_matches(' '),
14874                        comment_suffix.starts_with(' '),
14875                    );
14876
14877                    if prefix_range.is_empty() || suffix_range.is_empty() {
14878                        edits.push((
14879                            prefix_range.start..prefix_range.start,
14880                            full_comment_prefix.clone(),
14881                        ));
14882                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14883                        suffixes_inserted.push((end_row, comment_suffix.len()));
14884                    } else {
14885                        edits.push((prefix_range, empty_str.clone()));
14886                        edits.push((suffix_range, empty_str.clone()));
14887                    }
14888                } else {
14889                    continue;
14890                }
14891            }
14892
14893            drop(snapshot);
14894            this.buffer.update(cx, |buffer, cx| {
14895                buffer.edit(edits, None, cx);
14896            });
14897
14898            // Adjust selections so that they end before any comment suffixes that
14899            // were inserted.
14900            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14901            let mut selections = this.selections.all::<Point>(cx);
14902            let snapshot = this.buffer.read(cx).read(cx);
14903            for selection in &mut selections {
14904                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14905                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14906                        Ordering::Less => {
14907                            suffixes_inserted.next();
14908                            continue;
14909                        }
14910                        Ordering::Greater => break,
14911                        Ordering::Equal => {
14912                            if selection.end.column == snapshot.line_len(row) {
14913                                if selection.is_empty() {
14914                                    selection.start.column -= suffix_len as u32;
14915                                }
14916                                selection.end.column -= suffix_len as u32;
14917                            }
14918                            break;
14919                        }
14920                    }
14921                }
14922            }
14923
14924            drop(snapshot);
14925            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14926
14927            let selections = this.selections.all::<Point>(cx);
14928            let selections_on_single_row = selections.windows(2).all(|selections| {
14929                selections[0].start.row == selections[1].start.row
14930                    && selections[0].end.row == selections[1].end.row
14931                    && selections[0].start.row == selections[0].end.row
14932            });
14933            let selections_selecting = selections
14934                .iter()
14935                .any(|selection| selection.start != selection.end);
14936            let advance_downwards = action.advance_downwards
14937                && selections_on_single_row
14938                && !selections_selecting
14939                && !matches!(this.mode, EditorMode::SingleLine);
14940
14941            if advance_downwards {
14942                let snapshot = this.buffer.read(cx).snapshot(cx);
14943
14944                this.change_selections(Default::default(), window, cx, |s| {
14945                    s.move_cursors_with(|display_snapshot, display_point, _| {
14946                        let mut point = display_point.to_point(display_snapshot);
14947                        point.row += 1;
14948                        point = snapshot.clip_point(point, Bias::Left);
14949                        let display_point = point.to_display_point(display_snapshot);
14950                        let goal = SelectionGoal::HorizontalPosition(
14951                            display_snapshot
14952                                .x_for_display_point(display_point, text_layout_details)
14953                                .into(),
14954                        );
14955                        (display_point, goal)
14956                    })
14957                });
14958            }
14959        });
14960    }
14961
14962    pub fn select_enclosing_symbol(
14963        &mut self,
14964        _: &SelectEnclosingSymbol,
14965        window: &mut Window,
14966        cx: &mut Context<Self>,
14967    ) {
14968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14969
14970        let buffer = self.buffer.read(cx).snapshot(cx);
14971        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14972
14973        fn update_selection(
14974            selection: &Selection<usize>,
14975            buffer_snap: &MultiBufferSnapshot,
14976        ) -> Option<Selection<usize>> {
14977            let cursor = selection.head();
14978            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14979            for symbol in symbols.iter().rev() {
14980                let start = symbol.range.start.to_offset(buffer_snap);
14981                let end = symbol.range.end.to_offset(buffer_snap);
14982                let new_range = start..end;
14983                if start < selection.start || end > selection.end {
14984                    return Some(Selection {
14985                        id: selection.id,
14986                        start: new_range.start,
14987                        end: new_range.end,
14988                        goal: SelectionGoal::None,
14989                        reversed: selection.reversed,
14990                    });
14991                }
14992            }
14993            None
14994        }
14995
14996        let mut selected_larger_symbol = false;
14997        let new_selections = old_selections
14998            .iter()
14999            .map(|selection| match update_selection(selection, &buffer) {
15000                Some(new_selection) => {
15001                    if new_selection.range() != selection.range() {
15002                        selected_larger_symbol = true;
15003                    }
15004                    new_selection
15005                }
15006                None => selection.clone(),
15007            })
15008            .collect::<Vec<_>>();
15009
15010        if selected_larger_symbol {
15011            self.change_selections(Default::default(), window, cx, |s| {
15012                s.select(new_selections);
15013            });
15014        }
15015    }
15016
15017    pub fn select_larger_syntax_node(
15018        &mut self,
15019        _: &SelectLargerSyntaxNode,
15020        window: &mut Window,
15021        cx: &mut Context<Self>,
15022    ) {
15023        let Some(visible_row_count) = self.visible_row_count() else {
15024            return;
15025        };
15026        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15027        if old_selections.is_empty() {
15028            return;
15029        }
15030
15031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15032
15033        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15034        let buffer = self.buffer.read(cx).snapshot(cx);
15035
15036        let mut selected_larger_node = false;
15037        let mut new_selections = old_selections
15038            .iter()
15039            .map(|selection| {
15040                let old_range = selection.start..selection.end;
15041
15042                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15043                    // manually select word at selection
15044                    if ["string_content", "inline"].contains(&node.kind()) {
15045                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15046                        // ignore if word is already selected
15047                        if !word_range.is_empty() && old_range != word_range {
15048                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15049                            // only select word if start and end point belongs to same word
15050                            if word_range == last_word_range {
15051                                selected_larger_node = true;
15052                                return Selection {
15053                                    id: selection.id,
15054                                    start: word_range.start,
15055                                    end: word_range.end,
15056                                    goal: SelectionGoal::None,
15057                                    reversed: selection.reversed,
15058                                };
15059                            }
15060                        }
15061                    }
15062                }
15063
15064                let mut new_range = old_range.clone();
15065                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15066                {
15067                    new_range = match containing_range {
15068                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15069                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15070                    };
15071                    if !node.is_named() {
15072                        continue;
15073                    }
15074                    if !display_map.intersects_fold(new_range.start)
15075                        && !display_map.intersects_fold(new_range.end)
15076                    {
15077                        break;
15078                    }
15079                }
15080
15081                selected_larger_node |= new_range != old_range;
15082                Selection {
15083                    id: selection.id,
15084                    start: new_range.start,
15085                    end: new_range.end,
15086                    goal: SelectionGoal::None,
15087                    reversed: selection.reversed,
15088                }
15089            })
15090            .collect::<Vec<_>>();
15091
15092        if !selected_larger_node {
15093            return; // don't put this call in the history
15094        }
15095
15096        // scroll based on transformation done to the last selection created by the user
15097        let (last_old, last_new) = old_selections
15098            .last()
15099            .zip(new_selections.last().cloned())
15100            .expect("old_selections isn't empty");
15101
15102        // revert selection
15103        let is_selection_reversed = {
15104            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15105            new_selections.last_mut().expect("checked above").reversed =
15106                should_newest_selection_be_reversed;
15107            should_newest_selection_be_reversed
15108        };
15109
15110        if selected_larger_node {
15111            self.select_syntax_node_history.disable_clearing = true;
15112            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15113                s.select(new_selections.clone());
15114            });
15115            self.select_syntax_node_history.disable_clearing = false;
15116        }
15117
15118        let start_row = last_new.start.to_display_point(&display_map).row().0;
15119        let end_row = last_new.end.to_display_point(&display_map).row().0;
15120        let selection_height = end_row - start_row + 1;
15121        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15122
15123        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15124        let scroll_behavior = if fits_on_the_screen {
15125            self.request_autoscroll(Autoscroll::fit(), cx);
15126            SelectSyntaxNodeScrollBehavior::FitSelection
15127        } else if is_selection_reversed {
15128            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15129            SelectSyntaxNodeScrollBehavior::CursorTop
15130        } else {
15131            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15132            SelectSyntaxNodeScrollBehavior::CursorBottom
15133        };
15134
15135        self.select_syntax_node_history.push((
15136            old_selections,
15137            scroll_behavior,
15138            is_selection_reversed,
15139        ));
15140    }
15141
15142    pub fn select_smaller_syntax_node(
15143        &mut self,
15144        _: &SelectSmallerSyntaxNode,
15145        window: &mut Window,
15146        cx: &mut Context<Self>,
15147    ) {
15148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15149
15150        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15151            self.select_syntax_node_history.pop()
15152        {
15153            if let Some(selection) = selections.last_mut() {
15154                selection.reversed = is_selection_reversed;
15155            }
15156
15157            self.select_syntax_node_history.disable_clearing = true;
15158            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15159                s.select(selections.to_vec());
15160            });
15161            self.select_syntax_node_history.disable_clearing = false;
15162
15163            match scroll_behavior {
15164                SelectSyntaxNodeScrollBehavior::CursorTop => {
15165                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15166                }
15167                SelectSyntaxNodeScrollBehavior::FitSelection => {
15168                    self.request_autoscroll(Autoscroll::fit(), cx);
15169                }
15170                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15171                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15172                }
15173            }
15174        }
15175    }
15176
15177    pub fn unwrap_syntax_node(
15178        &mut self,
15179        _: &UnwrapSyntaxNode,
15180        window: &mut Window,
15181        cx: &mut Context<Self>,
15182    ) {
15183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15184
15185        let buffer = self.buffer.read(cx).snapshot(cx);
15186        let selections = self
15187            .selections
15188            .all::<usize>(cx)
15189            .into_iter()
15190            // subtracting the offset requires sorting
15191            .sorted_by_key(|i| i.start);
15192
15193        let full_edits = selections
15194            .into_iter()
15195            .filter_map(|selection| {
15196                let child = if selection.is_empty()
15197                    && let Some((_, ancestor_range)) =
15198                        buffer.syntax_ancestor(selection.start..selection.end)
15199                {
15200                    match ancestor_range {
15201                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15202                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15203                    }
15204                } else {
15205                    selection.range()
15206                };
15207
15208                let mut parent = child.clone();
15209                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15210                    parent = match ancestor_range {
15211                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15212                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15213                    };
15214                    if parent.start < child.start || parent.end > child.end {
15215                        break;
15216                    }
15217                }
15218
15219                if parent == child {
15220                    return None;
15221                }
15222                let text = buffer.text_for_range(child).collect::<String>();
15223                Some((selection.id, parent, text))
15224            })
15225            .collect::<Vec<_>>();
15226        if full_edits.is_empty() {
15227            return;
15228        }
15229
15230        self.transact(window, cx, |this, window, cx| {
15231            this.buffer.update(cx, |buffer, cx| {
15232                buffer.edit(
15233                    full_edits
15234                        .iter()
15235                        .map(|(_, p, t)| (p.clone(), t.clone()))
15236                        .collect::<Vec<_>>(),
15237                    None,
15238                    cx,
15239                );
15240            });
15241            this.change_selections(Default::default(), window, cx, |s| {
15242                let mut offset = 0;
15243                let mut selections = vec![];
15244                for (id, parent, text) in full_edits {
15245                    let start = parent.start - offset;
15246                    offset += parent.len() - text.len();
15247                    selections.push(Selection {
15248                        id,
15249                        start,
15250                        end: start + text.len(),
15251                        reversed: false,
15252                        goal: Default::default(),
15253                    });
15254                }
15255                s.select(selections);
15256            });
15257        });
15258    }
15259
15260    pub fn select_next_syntax_node(
15261        &mut self,
15262        _: &SelectNextSyntaxNode,
15263        window: &mut Window,
15264        cx: &mut Context<Self>,
15265    ) {
15266        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15267        if old_selections.is_empty() {
15268            return;
15269        }
15270
15271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15272
15273        let buffer = self.buffer.read(cx).snapshot(cx);
15274        let mut selected_sibling = false;
15275
15276        let new_selections = old_selections
15277            .iter()
15278            .map(|selection| {
15279                let old_range = selection.start..selection.end;
15280
15281                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15282                    let new_range = node.byte_range();
15283                    selected_sibling = true;
15284                    Selection {
15285                        id: selection.id,
15286                        start: new_range.start,
15287                        end: new_range.end,
15288                        goal: SelectionGoal::None,
15289                        reversed: selection.reversed,
15290                    }
15291                } else {
15292                    selection.clone()
15293                }
15294            })
15295            .collect::<Vec<_>>();
15296
15297        if selected_sibling {
15298            self.change_selections(
15299                SelectionEffects::scroll(Autoscroll::fit()),
15300                window,
15301                cx,
15302                |s| {
15303                    s.select(new_selections);
15304                },
15305            );
15306        }
15307    }
15308
15309    pub fn select_prev_syntax_node(
15310        &mut self,
15311        _: &SelectPreviousSyntaxNode,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) {
15315        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15316        if old_selections.is_empty() {
15317            return;
15318        }
15319
15320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15321
15322        let buffer = self.buffer.read(cx).snapshot(cx);
15323        let mut selected_sibling = false;
15324
15325        let new_selections = old_selections
15326            .iter()
15327            .map(|selection| {
15328                let old_range = selection.start..selection.end;
15329
15330                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15331                    let new_range = node.byte_range();
15332                    selected_sibling = true;
15333                    Selection {
15334                        id: selection.id,
15335                        start: new_range.start,
15336                        end: new_range.end,
15337                        goal: SelectionGoal::None,
15338                        reversed: selection.reversed,
15339                    }
15340                } else {
15341                    selection.clone()
15342                }
15343            })
15344            .collect::<Vec<_>>();
15345
15346        if selected_sibling {
15347            self.change_selections(
15348                SelectionEffects::scroll(Autoscroll::fit()),
15349                window,
15350                cx,
15351                |s| {
15352                    s.select(new_selections);
15353                },
15354            );
15355        }
15356    }
15357
15358    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15359        if !EditorSettings::get_global(cx).gutter.runnables {
15360            self.clear_tasks();
15361            return Task::ready(());
15362        }
15363        let project = self.project().map(Entity::downgrade);
15364        let task_sources = self.lsp_task_sources(cx);
15365        let multi_buffer = self.buffer.downgrade();
15366        cx.spawn_in(window, async move |editor, cx| {
15367            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15368            let Some(project) = project.and_then(|p| p.upgrade()) else {
15369                return;
15370            };
15371            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15372                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15373            }) else {
15374                return;
15375            };
15376
15377            let hide_runnables = project
15378                .update(cx, |project, _| project.is_via_collab())
15379                .unwrap_or(true);
15380            if hide_runnables {
15381                return;
15382            }
15383            let new_rows =
15384                cx.background_spawn({
15385                    let snapshot = display_snapshot.clone();
15386                    async move {
15387                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15388                    }
15389                })
15390                    .await;
15391            let Ok(lsp_tasks) =
15392                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15393            else {
15394                return;
15395            };
15396            let lsp_tasks = lsp_tasks.await;
15397
15398            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15399                lsp_tasks
15400                    .into_iter()
15401                    .flat_map(|(kind, tasks)| {
15402                        tasks.into_iter().filter_map(move |(location, task)| {
15403                            Some((kind.clone(), location?, task))
15404                        })
15405                    })
15406                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15407                        let buffer = location.target.buffer;
15408                        let buffer_snapshot = buffer.read(cx).snapshot();
15409                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15410                            |(excerpt_id, snapshot, _)| {
15411                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15412                                    display_snapshot
15413                                        .buffer_snapshot
15414                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15415                                } else {
15416                                    None
15417                                }
15418                            },
15419                        );
15420                        if let Some(offset) = offset {
15421                            let task_buffer_range =
15422                                location.target.range.to_point(&buffer_snapshot);
15423                            let context_buffer_range =
15424                                task_buffer_range.to_offset(&buffer_snapshot);
15425                            let context_range = BufferOffset(context_buffer_range.start)
15426                                ..BufferOffset(context_buffer_range.end);
15427
15428                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15429                                .or_insert_with(|| RunnableTasks {
15430                                    templates: Vec::new(),
15431                                    offset,
15432                                    column: task_buffer_range.start.column,
15433                                    extra_variables: HashMap::default(),
15434                                    context_range,
15435                                })
15436                                .templates
15437                                .push((kind, task.original_task().clone()));
15438                        }
15439
15440                        acc
15441                    })
15442            }) else {
15443                return;
15444            };
15445
15446            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15447                buffer.language_settings(cx).tasks.prefer_lsp
15448            }) else {
15449                return;
15450            };
15451
15452            let rows = Self::runnable_rows(
15453                project,
15454                display_snapshot,
15455                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15456                new_rows,
15457                cx.clone(),
15458            )
15459            .await;
15460            editor
15461                .update(cx, |editor, _| {
15462                    editor.clear_tasks();
15463                    for (key, mut value) in rows {
15464                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15465                            value.templates.extend(lsp_tasks.templates);
15466                        }
15467
15468                        editor.insert_tasks(key, value);
15469                    }
15470                    for (key, value) in lsp_tasks_by_rows {
15471                        editor.insert_tasks(key, value);
15472                    }
15473                })
15474                .ok();
15475        })
15476    }
15477    fn fetch_runnable_ranges(
15478        snapshot: &DisplaySnapshot,
15479        range: Range<Anchor>,
15480    ) -> Vec<language::RunnableRange> {
15481        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15482    }
15483
15484    fn runnable_rows(
15485        project: Entity<Project>,
15486        snapshot: DisplaySnapshot,
15487        prefer_lsp: bool,
15488        runnable_ranges: Vec<RunnableRange>,
15489        cx: AsyncWindowContext,
15490    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15491        cx.spawn(async move |cx| {
15492            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15493            for mut runnable in runnable_ranges {
15494                let Some(tasks) = cx
15495                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15496                    .ok()
15497                else {
15498                    continue;
15499                };
15500                let mut tasks = tasks.await;
15501
15502                if prefer_lsp {
15503                    tasks.retain(|(task_kind, _)| {
15504                        !matches!(task_kind, TaskSourceKind::Language { .. })
15505                    });
15506                }
15507                if tasks.is_empty() {
15508                    continue;
15509                }
15510
15511                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15512                let Some(row) = snapshot
15513                    .buffer_snapshot
15514                    .buffer_line_for_row(MultiBufferRow(point.row))
15515                    .map(|(_, range)| range.start.row)
15516                else {
15517                    continue;
15518                };
15519
15520                let context_range =
15521                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15522                runnable_rows.push((
15523                    (runnable.buffer_id, row),
15524                    RunnableTasks {
15525                        templates: tasks,
15526                        offset: snapshot
15527                            .buffer_snapshot
15528                            .anchor_before(runnable.run_range.start),
15529                        context_range,
15530                        column: point.column,
15531                        extra_variables: runnable.extra_captures,
15532                    },
15533                ));
15534            }
15535            runnable_rows
15536        })
15537    }
15538
15539    fn templates_with_tags(
15540        project: &Entity<Project>,
15541        runnable: &mut Runnable,
15542        cx: &mut App,
15543    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15544        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15545            let (worktree_id, file) = project
15546                .buffer_for_id(runnable.buffer, cx)
15547                .and_then(|buffer| buffer.read(cx).file())
15548                .map(|file| (file.worktree_id(cx), file.clone()))
15549                .unzip();
15550
15551            (
15552                project.task_store().read(cx).task_inventory().cloned(),
15553                worktree_id,
15554                file,
15555            )
15556        });
15557
15558        let tags = mem::take(&mut runnable.tags);
15559        let language = runnable.language.clone();
15560        cx.spawn(async move |cx| {
15561            let mut templates_with_tags = Vec::new();
15562            if let Some(inventory) = inventory {
15563                for RunnableTag(tag) in tags {
15564                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15565                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15566                    }) else {
15567                        return templates_with_tags;
15568                    };
15569                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15570                        move |(_, template)| {
15571                            template.tags.iter().any(|source_tag| source_tag == &tag)
15572                        },
15573                    ));
15574                }
15575            }
15576            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15577
15578            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15579                // Strongest source wins; if we have worktree tag binding, prefer that to
15580                // global and language bindings;
15581                // if we have a global binding, prefer that to language binding.
15582                let first_mismatch = templates_with_tags
15583                    .iter()
15584                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15585                if let Some(index) = first_mismatch {
15586                    templates_with_tags.truncate(index);
15587                }
15588            }
15589
15590            templates_with_tags
15591        })
15592    }
15593
15594    pub fn move_to_enclosing_bracket(
15595        &mut self,
15596        _: &MoveToEnclosingBracket,
15597        window: &mut Window,
15598        cx: &mut Context<Self>,
15599    ) {
15600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15601        self.change_selections(Default::default(), window, cx, |s| {
15602            s.move_offsets_with(|snapshot, selection| {
15603                let Some(enclosing_bracket_ranges) =
15604                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15605                else {
15606                    return;
15607                };
15608
15609                let mut best_length = usize::MAX;
15610                let mut best_inside = false;
15611                let mut best_in_bracket_range = false;
15612                let mut best_destination = None;
15613                for (open, close) in enclosing_bracket_ranges {
15614                    let close = close.to_inclusive();
15615                    let length = close.end() - open.start;
15616                    let inside = selection.start >= open.end && selection.end <= *close.start();
15617                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15618                        || close.contains(&selection.head());
15619
15620                    // If best is next to a bracket and current isn't, skip
15621                    if !in_bracket_range && best_in_bracket_range {
15622                        continue;
15623                    }
15624
15625                    // Prefer smaller lengths unless best is inside and current isn't
15626                    if length > best_length && (best_inside || !inside) {
15627                        continue;
15628                    }
15629
15630                    best_length = length;
15631                    best_inside = inside;
15632                    best_in_bracket_range = in_bracket_range;
15633                    best_destination = Some(
15634                        if close.contains(&selection.start) && close.contains(&selection.end) {
15635                            if inside { open.end } else { open.start }
15636                        } else if inside {
15637                            *close.start()
15638                        } else {
15639                            *close.end()
15640                        },
15641                    );
15642                }
15643
15644                if let Some(destination) = best_destination {
15645                    selection.collapse_to(destination, SelectionGoal::None);
15646                }
15647            })
15648        });
15649    }
15650
15651    pub fn undo_selection(
15652        &mut self,
15653        _: &UndoSelection,
15654        window: &mut Window,
15655        cx: &mut Context<Self>,
15656    ) {
15657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15658        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15659            self.selection_history.mode = SelectionHistoryMode::Undoing;
15660            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15661                this.end_selection(window, cx);
15662                this.change_selections(
15663                    SelectionEffects::scroll(Autoscroll::newest()),
15664                    window,
15665                    cx,
15666                    |s| s.select_anchors(entry.selections.to_vec()),
15667                );
15668            });
15669            self.selection_history.mode = SelectionHistoryMode::Normal;
15670
15671            self.select_next_state = entry.select_next_state;
15672            self.select_prev_state = entry.select_prev_state;
15673            self.add_selections_state = entry.add_selections_state;
15674        }
15675    }
15676
15677    pub fn redo_selection(
15678        &mut self,
15679        _: &RedoSelection,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) {
15683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15684        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15685            self.selection_history.mode = SelectionHistoryMode::Redoing;
15686            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15687                this.end_selection(window, cx);
15688                this.change_selections(
15689                    SelectionEffects::scroll(Autoscroll::newest()),
15690                    window,
15691                    cx,
15692                    |s| s.select_anchors(entry.selections.to_vec()),
15693                );
15694            });
15695            self.selection_history.mode = SelectionHistoryMode::Normal;
15696
15697            self.select_next_state = entry.select_next_state;
15698            self.select_prev_state = entry.select_prev_state;
15699            self.add_selections_state = entry.add_selections_state;
15700        }
15701    }
15702
15703    pub fn expand_excerpts(
15704        &mut self,
15705        action: &ExpandExcerpts,
15706        _: &mut Window,
15707        cx: &mut Context<Self>,
15708    ) {
15709        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15710    }
15711
15712    pub fn expand_excerpts_down(
15713        &mut self,
15714        action: &ExpandExcerptsDown,
15715        _: &mut Window,
15716        cx: &mut Context<Self>,
15717    ) {
15718        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15719    }
15720
15721    pub fn expand_excerpts_up(
15722        &mut self,
15723        action: &ExpandExcerptsUp,
15724        _: &mut Window,
15725        cx: &mut Context<Self>,
15726    ) {
15727        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15728    }
15729
15730    pub fn expand_excerpts_for_direction(
15731        &mut self,
15732        lines: u32,
15733        direction: ExpandExcerptDirection,
15734
15735        cx: &mut Context<Self>,
15736    ) {
15737        let selections = self.selections.disjoint_anchors_arc();
15738
15739        let lines = if lines == 0 {
15740            EditorSettings::get_global(cx).expand_excerpt_lines
15741        } else {
15742            lines
15743        };
15744
15745        self.buffer.update(cx, |buffer, cx| {
15746            let snapshot = buffer.snapshot(cx);
15747            let mut excerpt_ids = selections
15748                .iter()
15749                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15750                .collect::<Vec<_>>();
15751            excerpt_ids.sort();
15752            excerpt_ids.dedup();
15753            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15754        })
15755    }
15756
15757    pub fn expand_excerpt(
15758        &mut self,
15759        excerpt: ExcerptId,
15760        direction: ExpandExcerptDirection,
15761        window: &mut Window,
15762        cx: &mut Context<Self>,
15763    ) {
15764        let current_scroll_position = self.scroll_position(cx);
15765        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15766        let mut should_scroll_up = false;
15767
15768        if direction == ExpandExcerptDirection::Down {
15769            let multi_buffer = self.buffer.read(cx);
15770            let snapshot = multi_buffer.snapshot(cx);
15771            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15772                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15773                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15774            {
15775                let buffer_snapshot = buffer.read(cx).snapshot();
15776                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15777                let last_row = buffer_snapshot.max_point().row;
15778                let lines_below = last_row.saturating_sub(excerpt_end_row);
15779                should_scroll_up = lines_below >= lines_to_expand;
15780            }
15781        }
15782
15783        self.buffer.update(cx, |buffer, cx| {
15784            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15785        });
15786
15787        if should_scroll_up {
15788            let new_scroll_position =
15789                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15790            self.set_scroll_position(new_scroll_position, window, cx);
15791        }
15792    }
15793
15794    pub fn go_to_singleton_buffer_point(
15795        &mut self,
15796        point: Point,
15797        window: &mut Window,
15798        cx: &mut Context<Self>,
15799    ) {
15800        self.go_to_singleton_buffer_range(point..point, window, cx);
15801    }
15802
15803    pub fn go_to_singleton_buffer_range(
15804        &mut self,
15805        range: Range<Point>,
15806        window: &mut Window,
15807        cx: &mut Context<Self>,
15808    ) {
15809        let multibuffer = self.buffer().read(cx);
15810        let Some(buffer) = multibuffer.as_singleton() else {
15811            return;
15812        };
15813        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15814            return;
15815        };
15816        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15817            return;
15818        };
15819        self.change_selections(
15820            SelectionEffects::default().nav_history(true),
15821            window,
15822            cx,
15823            |s| s.select_anchor_ranges([start..end]),
15824        );
15825    }
15826
15827    pub fn go_to_diagnostic(
15828        &mut self,
15829        action: &GoToDiagnostic,
15830        window: &mut Window,
15831        cx: &mut Context<Self>,
15832    ) {
15833        if !self.diagnostics_enabled() {
15834            return;
15835        }
15836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15837        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15838    }
15839
15840    pub fn go_to_prev_diagnostic(
15841        &mut self,
15842        action: &GoToPreviousDiagnostic,
15843        window: &mut Window,
15844        cx: &mut Context<Self>,
15845    ) {
15846        if !self.diagnostics_enabled() {
15847            return;
15848        }
15849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15850        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15851    }
15852
15853    pub fn go_to_diagnostic_impl(
15854        &mut self,
15855        direction: Direction,
15856        severity: GoToDiagnosticSeverityFilter,
15857        window: &mut Window,
15858        cx: &mut Context<Self>,
15859    ) {
15860        let buffer = self.buffer.read(cx).snapshot(cx);
15861        let selection = self.selections.newest::<usize>(cx);
15862
15863        let mut active_group_id = None;
15864        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15865            && active_group.active_range.start.to_offset(&buffer) == selection.start
15866        {
15867            active_group_id = Some(active_group.group_id);
15868        }
15869
15870        fn filtered(
15871            snapshot: EditorSnapshot,
15872            severity: GoToDiagnosticSeverityFilter,
15873            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15874        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15875            diagnostics
15876                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15877                .filter(|entry| entry.range.start != entry.range.end)
15878                .filter(|entry| !entry.diagnostic.is_unnecessary)
15879                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15880        }
15881
15882        let snapshot = self.snapshot(window, cx);
15883        let before = filtered(
15884            snapshot.clone(),
15885            severity,
15886            buffer
15887                .diagnostics_in_range(0..selection.start)
15888                .filter(|entry| entry.range.start <= selection.start),
15889        );
15890        let after = filtered(
15891            snapshot,
15892            severity,
15893            buffer
15894                .diagnostics_in_range(selection.start..buffer.len())
15895                .filter(|entry| entry.range.start >= selection.start),
15896        );
15897
15898        let mut found: Option<DiagnosticEntry<usize>> = None;
15899        if direction == Direction::Prev {
15900            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15901            {
15902                for diagnostic in prev_diagnostics.into_iter().rev() {
15903                    if diagnostic.range.start != selection.start
15904                        || active_group_id
15905                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15906                    {
15907                        found = Some(diagnostic);
15908                        break 'outer;
15909                    }
15910                }
15911            }
15912        } else {
15913            for diagnostic in after.chain(before) {
15914                if diagnostic.range.start != selection.start
15915                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15916                {
15917                    found = Some(diagnostic);
15918                    break;
15919                }
15920            }
15921        }
15922        let Some(next_diagnostic) = found else {
15923            return;
15924        };
15925
15926        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15927        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15928            return;
15929        };
15930        self.change_selections(Default::default(), window, cx, |s| {
15931            s.select_ranges(vec![
15932                next_diagnostic.range.start..next_diagnostic.range.start,
15933            ])
15934        });
15935        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15936        self.refresh_edit_prediction(false, true, window, cx);
15937    }
15938
15939    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15941        let snapshot = self.snapshot(window, cx);
15942        let selection = self.selections.newest::<Point>(cx);
15943        self.go_to_hunk_before_or_after_position(
15944            &snapshot,
15945            selection.head(),
15946            Direction::Next,
15947            window,
15948            cx,
15949        );
15950    }
15951
15952    pub fn go_to_hunk_before_or_after_position(
15953        &mut self,
15954        snapshot: &EditorSnapshot,
15955        position: Point,
15956        direction: Direction,
15957        window: &mut Window,
15958        cx: &mut Context<Editor>,
15959    ) {
15960        let row = if direction == Direction::Next {
15961            self.hunk_after_position(snapshot, position)
15962                .map(|hunk| hunk.row_range.start)
15963        } else {
15964            self.hunk_before_position(snapshot, position)
15965        };
15966
15967        if let Some(row) = row {
15968            let destination = Point::new(row.0, 0);
15969            let autoscroll = Autoscroll::center();
15970
15971            self.unfold_ranges(&[destination..destination], false, false, cx);
15972            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15973                s.select_ranges([destination..destination]);
15974            });
15975        }
15976    }
15977
15978    fn hunk_after_position(
15979        &mut self,
15980        snapshot: &EditorSnapshot,
15981        position: Point,
15982    ) -> Option<MultiBufferDiffHunk> {
15983        snapshot
15984            .buffer_snapshot
15985            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15986            .find(|hunk| hunk.row_range.start.0 > position.row)
15987            .or_else(|| {
15988                snapshot
15989                    .buffer_snapshot
15990                    .diff_hunks_in_range(Point::zero()..position)
15991                    .find(|hunk| hunk.row_range.end.0 < position.row)
15992            })
15993    }
15994
15995    fn go_to_prev_hunk(
15996        &mut self,
15997        _: &GoToPreviousHunk,
15998        window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16002        let snapshot = self.snapshot(window, cx);
16003        let selection = self.selections.newest::<Point>(cx);
16004        self.go_to_hunk_before_or_after_position(
16005            &snapshot,
16006            selection.head(),
16007            Direction::Prev,
16008            window,
16009            cx,
16010        );
16011    }
16012
16013    fn hunk_before_position(
16014        &mut self,
16015        snapshot: &EditorSnapshot,
16016        position: Point,
16017    ) -> Option<MultiBufferRow> {
16018        snapshot
16019            .buffer_snapshot
16020            .diff_hunk_before(position)
16021            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16022    }
16023
16024    fn go_to_next_change(
16025        &mut self,
16026        _: &GoToNextChange,
16027        window: &mut Window,
16028        cx: &mut Context<Self>,
16029    ) {
16030        if let Some(selections) = self
16031            .change_list
16032            .next_change(1, Direction::Next)
16033            .map(|s| s.to_vec())
16034        {
16035            self.change_selections(Default::default(), window, cx, |s| {
16036                let map = s.display_map();
16037                s.select_display_ranges(selections.iter().map(|a| {
16038                    let point = a.to_display_point(&map);
16039                    point..point
16040                }))
16041            })
16042        }
16043    }
16044
16045    fn go_to_previous_change(
16046        &mut self,
16047        _: &GoToPreviousChange,
16048        window: &mut Window,
16049        cx: &mut Context<Self>,
16050    ) {
16051        if let Some(selections) = self
16052            .change_list
16053            .next_change(1, Direction::Prev)
16054            .map(|s| s.to_vec())
16055        {
16056            self.change_selections(Default::default(), window, cx, |s| {
16057                let map = s.display_map();
16058                s.select_display_ranges(selections.iter().map(|a| {
16059                    let point = a.to_display_point(&map);
16060                    point..point
16061                }))
16062            })
16063        }
16064    }
16065
16066    pub fn go_to_next_document_highlight(
16067        &mut self,
16068        _: &GoToNextDocumentHighlight,
16069        window: &mut Window,
16070        cx: &mut Context<Self>,
16071    ) {
16072        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16073    }
16074
16075    pub fn go_to_prev_document_highlight(
16076        &mut self,
16077        _: &GoToPreviousDocumentHighlight,
16078        window: &mut Window,
16079        cx: &mut Context<Self>,
16080    ) {
16081        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16082    }
16083
16084    pub fn go_to_document_highlight_before_or_after_position(
16085        &mut self,
16086        direction: Direction,
16087        window: &mut Window,
16088        cx: &mut Context<Editor>,
16089    ) {
16090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16091        let snapshot = self.snapshot(window, cx);
16092        let buffer = &snapshot.buffer_snapshot;
16093        let position = self.selections.newest::<Point>(cx).head();
16094        let anchor_position = buffer.anchor_after(position);
16095
16096        // Get all document highlights (both read and write)
16097        let mut all_highlights = Vec::new();
16098
16099        if let Some((_, read_highlights)) = self
16100            .background_highlights
16101            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16102        {
16103            all_highlights.extend(read_highlights.iter());
16104        }
16105
16106        if let Some((_, write_highlights)) = self
16107            .background_highlights
16108            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16109        {
16110            all_highlights.extend(write_highlights.iter());
16111        }
16112
16113        if all_highlights.is_empty() {
16114            return;
16115        }
16116
16117        // Sort highlights by position
16118        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16119
16120        let target_highlight = match direction {
16121            Direction::Next => {
16122                // Find the first highlight after the current position
16123                all_highlights
16124                    .iter()
16125                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16126            }
16127            Direction::Prev => {
16128                // Find the last highlight before the current position
16129                all_highlights
16130                    .iter()
16131                    .rev()
16132                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16133            }
16134        };
16135
16136        if let Some(highlight) = target_highlight {
16137            let destination = highlight.start.to_point(buffer);
16138            let autoscroll = Autoscroll::center();
16139
16140            self.unfold_ranges(&[destination..destination], false, false, cx);
16141            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16142                s.select_ranges([destination..destination]);
16143            });
16144        }
16145    }
16146
16147    fn go_to_line<T: 'static>(
16148        &mut self,
16149        position: Anchor,
16150        highlight_color: Option<Hsla>,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) {
16154        let snapshot = self.snapshot(window, cx).display_snapshot;
16155        let position = position.to_point(&snapshot.buffer_snapshot);
16156        let start = snapshot
16157            .buffer_snapshot
16158            .clip_point(Point::new(position.row, 0), Bias::Left);
16159        let end = start + Point::new(1, 0);
16160        let start = snapshot.buffer_snapshot.anchor_before(start);
16161        let end = snapshot.buffer_snapshot.anchor_before(end);
16162
16163        self.highlight_rows::<T>(
16164            start..end,
16165            highlight_color
16166                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16167            Default::default(),
16168            cx,
16169        );
16170
16171        if self.buffer.read(cx).is_singleton() {
16172            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16173        }
16174    }
16175
16176    pub fn go_to_definition(
16177        &mut self,
16178        _: &GoToDefinition,
16179        window: &mut Window,
16180        cx: &mut Context<Self>,
16181    ) -> Task<Result<Navigated>> {
16182        let definition =
16183            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16184        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16185        cx.spawn_in(window, async move |editor, cx| {
16186            if definition.await? == Navigated::Yes {
16187                return Ok(Navigated::Yes);
16188            }
16189            match fallback_strategy {
16190                GoToDefinitionFallback::None => Ok(Navigated::No),
16191                GoToDefinitionFallback::FindAllReferences => {
16192                    match editor.update_in(cx, |editor, window, cx| {
16193                        editor.find_all_references(&FindAllReferences, window, cx)
16194                    })? {
16195                        Some(references) => references.await,
16196                        None => Ok(Navigated::No),
16197                    }
16198                }
16199            }
16200        })
16201    }
16202
16203    pub fn go_to_declaration(
16204        &mut self,
16205        _: &GoToDeclaration,
16206        window: &mut Window,
16207        cx: &mut Context<Self>,
16208    ) -> Task<Result<Navigated>> {
16209        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16210    }
16211
16212    pub fn go_to_declaration_split(
16213        &mut self,
16214        _: &GoToDeclaration,
16215        window: &mut Window,
16216        cx: &mut Context<Self>,
16217    ) -> Task<Result<Navigated>> {
16218        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16219    }
16220
16221    pub fn go_to_implementation(
16222        &mut self,
16223        _: &GoToImplementation,
16224        window: &mut Window,
16225        cx: &mut Context<Self>,
16226    ) -> Task<Result<Navigated>> {
16227        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16228    }
16229
16230    pub fn go_to_implementation_split(
16231        &mut self,
16232        _: &GoToImplementationSplit,
16233        window: &mut Window,
16234        cx: &mut Context<Self>,
16235    ) -> Task<Result<Navigated>> {
16236        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16237    }
16238
16239    pub fn go_to_type_definition(
16240        &mut self,
16241        _: &GoToTypeDefinition,
16242        window: &mut Window,
16243        cx: &mut Context<Self>,
16244    ) -> Task<Result<Navigated>> {
16245        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16246    }
16247
16248    pub fn go_to_definition_split(
16249        &mut self,
16250        _: &GoToDefinitionSplit,
16251        window: &mut Window,
16252        cx: &mut Context<Self>,
16253    ) -> Task<Result<Navigated>> {
16254        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16255    }
16256
16257    pub fn go_to_type_definition_split(
16258        &mut self,
16259        _: &GoToTypeDefinitionSplit,
16260        window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) -> Task<Result<Navigated>> {
16263        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16264    }
16265
16266    fn go_to_definition_of_kind(
16267        &mut self,
16268        kind: GotoDefinitionKind,
16269        split: bool,
16270        window: &mut Window,
16271        cx: &mut Context<Self>,
16272    ) -> Task<Result<Navigated>> {
16273        let Some(provider) = self.semantics_provider.clone() else {
16274            return Task::ready(Ok(Navigated::No));
16275        };
16276        let head = self.selections.newest::<usize>(cx).head();
16277        let buffer = self.buffer.read(cx);
16278        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16279            return Task::ready(Ok(Navigated::No));
16280        };
16281        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16282            return Task::ready(Ok(Navigated::No));
16283        };
16284
16285        cx.spawn_in(window, async move |editor, cx| {
16286            let Some(definitions) = definitions.await? else {
16287                return Ok(Navigated::No);
16288            };
16289            let navigated = editor
16290                .update_in(cx, |editor, window, cx| {
16291                    editor.navigate_to_hover_links(
16292                        Some(kind),
16293                        definitions
16294                            .into_iter()
16295                            .filter(|location| {
16296                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16297                            })
16298                            .map(HoverLink::Text)
16299                            .collect::<Vec<_>>(),
16300                        split,
16301                        window,
16302                        cx,
16303                    )
16304                })?
16305                .await?;
16306            anyhow::Ok(navigated)
16307        })
16308    }
16309
16310    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16311        let selection = self.selections.newest_anchor();
16312        let head = selection.head();
16313        let tail = selection.tail();
16314
16315        let Some((buffer, start_position)) =
16316            self.buffer.read(cx).text_anchor_for_position(head, cx)
16317        else {
16318            return;
16319        };
16320
16321        let end_position = if head != tail {
16322            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16323                return;
16324            };
16325            Some(pos)
16326        } else {
16327            None
16328        };
16329
16330        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16331            let url = if let Some(end_pos) = end_position {
16332                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16333            } else {
16334                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16335            };
16336
16337            if let Some(url) = url {
16338                cx.update(|window, cx| {
16339                    if parse_zed_link(&url, cx).is_some() {
16340                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16341                    } else {
16342                        cx.open_url(&url);
16343                    }
16344                })?;
16345            }
16346
16347            anyhow::Ok(())
16348        });
16349
16350        url_finder.detach();
16351    }
16352
16353    pub fn open_selected_filename(
16354        &mut self,
16355        _: &OpenSelectedFilename,
16356        window: &mut Window,
16357        cx: &mut Context<Self>,
16358    ) {
16359        let Some(workspace) = self.workspace() else {
16360            return;
16361        };
16362
16363        let position = self.selections.newest_anchor().head();
16364
16365        let Some((buffer, buffer_position)) =
16366            self.buffer.read(cx).text_anchor_for_position(position, cx)
16367        else {
16368            return;
16369        };
16370
16371        let project = self.project.clone();
16372
16373        cx.spawn_in(window, async move |_, cx| {
16374            let result = find_file(&buffer, project, buffer_position, cx).await;
16375
16376            if let Some((_, path)) = result {
16377                workspace
16378                    .update_in(cx, |workspace, window, cx| {
16379                        workspace.open_resolved_path(path, window, cx)
16380                    })?
16381                    .await?;
16382            }
16383            anyhow::Ok(())
16384        })
16385        .detach();
16386    }
16387
16388    pub(crate) fn navigate_to_hover_links(
16389        &mut self,
16390        kind: Option<GotoDefinitionKind>,
16391        definitions: Vec<HoverLink>,
16392        split: bool,
16393        window: &mut Window,
16394        cx: &mut Context<Editor>,
16395    ) -> Task<Result<Navigated>> {
16396        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16397        let mut first_url_or_file = None;
16398        let definitions: Vec<_> = definitions
16399            .into_iter()
16400            .filter_map(|def| match def {
16401                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16402                HoverLink::InlayHint(lsp_location, server_id) => {
16403                    let computation =
16404                        self.compute_target_location(lsp_location, server_id, window, cx);
16405                    Some(cx.background_spawn(computation))
16406                }
16407                HoverLink::Url(url) => {
16408                    first_url_or_file = Some(Either::Left(url));
16409                    None
16410                }
16411                HoverLink::File(path) => {
16412                    first_url_or_file = Some(Either::Right(path));
16413                    None
16414                }
16415            })
16416            .collect();
16417
16418        let workspace = self.workspace();
16419
16420        cx.spawn_in(window, async move |editor, cx| {
16421            let locations: Vec<Location> = future::join_all(definitions)
16422                .await
16423                .into_iter()
16424                .filter_map(|location| location.transpose())
16425                .collect::<Result<_>>()
16426                .context("location tasks")?;
16427            let mut locations = cx.update(|_, cx| {
16428                locations
16429                    .into_iter()
16430                    .map(|location| {
16431                        let buffer = location.buffer.read(cx);
16432                        (location.buffer, location.range.to_point(buffer))
16433                    })
16434                    .into_group_map()
16435            })?;
16436            let mut num_locations = 0;
16437            for ranges in locations.values_mut() {
16438                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16439                ranges.dedup();
16440                num_locations += ranges.len();
16441            }
16442
16443            if num_locations > 1 {
16444                let Some(workspace) = workspace else {
16445                    return Ok(Navigated::No);
16446                };
16447
16448                let tab_kind = match kind {
16449                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16450                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16451                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16452                    Some(GotoDefinitionKind::Type) => "Types",
16453                };
16454                let title = editor
16455                    .update_in(cx, |_, _, cx| {
16456                        let target = locations
16457                            .iter()
16458                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16459                            .map(|(buffer, location)| {
16460                                buffer
16461                                    .read(cx)
16462                                    .text_for_range(location.clone())
16463                                    .collect::<String>()
16464                            })
16465                            .filter(|text| !text.contains('\n'))
16466                            .unique()
16467                            .take(3)
16468                            .join(", ");
16469                        if target.is_empty() {
16470                            tab_kind.to_owned()
16471                        } else {
16472                            format!("{tab_kind} for {target}")
16473                        }
16474                    })
16475                    .context("buffer title")?;
16476
16477                let opened = workspace
16478                    .update_in(cx, |workspace, window, cx| {
16479                        Self::open_locations_in_multibuffer(
16480                            workspace,
16481                            locations,
16482                            title,
16483                            split,
16484                            MultibufferSelectionMode::First,
16485                            window,
16486                            cx,
16487                        )
16488                    })
16489                    .is_ok();
16490
16491                anyhow::Ok(Navigated::from_bool(opened))
16492            } else if num_locations == 0 {
16493                // If there is one url or file, open it directly
16494                match first_url_or_file {
16495                    Some(Either::Left(url)) => {
16496                        cx.update(|_, cx| cx.open_url(&url))?;
16497                        Ok(Navigated::Yes)
16498                    }
16499                    Some(Either::Right(path)) => {
16500                        let Some(workspace) = workspace else {
16501                            return Ok(Navigated::No);
16502                        };
16503
16504                        workspace
16505                            .update_in(cx, |workspace, window, cx| {
16506                                workspace.open_resolved_path(path, window, cx)
16507                            })?
16508                            .await?;
16509                        Ok(Navigated::Yes)
16510                    }
16511                    None => Ok(Navigated::No),
16512                }
16513            } else {
16514                let Some(workspace) = workspace else {
16515                    return Ok(Navigated::No);
16516                };
16517
16518                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16519                let target_range = target_ranges.first().unwrap().clone();
16520
16521                editor.update_in(cx, |editor, window, cx| {
16522                    let range = target_range.to_point(target_buffer.read(cx));
16523                    let range = editor.range_for_match(&range);
16524                    let range = collapse_multiline_range(range);
16525
16526                    if !split
16527                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16528                    {
16529                        editor.go_to_singleton_buffer_range(range, window, cx);
16530                    } else {
16531                        let pane = workspace.read(cx).active_pane().clone();
16532                        window.defer(cx, move |window, cx| {
16533                            let target_editor: Entity<Self> =
16534                                workspace.update(cx, |workspace, cx| {
16535                                    let pane = if split {
16536                                        workspace.adjacent_pane(window, cx)
16537                                    } else {
16538                                        workspace.active_pane().clone()
16539                                    };
16540
16541                                    workspace.open_project_item(
16542                                        pane,
16543                                        target_buffer.clone(),
16544                                        true,
16545                                        true,
16546                                        window,
16547                                        cx,
16548                                    )
16549                                });
16550                            target_editor.update(cx, |target_editor, cx| {
16551                                // When selecting a definition in a different buffer, disable the nav history
16552                                // to avoid creating a history entry at the previous cursor location.
16553                                pane.update(cx, |pane, _| pane.disable_history());
16554                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16555                                pane.update(cx, |pane, _| pane.enable_history());
16556                            });
16557                        });
16558                    }
16559                    Navigated::Yes
16560                })
16561            }
16562        })
16563    }
16564
16565    fn compute_target_location(
16566        &self,
16567        lsp_location: lsp::Location,
16568        server_id: LanguageServerId,
16569        window: &mut Window,
16570        cx: &mut Context<Self>,
16571    ) -> Task<anyhow::Result<Option<Location>>> {
16572        let Some(project) = self.project.clone() else {
16573            return Task::ready(Ok(None));
16574        };
16575
16576        cx.spawn_in(window, async move |editor, cx| {
16577            let location_task = editor.update(cx, |_, cx| {
16578                project.update(cx, |project, cx| {
16579                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16580                })
16581            })?;
16582            let location = Some({
16583                let target_buffer_handle = location_task.await.context("open local buffer")?;
16584                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16585                    let target_start = target_buffer
16586                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16587                    let target_end = target_buffer
16588                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16589                    target_buffer.anchor_after(target_start)
16590                        ..target_buffer.anchor_before(target_end)
16591                })?;
16592                Location {
16593                    buffer: target_buffer_handle,
16594                    range,
16595                }
16596            });
16597            Ok(location)
16598        })
16599    }
16600
16601    pub fn find_all_references(
16602        &mut self,
16603        _: &FindAllReferences,
16604        window: &mut Window,
16605        cx: &mut Context<Self>,
16606    ) -> Option<Task<Result<Navigated>>> {
16607        let selection = self.selections.newest::<usize>(cx);
16608        let multi_buffer = self.buffer.read(cx);
16609        let head = selection.head();
16610
16611        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16612        let head_anchor = multi_buffer_snapshot.anchor_at(
16613            head,
16614            if head < selection.tail() {
16615                Bias::Right
16616            } else {
16617                Bias::Left
16618            },
16619        );
16620
16621        match self
16622            .find_all_references_task_sources
16623            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16624        {
16625            Ok(_) => {
16626                log::info!(
16627                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16628                );
16629                return None;
16630            }
16631            Err(i) => {
16632                self.find_all_references_task_sources.insert(i, head_anchor);
16633            }
16634        }
16635
16636        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16637        let workspace = self.workspace()?;
16638        let project = workspace.read(cx).project().clone();
16639        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16640        Some(cx.spawn_in(window, async move |editor, cx| {
16641            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16642                if let Ok(i) = editor
16643                    .find_all_references_task_sources
16644                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16645                {
16646                    editor.find_all_references_task_sources.remove(i);
16647                }
16648            });
16649
16650            let Some(locations) = references.await? else {
16651                return anyhow::Ok(Navigated::No);
16652            };
16653            let mut locations = cx.update(|_, cx| {
16654                locations
16655                    .into_iter()
16656                    .map(|location| {
16657                        let buffer = location.buffer.read(cx);
16658                        (location.buffer, location.range.to_point(buffer))
16659                    })
16660                    .into_group_map()
16661            })?;
16662            if locations.is_empty() {
16663                return anyhow::Ok(Navigated::No);
16664            }
16665            for ranges in locations.values_mut() {
16666                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16667                ranges.dedup();
16668            }
16669
16670            workspace.update_in(cx, |workspace, window, cx| {
16671                let target = locations
16672                    .iter()
16673                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16674                    .map(|(buffer, location)| {
16675                        buffer
16676                            .read(cx)
16677                            .text_for_range(location.clone())
16678                            .collect::<String>()
16679                    })
16680                    .filter(|text| !text.contains('\n'))
16681                    .unique()
16682                    .take(3)
16683                    .join(", ");
16684                let title = if target.is_empty() {
16685                    "References".to_owned()
16686                } else {
16687                    format!("References to {target}")
16688                };
16689                Self::open_locations_in_multibuffer(
16690                    workspace,
16691                    locations,
16692                    title,
16693                    false,
16694                    MultibufferSelectionMode::First,
16695                    window,
16696                    cx,
16697                );
16698                Navigated::Yes
16699            })
16700        }))
16701    }
16702
16703    /// Opens a multibuffer with the given project locations in it
16704    pub fn open_locations_in_multibuffer(
16705        workspace: &mut Workspace,
16706        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16707        title: String,
16708        split: bool,
16709        multibuffer_selection_mode: MultibufferSelectionMode,
16710        window: &mut Window,
16711        cx: &mut Context<Workspace>,
16712    ) {
16713        if locations.is_empty() {
16714            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16715            return;
16716        }
16717
16718        let capability = workspace.project().read(cx).capability();
16719        let mut ranges = <Vec<Range<Anchor>>>::new();
16720
16721        // a key to find existing multibuffer editors with the same set of locations
16722        // to prevent us from opening more and more multibuffer tabs for searches and the like
16723        let mut key = (title.clone(), vec![]);
16724        let excerpt_buffer = cx.new(|cx| {
16725            let key = &mut key.1;
16726            let mut multibuffer = MultiBuffer::new(capability);
16727            for (buffer, mut ranges_for_buffer) in locations {
16728                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16729                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16730                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16731                    PathKey::for_buffer(&buffer, cx),
16732                    buffer.clone(),
16733                    ranges_for_buffer,
16734                    multibuffer_context_lines(cx),
16735                    cx,
16736                );
16737                ranges.extend(new_ranges)
16738            }
16739
16740            multibuffer.with_title(title)
16741        });
16742        let existing = workspace.active_pane().update(cx, |pane, cx| {
16743            pane.items()
16744                .filter_map(|item| item.downcast::<Editor>())
16745                .find(|editor| {
16746                    editor
16747                        .read(cx)
16748                        .lookup_key
16749                        .as_ref()
16750                        .and_then(|it| {
16751                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16752                        })
16753                        .is_some_and(|it| *it == key)
16754                })
16755        });
16756        let editor = existing.unwrap_or_else(|| {
16757            cx.new(|cx| {
16758                let mut editor = Editor::for_multibuffer(
16759                    excerpt_buffer,
16760                    Some(workspace.project().clone()),
16761                    window,
16762                    cx,
16763                );
16764                editor.lookup_key = Some(Box::new(key));
16765                editor
16766            })
16767        });
16768        editor.update(cx, |editor, cx| {
16769            match multibuffer_selection_mode {
16770                MultibufferSelectionMode::First => {
16771                    if let Some(first_range) = ranges.first() {
16772                        editor.change_selections(
16773                            SelectionEffects::no_scroll(),
16774                            window,
16775                            cx,
16776                            |selections| {
16777                                selections.clear_disjoint();
16778                                selections
16779                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16780                            },
16781                        );
16782                    }
16783                    editor.highlight_background::<Self>(
16784                        &ranges,
16785                        |theme| theme.colors().editor_highlighted_line_background,
16786                        cx,
16787                    );
16788                }
16789                MultibufferSelectionMode::All => {
16790                    editor.change_selections(
16791                        SelectionEffects::no_scroll(),
16792                        window,
16793                        cx,
16794                        |selections| {
16795                            selections.clear_disjoint();
16796                            selections.select_anchor_ranges(ranges);
16797                        },
16798                    );
16799                }
16800            }
16801            editor.register_buffers_with_language_servers(cx);
16802        });
16803
16804        let item = Box::new(editor);
16805        let item_id = item.item_id();
16806
16807        if split {
16808            workspace.split_item(SplitDirection::Right, item, window, cx);
16809        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16810            let (preview_item_id, preview_item_idx) =
16811                workspace.active_pane().read_with(cx, |pane, _| {
16812                    (pane.preview_item_id(), pane.preview_item_idx())
16813                });
16814
16815            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16816
16817            if let Some(preview_item_id) = preview_item_id {
16818                workspace.active_pane().update(cx, |pane, cx| {
16819                    pane.remove_item(preview_item_id, false, false, window, cx);
16820                });
16821            }
16822        } else {
16823            workspace.add_item_to_active_pane(item, None, true, window, cx);
16824        }
16825        workspace.active_pane().update(cx, |pane, cx| {
16826            pane.set_preview_item_id(Some(item_id), cx);
16827        });
16828    }
16829
16830    pub fn rename(
16831        &mut self,
16832        _: &Rename,
16833        window: &mut Window,
16834        cx: &mut Context<Self>,
16835    ) -> Option<Task<Result<()>>> {
16836        use language::ToOffset as _;
16837
16838        let provider = self.semantics_provider.clone()?;
16839        let selection = self.selections.newest_anchor().clone();
16840        let (cursor_buffer, cursor_buffer_position) = self
16841            .buffer
16842            .read(cx)
16843            .text_anchor_for_position(selection.head(), cx)?;
16844        let (tail_buffer, cursor_buffer_position_end) = self
16845            .buffer
16846            .read(cx)
16847            .text_anchor_for_position(selection.tail(), cx)?;
16848        if tail_buffer != cursor_buffer {
16849            return None;
16850        }
16851
16852        let snapshot = cursor_buffer.read(cx).snapshot();
16853        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16854        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16855        let prepare_rename = provider
16856            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16857            .unwrap_or_else(|| Task::ready(Ok(None)));
16858        drop(snapshot);
16859
16860        Some(cx.spawn_in(window, async move |this, cx| {
16861            let rename_range = if let Some(range) = prepare_rename.await? {
16862                Some(range)
16863            } else {
16864                this.update(cx, |this, cx| {
16865                    let buffer = this.buffer.read(cx).snapshot(cx);
16866                    let mut buffer_highlights = this
16867                        .document_highlights_for_position(selection.head(), &buffer)
16868                        .filter(|highlight| {
16869                            highlight.start.excerpt_id == selection.head().excerpt_id
16870                                && highlight.end.excerpt_id == selection.head().excerpt_id
16871                        });
16872                    buffer_highlights
16873                        .next()
16874                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16875                })?
16876            };
16877            if let Some(rename_range) = rename_range {
16878                this.update_in(cx, |this, window, cx| {
16879                    let snapshot = cursor_buffer.read(cx).snapshot();
16880                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16881                    let cursor_offset_in_rename_range =
16882                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16883                    let cursor_offset_in_rename_range_end =
16884                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16885
16886                    this.take_rename(false, window, cx);
16887                    let buffer = this.buffer.read(cx).read(cx);
16888                    let cursor_offset = selection.head().to_offset(&buffer);
16889                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16890                    let rename_end = rename_start + rename_buffer_range.len();
16891                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16892                    let mut old_highlight_id = None;
16893                    let old_name: Arc<str> = buffer
16894                        .chunks(rename_start..rename_end, true)
16895                        .map(|chunk| {
16896                            if old_highlight_id.is_none() {
16897                                old_highlight_id = chunk.syntax_highlight_id;
16898                            }
16899                            chunk.text
16900                        })
16901                        .collect::<String>()
16902                        .into();
16903
16904                    drop(buffer);
16905
16906                    // Position the selection in the rename editor so that it matches the current selection.
16907                    this.show_local_selections = false;
16908                    let rename_editor = cx.new(|cx| {
16909                        let mut editor = Editor::single_line(window, cx);
16910                        editor.buffer.update(cx, |buffer, cx| {
16911                            buffer.edit([(0..0, old_name.clone())], None, cx)
16912                        });
16913                        let rename_selection_range = match cursor_offset_in_rename_range
16914                            .cmp(&cursor_offset_in_rename_range_end)
16915                        {
16916                            Ordering::Equal => {
16917                                editor.select_all(&SelectAll, window, cx);
16918                                return editor;
16919                            }
16920                            Ordering::Less => {
16921                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16922                            }
16923                            Ordering::Greater => {
16924                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16925                            }
16926                        };
16927                        if rename_selection_range.end > old_name.len() {
16928                            editor.select_all(&SelectAll, window, cx);
16929                        } else {
16930                            editor.change_selections(Default::default(), window, cx, |s| {
16931                                s.select_ranges([rename_selection_range]);
16932                            });
16933                        }
16934                        editor
16935                    });
16936                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16937                        if e == &EditorEvent::Focused {
16938                            cx.emit(EditorEvent::FocusedIn)
16939                        }
16940                    })
16941                    .detach();
16942
16943                    let write_highlights =
16944                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16945                    let read_highlights =
16946                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16947                    let ranges = write_highlights
16948                        .iter()
16949                        .flat_map(|(_, ranges)| ranges.iter())
16950                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16951                        .cloned()
16952                        .collect();
16953
16954                    this.highlight_text::<Rename>(
16955                        ranges,
16956                        HighlightStyle {
16957                            fade_out: Some(0.6),
16958                            ..Default::default()
16959                        },
16960                        cx,
16961                    );
16962                    let rename_focus_handle = rename_editor.focus_handle(cx);
16963                    window.focus(&rename_focus_handle);
16964                    let block_id = this.insert_blocks(
16965                        [BlockProperties {
16966                            style: BlockStyle::Flex,
16967                            placement: BlockPlacement::Below(range.start),
16968                            height: Some(1),
16969                            render: Arc::new({
16970                                let rename_editor = rename_editor.clone();
16971                                move |cx: &mut BlockContext| {
16972                                    let mut text_style = cx.editor_style.text.clone();
16973                                    if let Some(highlight_style) = old_highlight_id
16974                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16975                                    {
16976                                        text_style = text_style.highlight(highlight_style);
16977                                    }
16978                                    div()
16979                                        .block_mouse_except_scroll()
16980                                        .pl(cx.anchor_x)
16981                                        .child(EditorElement::new(
16982                                            &rename_editor,
16983                                            EditorStyle {
16984                                                background: cx.theme().system().transparent,
16985                                                local_player: cx.editor_style.local_player,
16986                                                text: text_style,
16987                                                scrollbar_width: cx.editor_style.scrollbar_width,
16988                                                syntax: cx.editor_style.syntax.clone(),
16989                                                status: cx.editor_style.status.clone(),
16990                                                inlay_hints_style: HighlightStyle {
16991                                                    font_weight: Some(FontWeight::BOLD),
16992                                                    ..make_inlay_hints_style(cx.app)
16993                                                },
16994                                                edit_prediction_styles: make_suggestion_styles(
16995                                                    cx.app,
16996                                                ),
16997                                                ..EditorStyle::default()
16998                                            },
16999                                        ))
17000                                        .into_any_element()
17001                                }
17002                            }),
17003                            priority: 0,
17004                        }],
17005                        Some(Autoscroll::fit()),
17006                        cx,
17007                    )[0];
17008                    this.pending_rename = Some(RenameState {
17009                        range,
17010                        old_name,
17011                        editor: rename_editor,
17012                        block_id,
17013                    });
17014                })?;
17015            }
17016
17017            Ok(())
17018        }))
17019    }
17020
17021    pub fn confirm_rename(
17022        &mut self,
17023        _: &ConfirmRename,
17024        window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) -> Option<Task<Result<()>>> {
17027        let rename = self.take_rename(false, window, cx)?;
17028        let workspace = self.workspace()?.downgrade();
17029        let (buffer, start) = self
17030            .buffer
17031            .read(cx)
17032            .text_anchor_for_position(rename.range.start, cx)?;
17033        let (end_buffer, _) = self
17034            .buffer
17035            .read(cx)
17036            .text_anchor_for_position(rename.range.end, cx)?;
17037        if buffer != end_buffer {
17038            return None;
17039        }
17040
17041        let old_name = rename.old_name;
17042        let new_name = rename.editor.read(cx).text(cx);
17043
17044        let rename = self.semantics_provider.as_ref()?.perform_rename(
17045            &buffer,
17046            start,
17047            new_name.clone(),
17048            cx,
17049        )?;
17050
17051        Some(cx.spawn_in(window, async move |editor, cx| {
17052            let project_transaction = rename.await?;
17053            Self::open_project_transaction(
17054                &editor,
17055                workspace,
17056                project_transaction,
17057                format!("Rename: {}{}", old_name, new_name),
17058                cx,
17059            )
17060            .await?;
17061
17062            editor.update(cx, |editor, cx| {
17063                editor.refresh_document_highlights(cx);
17064            })?;
17065            Ok(())
17066        }))
17067    }
17068
17069    fn take_rename(
17070        &mut self,
17071        moving_cursor: bool,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) -> Option<RenameState> {
17075        let rename = self.pending_rename.take()?;
17076        if rename.editor.focus_handle(cx).is_focused(window) {
17077            window.focus(&self.focus_handle);
17078        }
17079
17080        self.remove_blocks(
17081            [rename.block_id].into_iter().collect(),
17082            Some(Autoscroll::fit()),
17083            cx,
17084        );
17085        self.clear_highlights::<Rename>(cx);
17086        self.show_local_selections = true;
17087
17088        if moving_cursor {
17089            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17090                editor.selections.newest::<usize>(cx).head()
17091            });
17092
17093            // Update the selection to match the position of the selection inside
17094            // the rename editor.
17095            let snapshot = self.buffer.read(cx).read(cx);
17096            let rename_range = rename.range.to_offset(&snapshot);
17097            let cursor_in_editor = snapshot
17098                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17099                .min(rename_range.end);
17100            drop(snapshot);
17101
17102            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17103                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17104            });
17105        } else {
17106            self.refresh_document_highlights(cx);
17107        }
17108
17109        Some(rename)
17110    }
17111
17112    pub fn pending_rename(&self) -> Option<&RenameState> {
17113        self.pending_rename.as_ref()
17114    }
17115
17116    fn format(
17117        &mut self,
17118        _: &Format,
17119        window: &mut Window,
17120        cx: &mut Context<Self>,
17121    ) -> Option<Task<Result<()>>> {
17122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17123
17124        let project = match &self.project {
17125            Some(project) => project.clone(),
17126            None => return None,
17127        };
17128
17129        Some(self.perform_format(
17130            project,
17131            FormatTrigger::Manual,
17132            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17133            window,
17134            cx,
17135        ))
17136    }
17137
17138    fn format_selections(
17139        &mut self,
17140        _: &FormatSelections,
17141        window: &mut Window,
17142        cx: &mut Context<Self>,
17143    ) -> Option<Task<Result<()>>> {
17144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17145
17146        let project = match &self.project {
17147            Some(project) => project.clone(),
17148            None => return None,
17149        };
17150
17151        let ranges = self
17152            .selections
17153            .all_adjusted(cx)
17154            .into_iter()
17155            .map(|selection| selection.range())
17156            .collect_vec();
17157
17158        Some(self.perform_format(
17159            project,
17160            FormatTrigger::Manual,
17161            FormatTarget::Ranges(ranges),
17162            window,
17163            cx,
17164        ))
17165    }
17166
17167    fn perform_format(
17168        &mut self,
17169        project: Entity<Project>,
17170        trigger: FormatTrigger,
17171        target: FormatTarget,
17172        window: &mut Window,
17173        cx: &mut Context<Self>,
17174    ) -> Task<Result<()>> {
17175        let buffer = self.buffer.clone();
17176        let (buffers, target) = match target {
17177            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17178            FormatTarget::Ranges(selection_ranges) => {
17179                let multi_buffer = buffer.read(cx);
17180                let snapshot = multi_buffer.read(cx);
17181                let mut buffers = HashSet::default();
17182                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17183                    BTreeMap::new();
17184                for selection_range in selection_ranges {
17185                    for (buffer, buffer_range, _) in
17186                        snapshot.range_to_buffer_ranges(selection_range)
17187                    {
17188                        let buffer_id = buffer.remote_id();
17189                        let start = buffer.anchor_before(buffer_range.start);
17190                        let end = buffer.anchor_after(buffer_range.end);
17191                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17192                        buffer_id_to_ranges
17193                            .entry(buffer_id)
17194                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17195                            .or_insert_with(|| vec![start..end]);
17196                    }
17197                }
17198                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17199            }
17200        };
17201
17202        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17203        let selections_prev = transaction_id_prev
17204            .and_then(|transaction_id_prev| {
17205                // default to selections as they were after the last edit, if we have them,
17206                // instead of how they are now.
17207                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17208                // will take you back to where you made the last edit, instead of staying where you scrolled
17209                self.selection_history
17210                    .transaction(transaction_id_prev)
17211                    .map(|t| t.0.clone())
17212            })
17213            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17214
17215        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17216        let format = project.update(cx, |project, cx| {
17217            project.format(buffers, target, true, trigger, cx)
17218        });
17219
17220        cx.spawn_in(window, async move |editor, cx| {
17221            let transaction = futures::select_biased! {
17222                transaction = format.log_err().fuse() => transaction,
17223                () = timeout => {
17224                    log::warn!("timed out waiting for formatting");
17225                    None
17226                }
17227            };
17228
17229            buffer
17230                .update(cx, |buffer, cx| {
17231                    if let Some(transaction) = transaction
17232                        && !buffer.is_singleton()
17233                    {
17234                        buffer.push_transaction(&transaction.0, cx);
17235                    }
17236                    cx.notify();
17237                })
17238                .ok();
17239
17240            if let Some(transaction_id_now) =
17241                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17242            {
17243                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17244                if has_new_transaction {
17245                    _ = editor.update(cx, |editor, _| {
17246                        editor
17247                            .selection_history
17248                            .insert_transaction(transaction_id_now, selections_prev);
17249                    });
17250                }
17251            }
17252
17253            Ok(())
17254        })
17255    }
17256
17257    fn organize_imports(
17258        &mut self,
17259        _: &OrganizeImports,
17260        window: &mut Window,
17261        cx: &mut Context<Self>,
17262    ) -> Option<Task<Result<()>>> {
17263        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17264        let project = match &self.project {
17265            Some(project) => project.clone(),
17266            None => return None,
17267        };
17268        Some(self.perform_code_action_kind(
17269            project,
17270            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17271            window,
17272            cx,
17273        ))
17274    }
17275
17276    fn perform_code_action_kind(
17277        &mut self,
17278        project: Entity<Project>,
17279        kind: CodeActionKind,
17280        window: &mut Window,
17281        cx: &mut Context<Self>,
17282    ) -> Task<Result<()>> {
17283        let buffer = self.buffer.clone();
17284        let buffers = buffer.read(cx).all_buffers();
17285        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17286        let apply_action = project.update(cx, |project, cx| {
17287            project.apply_code_action_kind(buffers, kind, true, cx)
17288        });
17289        cx.spawn_in(window, async move |_, cx| {
17290            let transaction = futures::select_biased! {
17291                () = timeout => {
17292                    log::warn!("timed out waiting for executing code action");
17293                    None
17294                }
17295                transaction = apply_action.log_err().fuse() => transaction,
17296            };
17297            buffer
17298                .update(cx, |buffer, cx| {
17299                    // check if we need this
17300                    if let Some(transaction) = transaction
17301                        && !buffer.is_singleton()
17302                    {
17303                        buffer.push_transaction(&transaction.0, cx);
17304                    }
17305                    cx.notify();
17306                })
17307                .ok();
17308            Ok(())
17309        })
17310    }
17311
17312    pub fn restart_language_server(
17313        &mut self,
17314        _: &RestartLanguageServer,
17315        _: &mut Window,
17316        cx: &mut Context<Self>,
17317    ) {
17318        if let Some(project) = self.project.clone() {
17319            self.buffer.update(cx, |multi_buffer, cx| {
17320                project.update(cx, |project, cx| {
17321                    project.restart_language_servers_for_buffers(
17322                        multi_buffer.all_buffers().into_iter().collect(),
17323                        HashSet::default(),
17324                        cx,
17325                    );
17326                });
17327            })
17328        }
17329    }
17330
17331    pub fn stop_language_server(
17332        &mut self,
17333        _: &StopLanguageServer,
17334        _: &mut Window,
17335        cx: &mut Context<Self>,
17336    ) {
17337        if let Some(project) = self.project.clone() {
17338            self.buffer.update(cx, |multi_buffer, cx| {
17339                project.update(cx, |project, cx| {
17340                    project.stop_language_servers_for_buffers(
17341                        multi_buffer.all_buffers().into_iter().collect(),
17342                        HashSet::default(),
17343                        cx,
17344                    );
17345                    cx.emit(project::Event::RefreshInlayHints);
17346                });
17347            });
17348        }
17349    }
17350
17351    fn cancel_language_server_work(
17352        workspace: &mut Workspace,
17353        _: &actions::CancelLanguageServerWork,
17354        _: &mut Window,
17355        cx: &mut Context<Workspace>,
17356    ) {
17357        let project = workspace.project();
17358        let buffers = workspace
17359            .active_item(cx)
17360            .and_then(|item| item.act_as::<Editor>(cx))
17361            .map_or(HashSet::default(), |editor| {
17362                editor.read(cx).buffer.read(cx).all_buffers()
17363            });
17364        project.update(cx, |project, cx| {
17365            project.cancel_language_server_work_for_buffers(buffers, cx);
17366        });
17367    }
17368
17369    fn show_character_palette(
17370        &mut self,
17371        _: &ShowCharacterPalette,
17372        window: &mut Window,
17373        _: &mut Context<Self>,
17374    ) {
17375        window.show_character_palette();
17376    }
17377
17378    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17379        if !self.diagnostics_enabled() {
17380            return;
17381        }
17382
17383        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17384            let buffer = self.buffer.read(cx).snapshot(cx);
17385            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17386            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17387            let is_valid = buffer
17388                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17389                .any(|entry| {
17390                    entry.diagnostic.is_primary
17391                        && !entry.range.is_empty()
17392                        && entry.range.start == primary_range_start
17393                        && entry.diagnostic.message == active_diagnostics.active_message
17394                });
17395
17396            if !is_valid {
17397                self.dismiss_diagnostics(cx);
17398            }
17399        }
17400    }
17401
17402    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17403        match &self.active_diagnostics {
17404            ActiveDiagnostic::Group(group) => Some(group),
17405            _ => None,
17406        }
17407    }
17408
17409    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17410        if !self.diagnostics_enabled() {
17411            return;
17412        }
17413        self.dismiss_diagnostics(cx);
17414        self.active_diagnostics = ActiveDiagnostic::All;
17415    }
17416
17417    fn activate_diagnostics(
17418        &mut self,
17419        buffer_id: BufferId,
17420        diagnostic: DiagnosticEntry<usize>,
17421        window: &mut Window,
17422        cx: &mut Context<Self>,
17423    ) {
17424        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17425            return;
17426        }
17427        self.dismiss_diagnostics(cx);
17428        let snapshot = self.snapshot(window, cx);
17429        let buffer = self.buffer.read(cx).snapshot(cx);
17430        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17431            return;
17432        };
17433
17434        let diagnostic_group = buffer
17435            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17436            .collect::<Vec<_>>();
17437
17438        let blocks =
17439            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17440
17441        let blocks = self.display_map.update(cx, |display_map, cx| {
17442            display_map.insert_blocks(blocks, cx).into_iter().collect()
17443        });
17444        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17445            active_range: buffer.anchor_before(diagnostic.range.start)
17446                ..buffer.anchor_after(diagnostic.range.end),
17447            active_message: diagnostic.diagnostic.message.clone(),
17448            group_id: diagnostic.diagnostic.group_id,
17449            blocks,
17450        });
17451        cx.notify();
17452    }
17453
17454    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17455        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17456            return;
17457        };
17458
17459        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17460        if let ActiveDiagnostic::Group(group) = prev {
17461            self.display_map.update(cx, |display_map, cx| {
17462                display_map.remove_blocks(group.blocks, cx);
17463            });
17464            cx.notify();
17465        }
17466    }
17467
17468    /// Disable inline diagnostics rendering for this editor.
17469    pub fn disable_inline_diagnostics(&mut self) {
17470        self.inline_diagnostics_enabled = false;
17471        self.inline_diagnostics_update = Task::ready(());
17472        self.inline_diagnostics.clear();
17473    }
17474
17475    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17476        self.diagnostics_enabled = false;
17477        self.dismiss_diagnostics(cx);
17478        self.inline_diagnostics_update = Task::ready(());
17479        self.inline_diagnostics.clear();
17480    }
17481
17482    pub fn disable_word_completions(&mut self) {
17483        self.word_completions_enabled = false;
17484    }
17485
17486    pub fn diagnostics_enabled(&self) -> bool {
17487        self.diagnostics_enabled && self.mode.is_full()
17488    }
17489
17490    pub fn inline_diagnostics_enabled(&self) -> bool {
17491        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17492    }
17493
17494    pub fn show_inline_diagnostics(&self) -> bool {
17495        self.show_inline_diagnostics
17496    }
17497
17498    pub fn toggle_inline_diagnostics(
17499        &mut self,
17500        _: &ToggleInlineDiagnostics,
17501        window: &mut Window,
17502        cx: &mut Context<Editor>,
17503    ) {
17504        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17505        self.refresh_inline_diagnostics(false, window, cx);
17506    }
17507
17508    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17509        self.diagnostics_max_severity = severity;
17510        self.display_map.update(cx, |display_map, _| {
17511            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17512        });
17513    }
17514
17515    pub fn toggle_diagnostics(
17516        &mut self,
17517        _: &ToggleDiagnostics,
17518        window: &mut Window,
17519        cx: &mut Context<Editor>,
17520    ) {
17521        if !self.diagnostics_enabled() {
17522            return;
17523        }
17524
17525        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17526            EditorSettings::get_global(cx)
17527                .diagnostics_max_severity
17528                .filter(|severity| severity != &DiagnosticSeverity::Off)
17529                .unwrap_or(DiagnosticSeverity::Hint)
17530        } else {
17531            DiagnosticSeverity::Off
17532        };
17533        self.set_max_diagnostics_severity(new_severity, cx);
17534        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17535            self.active_diagnostics = ActiveDiagnostic::None;
17536            self.inline_diagnostics_update = Task::ready(());
17537            self.inline_diagnostics.clear();
17538        } else {
17539            self.refresh_inline_diagnostics(false, window, cx);
17540        }
17541
17542        cx.notify();
17543    }
17544
17545    pub fn toggle_minimap(
17546        &mut self,
17547        _: &ToggleMinimap,
17548        window: &mut Window,
17549        cx: &mut Context<Editor>,
17550    ) {
17551        if self.supports_minimap(cx) {
17552            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17553        }
17554    }
17555
17556    fn refresh_inline_diagnostics(
17557        &mut self,
17558        debounce: bool,
17559        window: &mut Window,
17560        cx: &mut Context<Self>,
17561    ) {
17562        let max_severity = ProjectSettings::get_global(cx)
17563            .diagnostics
17564            .inline
17565            .max_severity
17566            .unwrap_or(self.diagnostics_max_severity);
17567
17568        if !self.inline_diagnostics_enabled()
17569            || !self.show_inline_diagnostics
17570            || max_severity == DiagnosticSeverity::Off
17571        {
17572            self.inline_diagnostics_update = Task::ready(());
17573            self.inline_diagnostics.clear();
17574            return;
17575        }
17576
17577        let debounce_ms = ProjectSettings::get_global(cx)
17578            .diagnostics
17579            .inline
17580            .update_debounce_ms;
17581        let debounce = if debounce && debounce_ms > 0 {
17582            Some(Duration::from_millis(debounce_ms))
17583        } else {
17584            None
17585        };
17586        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17587            if let Some(debounce) = debounce {
17588                cx.background_executor().timer(debounce).await;
17589            }
17590            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17591                editor
17592                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17593                    .ok()
17594            }) else {
17595                return;
17596            };
17597
17598            let new_inline_diagnostics = cx
17599                .background_spawn(async move {
17600                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17601                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17602                        let message = diagnostic_entry
17603                            .diagnostic
17604                            .message
17605                            .split_once('\n')
17606                            .map(|(line, _)| line)
17607                            .map(SharedString::new)
17608                            .unwrap_or_else(|| {
17609                                SharedString::from(diagnostic_entry.diagnostic.message)
17610                            });
17611                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17612                        let (Ok(i) | Err(i)) = inline_diagnostics
17613                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17614                        inline_diagnostics.insert(
17615                            i,
17616                            (
17617                                start_anchor,
17618                                InlineDiagnostic {
17619                                    message,
17620                                    group_id: diagnostic_entry.diagnostic.group_id,
17621                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17622                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17623                                    severity: diagnostic_entry.diagnostic.severity,
17624                                },
17625                            ),
17626                        );
17627                    }
17628                    inline_diagnostics
17629                })
17630                .await;
17631
17632            editor
17633                .update(cx, |editor, cx| {
17634                    editor.inline_diagnostics = new_inline_diagnostics;
17635                    cx.notify();
17636                })
17637                .ok();
17638        });
17639    }
17640
17641    fn pull_diagnostics(
17642        &mut self,
17643        buffer_id: Option<BufferId>,
17644        window: &Window,
17645        cx: &mut Context<Self>,
17646    ) -> Option<()> {
17647        if !self.mode().is_full() {
17648            return None;
17649        }
17650        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17651            .diagnostics
17652            .lsp_pull_diagnostics;
17653        if !pull_diagnostics_settings.enabled {
17654            return None;
17655        }
17656        let project = self.project()?.downgrade();
17657        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17658        let mut buffers = self.buffer.read(cx).all_buffers();
17659        if let Some(buffer_id) = buffer_id {
17660            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17661        }
17662
17663        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17664            cx.background_executor().timer(debounce).await;
17665
17666            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17667                buffers
17668                    .into_iter()
17669                    .filter_map(|buffer| {
17670                        project
17671                            .update(cx, |project, cx| {
17672                                project.lsp_store().update(cx, |lsp_store, cx| {
17673                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17674                                })
17675                            })
17676                            .ok()
17677                    })
17678                    .collect::<FuturesUnordered<_>>()
17679            }) else {
17680                return;
17681            };
17682
17683            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17684                match pull_task {
17685                    Ok(()) => {
17686                        if editor
17687                            .update_in(cx, |editor, window, cx| {
17688                                editor.update_diagnostics_state(window, cx);
17689                            })
17690                            .is_err()
17691                        {
17692                            return;
17693                        }
17694                    }
17695                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17696                }
17697            }
17698        });
17699
17700        Some(())
17701    }
17702
17703    pub fn set_selections_from_remote(
17704        &mut self,
17705        selections: Vec<Selection<Anchor>>,
17706        pending_selection: Option<Selection<Anchor>>,
17707        window: &mut Window,
17708        cx: &mut Context<Self>,
17709    ) {
17710        let old_cursor_position = self.selections.newest_anchor().head();
17711        self.selections.change_with(cx, |s| {
17712            s.select_anchors(selections);
17713            if let Some(pending_selection) = pending_selection {
17714                s.set_pending(pending_selection, SelectMode::Character);
17715            } else {
17716                s.clear_pending();
17717            }
17718        });
17719        self.selections_did_change(
17720            false,
17721            &old_cursor_position,
17722            SelectionEffects::default(),
17723            window,
17724            cx,
17725        );
17726    }
17727
17728    pub fn transact(
17729        &mut self,
17730        window: &mut Window,
17731        cx: &mut Context<Self>,
17732        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17733    ) -> Option<TransactionId> {
17734        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17735            this.start_transaction_at(Instant::now(), window, cx);
17736            update(this, window, cx);
17737            this.end_transaction_at(Instant::now(), cx)
17738        })
17739    }
17740
17741    pub fn start_transaction_at(
17742        &mut self,
17743        now: Instant,
17744        window: &mut Window,
17745        cx: &mut Context<Self>,
17746    ) -> Option<TransactionId> {
17747        self.end_selection(window, cx);
17748        if let Some(tx_id) = self
17749            .buffer
17750            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17751        {
17752            self.selection_history
17753                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17754            cx.emit(EditorEvent::TransactionBegun {
17755                transaction_id: tx_id,
17756            });
17757            Some(tx_id)
17758        } else {
17759            None
17760        }
17761    }
17762
17763    pub fn end_transaction_at(
17764        &mut self,
17765        now: Instant,
17766        cx: &mut Context<Self>,
17767    ) -> Option<TransactionId> {
17768        if let Some(transaction_id) = self
17769            .buffer
17770            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17771        {
17772            if let Some((_, end_selections)) =
17773                self.selection_history.transaction_mut(transaction_id)
17774            {
17775                *end_selections = Some(self.selections.disjoint_anchors_arc());
17776            } else {
17777                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17778            }
17779
17780            cx.emit(EditorEvent::Edited { transaction_id });
17781            Some(transaction_id)
17782        } else {
17783            None
17784        }
17785    }
17786
17787    pub fn modify_transaction_selection_history(
17788        &mut self,
17789        transaction_id: TransactionId,
17790        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17791    ) -> bool {
17792        self.selection_history
17793            .transaction_mut(transaction_id)
17794            .map(modify)
17795            .is_some()
17796    }
17797
17798    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17799        if self.selection_mark_mode {
17800            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17801                s.move_with(|_, sel| {
17802                    sel.collapse_to(sel.head(), SelectionGoal::None);
17803                });
17804            })
17805        }
17806        self.selection_mark_mode = true;
17807        cx.notify();
17808    }
17809
17810    pub fn swap_selection_ends(
17811        &mut self,
17812        _: &actions::SwapSelectionEnds,
17813        window: &mut Window,
17814        cx: &mut Context<Self>,
17815    ) {
17816        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17817            s.move_with(|_, sel| {
17818                if sel.start != sel.end {
17819                    sel.reversed = !sel.reversed
17820                }
17821            });
17822        });
17823        self.request_autoscroll(Autoscroll::newest(), cx);
17824        cx.notify();
17825    }
17826
17827    pub fn toggle_focus(
17828        workspace: &mut Workspace,
17829        _: &actions::ToggleFocus,
17830        window: &mut Window,
17831        cx: &mut Context<Workspace>,
17832    ) {
17833        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17834            return;
17835        };
17836        workspace.activate_item(&item, true, true, window, cx);
17837    }
17838
17839    pub fn toggle_fold(
17840        &mut self,
17841        _: &actions::ToggleFold,
17842        window: &mut Window,
17843        cx: &mut Context<Self>,
17844    ) {
17845        if self.is_singleton(cx) {
17846            let selection = self.selections.newest::<Point>(cx);
17847
17848            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17849            let range = if selection.is_empty() {
17850                let point = selection.head().to_display_point(&display_map);
17851                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17852                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17853                    .to_point(&display_map);
17854                start..end
17855            } else {
17856                selection.range()
17857            };
17858            if display_map.folds_in_range(range).next().is_some() {
17859                self.unfold_lines(&Default::default(), window, cx)
17860            } else {
17861                self.fold(&Default::default(), window, cx)
17862            }
17863        } else {
17864            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17865            let buffer_ids: HashSet<_> = self
17866                .selections
17867                .disjoint_anchor_ranges()
17868                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17869                .collect();
17870
17871            let should_unfold = buffer_ids
17872                .iter()
17873                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17874
17875            for buffer_id in buffer_ids {
17876                if should_unfold {
17877                    self.unfold_buffer(buffer_id, cx);
17878                } else {
17879                    self.fold_buffer(buffer_id, cx);
17880                }
17881            }
17882        }
17883    }
17884
17885    pub fn toggle_fold_recursive(
17886        &mut self,
17887        _: &actions::ToggleFoldRecursive,
17888        window: &mut Window,
17889        cx: &mut Context<Self>,
17890    ) {
17891        let selection = self.selections.newest::<Point>(cx);
17892
17893        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17894        let range = if selection.is_empty() {
17895            let point = selection.head().to_display_point(&display_map);
17896            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17897            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17898                .to_point(&display_map);
17899            start..end
17900        } else {
17901            selection.range()
17902        };
17903        if display_map.folds_in_range(range).next().is_some() {
17904            self.unfold_recursive(&Default::default(), window, cx)
17905        } else {
17906            self.fold_recursive(&Default::default(), window, cx)
17907        }
17908    }
17909
17910    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17911        if self.is_singleton(cx) {
17912            let mut to_fold = Vec::new();
17913            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17914            let selections = self.selections.all_adjusted(cx);
17915
17916            for selection in selections {
17917                let range = selection.range().sorted();
17918                let buffer_start_row = range.start.row;
17919
17920                if range.start.row != range.end.row {
17921                    let mut found = false;
17922                    let mut row = range.start.row;
17923                    while row <= range.end.row {
17924                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17925                        {
17926                            found = true;
17927                            row = crease.range().end.row + 1;
17928                            to_fold.push(crease);
17929                        } else {
17930                            row += 1
17931                        }
17932                    }
17933                    if found {
17934                        continue;
17935                    }
17936                }
17937
17938                for row in (0..=range.start.row).rev() {
17939                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17940                        && crease.range().end.row >= buffer_start_row
17941                    {
17942                        to_fold.push(crease);
17943                        if row <= range.start.row {
17944                            break;
17945                        }
17946                    }
17947                }
17948            }
17949
17950            self.fold_creases(to_fold, true, window, cx);
17951        } else {
17952            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17953            let buffer_ids = self
17954                .selections
17955                .disjoint_anchor_ranges()
17956                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17957                .collect::<HashSet<_>>();
17958            for buffer_id in buffer_ids {
17959                self.fold_buffer(buffer_id, cx);
17960            }
17961        }
17962    }
17963
17964    pub fn toggle_fold_all(
17965        &mut self,
17966        _: &actions::ToggleFoldAll,
17967        window: &mut Window,
17968        cx: &mut Context<Self>,
17969    ) {
17970        if self.buffer.read(cx).is_singleton() {
17971            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17972            let has_folds = display_map
17973                .folds_in_range(0..display_map.buffer_snapshot.len())
17974                .next()
17975                .is_some();
17976
17977            if has_folds {
17978                self.unfold_all(&actions::UnfoldAll, window, cx);
17979            } else {
17980                self.fold_all(&actions::FoldAll, window, cx);
17981            }
17982        } else {
17983            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17984            let should_unfold = buffer_ids
17985                .iter()
17986                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17987
17988            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17989                editor
17990                    .update_in(cx, |editor, _, cx| {
17991                        for buffer_id in buffer_ids {
17992                            if should_unfold {
17993                                editor.unfold_buffer(buffer_id, cx);
17994                            } else {
17995                                editor.fold_buffer(buffer_id, cx);
17996                            }
17997                        }
17998                    })
17999                    .ok();
18000            });
18001        }
18002    }
18003
18004    fn fold_at_level(
18005        &mut self,
18006        fold_at: &FoldAtLevel,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        if !self.buffer.read(cx).is_singleton() {
18011            return;
18012        }
18013
18014        let fold_at_level = fold_at.0;
18015        let snapshot = self.buffer.read(cx).snapshot(cx);
18016        let mut to_fold = Vec::new();
18017        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18018
18019        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18020            while start_row < end_row {
18021                match self
18022                    .snapshot(window, cx)
18023                    .crease_for_buffer_row(MultiBufferRow(start_row))
18024                {
18025                    Some(crease) => {
18026                        let nested_start_row = crease.range().start.row + 1;
18027                        let nested_end_row = crease.range().end.row;
18028
18029                        if current_level < fold_at_level {
18030                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18031                        } else if current_level == fold_at_level {
18032                            to_fold.push(crease);
18033                        }
18034
18035                        start_row = nested_end_row + 1;
18036                    }
18037                    None => start_row += 1,
18038                }
18039            }
18040        }
18041
18042        self.fold_creases(to_fold, true, window, cx);
18043    }
18044
18045    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18046        if self.buffer.read(cx).is_singleton() {
18047            let mut fold_ranges = Vec::new();
18048            let snapshot = self.buffer.read(cx).snapshot(cx);
18049
18050            for row in 0..snapshot.max_row().0 {
18051                if let Some(foldable_range) = self
18052                    .snapshot(window, cx)
18053                    .crease_for_buffer_row(MultiBufferRow(row))
18054                {
18055                    fold_ranges.push(foldable_range);
18056                }
18057            }
18058
18059            self.fold_creases(fold_ranges, true, window, cx);
18060        } else {
18061            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18062                editor
18063                    .update_in(cx, |editor, _, cx| {
18064                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18065                            editor.fold_buffer(buffer_id, cx);
18066                        }
18067                    })
18068                    .ok();
18069            });
18070        }
18071    }
18072
18073    pub fn fold_function_bodies(
18074        &mut self,
18075        _: &actions::FoldFunctionBodies,
18076        window: &mut Window,
18077        cx: &mut Context<Self>,
18078    ) {
18079        let snapshot = self.buffer.read(cx).snapshot(cx);
18080
18081        let ranges = snapshot
18082            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18083            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18084            .collect::<Vec<_>>();
18085
18086        let creases = ranges
18087            .into_iter()
18088            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18089            .collect();
18090
18091        self.fold_creases(creases, true, window, cx);
18092    }
18093
18094    pub fn fold_recursive(
18095        &mut self,
18096        _: &actions::FoldRecursive,
18097        window: &mut Window,
18098        cx: &mut Context<Self>,
18099    ) {
18100        let mut to_fold = Vec::new();
18101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18102        let selections = self.selections.all_adjusted(cx);
18103
18104        for selection in selections {
18105            let range = selection.range().sorted();
18106            let buffer_start_row = range.start.row;
18107
18108            if range.start.row != range.end.row {
18109                let mut found = false;
18110                for row in range.start.row..=range.end.row {
18111                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18112                        found = true;
18113                        to_fold.push(crease);
18114                    }
18115                }
18116                if found {
18117                    continue;
18118                }
18119            }
18120
18121            for row in (0..=range.start.row).rev() {
18122                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18123                    if crease.range().end.row >= buffer_start_row {
18124                        to_fold.push(crease);
18125                    } else {
18126                        break;
18127                    }
18128                }
18129            }
18130        }
18131
18132        self.fold_creases(to_fold, true, window, cx);
18133    }
18134
18135    pub fn fold_at(
18136        &mut self,
18137        buffer_row: MultiBufferRow,
18138        window: &mut Window,
18139        cx: &mut Context<Self>,
18140    ) {
18141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18142
18143        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18144            let autoscroll = self
18145                .selections
18146                .all::<Point>(cx)
18147                .iter()
18148                .any(|selection| crease.range().overlaps(&selection.range()));
18149
18150            self.fold_creases(vec![crease], autoscroll, window, cx);
18151        }
18152    }
18153
18154    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18155        if self.is_singleton(cx) {
18156            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18157            let buffer = &display_map.buffer_snapshot;
18158            let selections = self.selections.all::<Point>(cx);
18159            let ranges = selections
18160                .iter()
18161                .map(|s| {
18162                    let range = s.display_range(&display_map).sorted();
18163                    let mut start = range.start.to_point(&display_map);
18164                    let mut end = range.end.to_point(&display_map);
18165                    start.column = 0;
18166                    end.column = buffer.line_len(MultiBufferRow(end.row));
18167                    start..end
18168                })
18169                .collect::<Vec<_>>();
18170
18171            self.unfold_ranges(&ranges, true, true, cx);
18172        } else {
18173            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18174            let buffer_ids = self
18175                .selections
18176                .disjoint_anchor_ranges()
18177                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18178                .collect::<HashSet<_>>();
18179            for buffer_id in buffer_ids {
18180                self.unfold_buffer(buffer_id, cx);
18181            }
18182        }
18183    }
18184
18185    pub fn unfold_recursive(
18186        &mut self,
18187        _: &UnfoldRecursive,
18188        _window: &mut Window,
18189        cx: &mut Context<Self>,
18190    ) {
18191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18192        let selections = self.selections.all::<Point>(cx);
18193        let ranges = selections
18194            .iter()
18195            .map(|s| {
18196                let mut range = s.display_range(&display_map).sorted();
18197                *range.start.column_mut() = 0;
18198                *range.end.column_mut() = display_map.line_len(range.end.row());
18199                let start = range.start.to_point(&display_map);
18200                let end = range.end.to_point(&display_map);
18201                start..end
18202            })
18203            .collect::<Vec<_>>();
18204
18205        self.unfold_ranges(&ranges, true, true, cx);
18206    }
18207
18208    pub fn unfold_at(
18209        &mut self,
18210        buffer_row: MultiBufferRow,
18211        _window: &mut Window,
18212        cx: &mut Context<Self>,
18213    ) {
18214        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18215
18216        let intersection_range = Point::new(buffer_row.0, 0)
18217            ..Point::new(
18218                buffer_row.0,
18219                display_map.buffer_snapshot.line_len(buffer_row),
18220            );
18221
18222        let autoscroll = self
18223            .selections
18224            .all::<Point>(cx)
18225            .iter()
18226            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18227
18228        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18229    }
18230
18231    pub fn unfold_all(
18232        &mut self,
18233        _: &actions::UnfoldAll,
18234        _window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) {
18237        if self.buffer.read(cx).is_singleton() {
18238            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18239            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18240        } else {
18241            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18242                editor
18243                    .update(cx, |editor, cx| {
18244                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18245                            editor.unfold_buffer(buffer_id, cx);
18246                        }
18247                    })
18248                    .ok();
18249            });
18250        }
18251    }
18252
18253    pub fn fold_selected_ranges(
18254        &mut self,
18255        _: &FoldSelectedRanges,
18256        window: &mut Window,
18257        cx: &mut Context<Self>,
18258    ) {
18259        let selections = self.selections.all_adjusted(cx);
18260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18261        let ranges = selections
18262            .into_iter()
18263            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18264            .collect::<Vec<_>>();
18265        self.fold_creases(ranges, true, window, cx);
18266    }
18267
18268    pub fn fold_ranges<T: ToOffset + Clone>(
18269        &mut self,
18270        ranges: Vec<Range<T>>,
18271        auto_scroll: bool,
18272        window: &mut Window,
18273        cx: &mut Context<Self>,
18274    ) {
18275        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18276        let ranges = ranges
18277            .into_iter()
18278            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18279            .collect::<Vec<_>>();
18280        self.fold_creases(ranges, auto_scroll, window, cx);
18281    }
18282
18283    pub fn fold_creases<T: ToOffset + Clone>(
18284        &mut self,
18285        creases: Vec<Crease<T>>,
18286        auto_scroll: bool,
18287        _window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        if creases.is_empty() {
18291            return;
18292        }
18293
18294        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18295
18296        if auto_scroll {
18297            self.request_autoscroll(Autoscroll::fit(), cx);
18298        }
18299
18300        cx.notify();
18301
18302        self.scrollbar_marker_state.dirty = true;
18303        self.folds_did_change(cx);
18304    }
18305
18306    /// Removes any folds whose ranges intersect any of the given ranges.
18307    pub fn unfold_ranges<T: ToOffset + Clone>(
18308        &mut self,
18309        ranges: &[Range<T>],
18310        inclusive: bool,
18311        auto_scroll: bool,
18312        cx: &mut Context<Self>,
18313    ) {
18314        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18315            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18316        });
18317        self.folds_did_change(cx);
18318    }
18319
18320    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18321        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18322            return;
18323        }
18324        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18325        self.display_map.update(cx, |display_map, cx| {
18326            display_map.fold_buffers([buffer_id], cx)
18327        });
18328        cx.emit(EditorEvent::BufferFoldToggled {
18329            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18330            folded: true,
18331        });
18332        cx.notify();
18333    }
18334
18335    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18336        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18337            return;
18338        }
18339        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18340        self.display_map.update(cx, |display_map, cx| {
18341            display_map.unfold_buffers([buffer_id], cx);
18342        });
18343        cx.emit(EditorEvent::BufferFoldToggled {
18344            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18345            folded: false,
18346        });
18347        cx.notify();
18348    }
18349
18350    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18351        self.display_map.read(cx).is_buffer_folded(buffer)
18352    }
18353
18354    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18355        self.display_map.read(cx).folded_buffers()
18356    }
18357
18358    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18359        self.display_map.update(cx, |display_map, cx| {
18360            display_map.disable_header_for_buffer(buffer_id, cx);
18361        });
18362        cx.notify();
18363    }
18364
18365    /// Removes any folds with the given ranges.
18366    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18367        &mut self,
18368        ranges: &[Range<T>],
18369        type_id: TypeId,
18370        auto_scroll: bool,
18371        cx: &mut Context<Self>,
18372    ) {
18373        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18374            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18375        });
18376        self.folds_did_change(cx);
18377    }
18378
18379    fn remove_folds_with<T: ToOffset + Clone>(
18380        &mut self,
18381        ranges: &[Range<T>],
18382        auto_scroll: bool,
18383        cx: &mut Context<Self>,
18384        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18385    ) {
18386        if ranges.is_empty() {
18387            return;
18388        }
18389
18390        let mut buffers_affected = HashSet::default();
18391        let multi_buffer = self.buffer().read(cx);
18392        for range in ranges {
18393            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18394                buffers_affected.insert(buffer.read(cx).remote_id());
18395            };
18396        }
18397
18398        self.display_map.update(cx, update);
18399
18400        if auto_scroll {
18401            self.request_autoscroll(Autoscroll::fit(), cx);
18402        }
18403
18404        cx.notify();
18405        self.scrollbar_marker_state.dirty = true;
18406        self.active_indent_guides_state.dirty = true;
18407    }
18408
18409    pub fn update_renderer_widths(
18410        &mut self,
18411        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18412        cx: &mut Context<Self>,
18413    ) -> bool {
18414        self.display_map
18415            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18416    }
18417
18418    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18419        self.display_map.read(cx).fold_placeholder.clone()
18420    }
18421
18422    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18423        self.buffer.update(cx, |buffer, cx| {
18424            buffer.set_all_diff_hunks_expanded(cx);
18425        });
18426    }
18427
18428    pub fn expand_all_diff_hunks(
18429        &mut self,
18430        _: &ExpandAllDiffHunks,
18431        _window: &mut Window,
18432        cx: &mut Context<Self>,
18433    ) {
18434        self.buffer.update(cx, |buffer, cx| {
18435            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18436        });
18437    }
18438
18439    pub fn toggle_selected_diff_hunks(
18440        &mut self,
18441        _: &ToggleSelectedDiffHunks,
18442        _window: &mut Window,
18443        cx: &mut Context<Self>,
18444    ) {
18445        let ranges: Vec<_> = self
18446            .selections
18447            .disjoint_anchors()
18448            .iter()
18449            .map(|s| s.range())
18450            .collect();
18451        self.toggle_diff_hunks_in_ranges(ranges, cx);
18452    }
18453
18454    pub fn diff_hunks_in_ranges<'a>(
18455        &'a self,
18456        ranges: &'a [Range<Anchor>],
18457        buffer: &'a MultiBufferSnapshot,
18458    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18459        ranges.iter().flat_map(move |range| {
18460            let end_excerpt_id = range.end.excerpt_id;
18461            let range = range.to_point(buffer);
18462            let mut peek_end = range.end;
18463            if range.end.row < buffer.max_row().0 {
18464                peek_end = Point::new(range.end.row + 1, 0);
18465            }
18466            buffer
18467                .diff_hunks_in_range(range.start..peek_end)
18468                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18469        })
18470    }
18471
18472    pub fn has_stageable_diff_hunks_in_ranges(
18473        &self,
18474        ranges: &[Range<Anchor>],
18475        snapshot: &MultiBufferSnapshot,
18476    ) -> bool {
18477        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18478        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18479    }
18480
18481    pub fn toggle_staged_selected_diff_hunks(
18482        &mut self,
18483        _: &::git::ToggleStaged,
18484        _: &mut Window,
18485        cx: &mut Context<Self>,
18486    ) {
18487        let snapshot = self.buffer.read(cx).snapshot(cx);
18488        let ranges: Vec<_> = self
18489            .selections
18490            .disjoint_anchors()
18491            .iter()
18492            .map(|s| s.range())
18493            .collect();
18494        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18495        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18496    }
18497
18498    pub fn set_render_diff_hunk_controls(
18499        &mut self,
18500        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18501        cx: &mut Context<Self>,
18502    ) {
18503        self.render_diff_hunk_controls = render_diff_hunk_controls;
18504        cx.notify();
18505    }
18506
18507    pub fn stage_and_next(
18508        &mut self,
18509        _: &::git::StageAndNext,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        self.do_stage_or_unstage_and_next(true, window, cx);
18514    }
18515
18516    pub fn unstage_and_next(
18517        &mut self,
18518        _: &::git::UnstageAndNext,
18519        window: &mut Window,
18520        cx: &mut Context<Self>,
18521    ) {
18522        self.do_stage_or_unstage_and_next(false, window, cx);
18523    }
18524
18525    pub fn stage_or_unstage_diff_hunks(
18526        &mut self,
18527        stage: bool,
18528        ranges: Vec<Range<Anchor>>,
18529        cx: &mut Context<Self>,
18530    ) {
18531        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18532        cx.spawn(async move |this, cx| {
18533            task.await?;
18534            this.update(cx, |this, cx| {
18535                let snapshot = this.buffer.read(cx).snapshot(cx);
18536                let chunk_by = this
18537                    .diff_hunks_in_ranges(&ranges, &snapshot)
18538                    .chunk_by(|hunk| hunk.buffer_id);
18539                for (buffer_id, hunks) in &chunk_by {
18540                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18541                }
18542            })
18543        })
18544        .detach_and_log_err(cx);
18545    }
18546
18547    fn save_buffers_for_ranges_if_needed(
18548        &mut self,
18549        ranges: &[Range<Anchor>],
18550        cx: &mut Context<Editor>,
18551    ) -> Task<Result<()>> {
18552        let multibuffer = self.buffer.read(cx);
18553        let snapshot = multibuffer.read(cx);
18554        let buffer_ids: HashSet<_> = ranges
18555            .iter()
18556            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18557            .collect();
18558        drop(snapshot);
18559
18560        let mut buffers = HashSet::default();
18561        for buffer_id in buffer_ids {
18562            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18563                let buffer = buffer_entity.read(cx);
18564                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18565                {
18566                    buffers.insert(buffer_entity);
18567                }
18568            }
18569        }
18570
18571        if let Some(project) = &self.project {
18572            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18573        } else {
18574            Task::ready(Ok(()))
18575        }
18576    }
18577
18578    fn do_stage_or_unstage_and_next(
18579        &mut self,
18580        stage: bool,
18581        window: &mut Window,
18582        cx: &mut Context<Self>,
18583    ) {
18584        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18585
18586        if ranges.iter().any(|range| range.start != range.end) {
18587            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18588            return;
18589        }
18590
18591        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18592        let snapshot = self.snapshot(window, cx);
18593        let position = self.selections.newest::<Point>(cx).head();
18594        let mut row = snapshot
18595            .buffer_snapshot
18596            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18597            .find(|hunk| hunk.row_range.start.0 > position.row)
18598            .map(|hunk| hunk.row_range.start);
18599
18600        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18601        // Outside of the project diff editor, wrap around to the beginning.
18602        if !all_diff_hunks_expanded {
18603            row = row.or_else(|| {
18604                snapshot
18605                    .buffer_snapshot
18606                    .diff_hunks_in_range(Point::zero()..position)
18607                    .find(|hunk| hunk.row_range.end.0 < position.row)
18608                    .map(|hunk| hunk.row_range.start)
18609            });
18610        }
18611
18612        if let Some(row) = row {
18613            let destination = Point::new(row.0, 0);
18614            let autoscroll = Autoscroll::center();
18615
18616            self.unfold_ranges(&[destination..destination], false, false, cx);
18617            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18618                s.select_ranges([destination..destination]);
18619            });
18620        }
18621    }
18622
18623    fn do_stage_or_unstage(
18624        &self,
18625        stage: bool,
18626        buffer_id: BufferId,
18627        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18628        cx: &mut App,
18629    ) -> Option<()> {
18630        let project = self.project()?;
18631        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18632        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18633        let buffer_snapshot = buffer.read(cx).snapshot();
18634        let file_exists = buffer_snapshot
18635            .file()
18636            .is_some_and(|file| file.disk_state().exists());
18637        diff.update(cx, |diff, cx| {
18638            diff.stage_or_unstage_hunks(
18639                stage,
18640                &hunks
18641                    .map(|hunk| buffer_diff::DiffHunk {
18642                        buffer_range: hunk.buffer_range,
18643                        diff_base_byte_range: hunk.diff_base_byte_range,
18644                        secondary_status: hunk.secondary_status,
18645                        range: Point::zero()..Point::zero(), // unused
18646                    })
18647                    .collect::<Vec<_>>(),
18648                &buffer_snapshot,
18649                file_exists,
18650                cx,
18651            )
18652        });
18653        None
18654    }
18655
18656    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18657        let ranges: Vec<_> = self
18658            .selections
18659            .disjoint_anchors()
18660            .iter()
18661            .map(|s| s.range())
18662            .collect();
18663        self.buffer
18664            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18665    }
18666
18667    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18668        self.buffer.update(cx, |buffer, cx| {
18669            let ranges = vec![Anchor::min()..Anchor::max()];
18670            if !buffer.all_diff_hunks_expanded()
18671                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18672            {
18673                buffer.collapse_diff_hunks(ranges, cx);
18674                true
18675            } else {
18676                false
18677            }
18678        })
18679    }
18680
18681    fn toggle_diff_hunks_in_ranges(
18682        &mut self,
18683        ranges: Vec<Range<Anchor>>,
18684        cx: &mut Context<Editor>,
18685    ) {
18686        self.buffer.update(cx, |buffer, cx| {
18687            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18688            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18689        })
18690    }
18691
18692    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18693        self.buffer.update(cx, |buffer, cx| {
18694            let snapshot = buffer.snapshot(cx);
18695            let excerpt_id = range.end.excerpt_id;
18696            let point_range = range.to_point(&snapshot);
18697            let expand = !buffer.single_hunk_is_expanded(range, cx);
18698            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18699        })
18700    }
18701
18702    pub(crate) fn apply_all_diff_hunks(
18703        &mut self,
18704        _: &ApplyAllDiffHunks,
18705        window: &mut Window,
18706        cx: &mut Context<Self>,
18707    ) {
18708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18709
18710        let buffers = self.buffer.read(cx).all_buffers();
18711        for branch_buffer in buffers {
18712            branch_buffer.update(cx, |branch_buffer, cx| {
18713                branch_buffer.merge_into_base(Vec::new(), cx);
18714            });
18715        }
18716
18717        if let Some(project) = self.project.clone() {
18718            self.save(
18719                SaveOptions {
18720                    format: true,
18721                    autosave: false,
18722                },
18723                project,
18724                window,
18725                cx,
18726            )
18727            .detach_and_log_err(cx);
18728        }
18729    }
18730
18731    pub(crate) fn apply_selected_diff_hunks(
18732        &mut self,
18733        _: &ApplyDiffHunk,
18734        window: &mut Window,
18735        cx: &mut Context<Self>,
18736    ) {
18737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18738        let snapshot = self.snapshot(window, cx);
18739        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18740        let mut ranges_by_buffer = HashMap::default();
18741        self.transact(window, cx, |editor, _window, cx| {
18742            for hunk in hunks {
18743                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18744                    ranges_by_buffer
18745                        .entry(buffer.clone())
18746                        .or_insert_with(Vec::new)
18747                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18748                }
18749            }
18750
18751            for (buffer, ranges) in ranges_by_buffer {
18752                buffer.update(cx, |buffer, cx| {
18753                    buffer.merge_into_base(ranges, cx);
18754                });
18755            }
18756        });
18757
18758        if let Some(project) = self.project.clone() {
18759            self.save(
18760                SaveOptions {
18761                    format: true,
18762                    autosave: false,
18763                },
18764                project,
18765                window,
18766                cx,
18767            )
18768            .detach_and_log_err(cx);
18769        }
18770    }
18771
18772    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18773        if hovered != self.gutter_hovered {
18774            self.gutter_hovered = hovered;
18775            cx.notify();
18776        }
18777    }
18778
18779    pub fn insert_blocks(
18780        &mut self,
18781        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18782        autoscroll: Option<Autoscroll>,
18783        cx: &mut Context<Self>,
18784    ) -> Vec<CustomBlockId> {
18785        let blocks = self
18786            .display_map
18787            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18788        if let Some(autoscroll) = autoscroll {
18789            self.request_autoscroll(autoscroll, cx);
18790        }
18791        cx.notify();
18792        blocks
18793    }
18794
18795    pub fn resize_blocks(
18796        &mut self,
18797        heights: HashMap<CustomBlockId, u32>,
18798        autoscroll: Option<Autoscroll>,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.display_map
18802            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18803        if let Some(autoscroll) = autoscroll {
18804            self.request_autoscroll(autoscroll, cx);
18805        }
18806        cx.notify();
18807    }
18808
18809    pub fn replace_blocks(
18810        &mut self,
18811        renderers: HashMap<CustomBlockId, RenderBlock>,
18812        autoscroll: Option<Autoscroll>,
18813        cx: &mut Context<Self>,
18814    ) {
18815        self.display_map
18816            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18817        if let Some(autoscroll) = autoscroll {
18818            self.request_autoscroll(autoscroll, cx);
18819        }
18820        cx.notify();
18821    }
18822
18823    pub fn remove_blocks(
18824        &mut self,
18825        block_ids: HashSet<CustomBlockId>,
18826        autoscroll: Option<Autoscroll>,
18827        cx: &mut Context<Self>,
18828    ) {
18829        self.display_map.update(cx, |display_map, cx| {
18830            display_map.remove_blocks(block_ids, cx)
18831        });
18832        if let Some(autoscroll) = autoscroll {
18833            self.request_autoscroll(autoscroll, cx);
18834        }
18835        cx.notify();
18836    }
18837
18838    pub fn row_for_block(
18839        &self,
18840        block_id: CustomBlockId,
18841        cx: &mut Context<Self>,
18842    ) -> Option<DisplayRow> {
18843        self.display_map
18844            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18845    }
18846
18847    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18848        self.focused_block = Some(focused_block);
18849    }
18850
18851    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18852        self.focused_block.take()
18853    }
18854
18855    pub fn insert_creases(
18856        &mut self,
18857        creases: impl IntoIterator<Item = Crease<Anchor>>,
18858        cx: &mut Context<Self>,
18859    ) -> Vec<CreaseId> {
18860        self.display_map
18861            .update(cx, |map, cx| map.insert_creases(creases, cx))
18862    }
18863
18864    pub fn remove_creases(
18865        &mut self,
18866        ids: impl IntoIterator<Item = CreaseId>,
18867        cx: &mut Context<Self>,
18868    ) -> Vec<(CreaseId, Range<Anchor>)> {
18869        self.display_map
18870            .update(cx, |map, cx| map.remove_creases(ids, cx))
18871    }
18872
18873    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18874        self.display_map
18875            .update(cx, |map, cx| map.snapshot(cx))
18876            .longest_row()
18877    }
18878
18879    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18880        self.display_map
18881            .update(cx, |map, cx| map.snapshot(cx))
18882            .max_point()
18883    }
18884
18885    pub fn text(&self, cx: &App) -> String {
18886        self.buffer.read(cx).read(cx).text()
18887    }
18888
18889    pub fn is_empty(&self, cx: &App) -> bool {
18890        self.buffer.read(cx).read(cx).is_empty()
18891    }
18892
18893    pub fn text_option(&self, cx: &App) -> Option<String> {
18894        let text = self.text(cx);
18895        let text = text.trim();
18896
18897        if text.is_empty() {
18898            return None;
18899        }
18900
18901        Some(text.to_string())
18902    }
18903
18904    pub fn set_text(
18905        &mut self,
18906        text: impl Into<Arc<str>>,
18907        window: &mut Window,
18908        cx: &mut Context<Self>,
18909    ) {
18910        self.transact(window, cx, |this, _, cx| {
18911            this.buffer
18912                .read(cx)
18913                .as_singleton()
18914                .expect("you can only call set_text on editors for singleton buffers")
18915                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18916        });
18917    }
18918
18919    pub fn display_text(&self, cx: &mut App) -> String {
18920        self.display_map
18921            .update(cx, |map, cx| map.snapshot(cx))
18922            .text()
18923    }
18924
18925    fn create_minimap(
18926        &self,
18927        minimap_settings: MinimapSettings,
18928        window: &mut Window,
18929        cx: &mut Context<Self>,
18930    ) -> Option<Entity<Self>> {
18931        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18932            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18933    }
18934
18935    fn initialize_new_minimap(
18936        &self,
18937        minimap_settings: MinimapSettings,
18938        window: &mut Window,
18939        cx: &mut Context<Self>,
18940    ) -> Entity<Self> {
18941        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18942
18943        let mut minimap = Editor::new_internal(
18944            EditorMode::Minimap {
18945                parent: cx.weak_entity(),
18946            },
18947            self.buffer.clone(),
18948            None,
18949            Some(self.display_map.clone()),
18950            window,
18951            cx,
18952        );
18953        minimap.scroll_manager.clone_state(&self.scroll_manager);
18954        minimap.set_text_style_refinement(TextStyleRefinement {
18955            font_size: Some(MINIMAP_FONT_SIZE),
18956            font_weight: Some(MINIMAP_FONT_WEIGHT),
18957            ..Default::default()
18958        });
18959        minimap.update_minimap_configuration(minimap_settings, cx);
18960        cx.new(|_| minimap)
18961    }
18962
18963    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18964        let current_line_highlight = minimap_settings
18965            .current_line_highlight
18966            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18967        self.set_current_line_highlight(Some(current_line_highlight));
18968    }
18969
18970    pub fn minimap(&self) -> Option<&Entity<Self>> {
18971        self.minimap
18972            .as_ref()
18973            .filter(|_| self.minimap_visibility.visible())
18974    }
18975
18976    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18977        let mut wrap_guides = smallvec![];
18978
18979        if self.show_wrap_guides == Some(false) {
18980            return wrap_guides;
18981        }
18982
18983        let settings = self.buffer.read(cx).language_settings(cx);
18984        if settings.show_wrap_guides {
18985            match self.soft_wrap_mode(cx) {
18986                SoftWrap::Column(soft_wrap) => {
18987                    wrap_guides.push((soft_wrap as usize, true));
18988                }
18989                SoftWrap::Bounded(soft_wrap) => {
18990                    wrap_guides.push((soft_wrap as usize, true));
18991                }
18992                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18993            }
18994            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18995        }
18996
18997        wrap_guides
18998    }
18999
19000    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19001        let settings = self.buffer.read(cx).language_settings(cx);
19002        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19003        match mode {
19004            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19005                SoftWrap::None
19006            }
19007            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19008            language_settings::SoftWrap::PreferredLineLength => {
19009                SoftWrap::Column(settings.preferred_line_length)
19010            }
19011            language_settings::SoftWrap::Bounded => {
19012                SoftWrap::Bounded(settings.preferred_line_length)
19013            }
19014        }
19015    }
19016
19017    pub fn set_soft_wrap_mode(
19018        &mut self,
19019        mode: language_settings::SoftWrap,
19020
19021        cx: &mut Context<Self>,
19022    ) {
19023        self.soft_wrap_mode_override = Some(mode);
19024        cx.notify();
19025    }
19026
19027    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19028        self.hard_wrap = hard_wrap;
19029        cx.notify();
19030    }
19031
19032    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19033        self.text_style_refinement = Some(style);
19034    }
19035
19036    /// called by the Element so we know what style we were most recently rendered with.
19037    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19038        // We intentionally do not inform the display map about the minimap style
19039        // so that wrapping is not recalculated and stays consistent for the editor
19040        // and its linked minimap.
19041        if !self.mode.is_minimap() {
19042            let font = style.text.font();
19043            let font_size = style.text.font_size.to_pixels(window.rem_size());
19044            let display_map = self
19045                .placeholder_display_map
19046                .as_ref()
19047                .filter(|_| self.is_empty(cx))
19048                .unwrap_or(&self.display_map);
19049
19050            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19051        }
19052        self.style = Some(style);
19053    }
19054
19055    pub fn style(&self) -> Option<&EditorStyle> {
19056        self.style.as_ref()
19057    }
19058
19059    // Called by the element. This method is not designed to be called outside of the editor
19060    // element's layout code because it does not notify when rewrapping is computed synchronously.
19061    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19062        if self.is_empty(cx) {
19063            self.placeholder_display_map
19064                .as_ref()
19065                .map_or(false, |display_map| {
19066                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19067                })
19068        } else {
19069            self.display_map
19070                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19071        }
19072    }
19073
19074    pub fn set_soft_wrap(&mut self) {
19075        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19076    }
19077
19078    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19079        if self.soft_wrap_mode_override.is_some() {
19080            self.soft_wrap_mode_override.take();
19081        } else {
19082            let soft_wrap = match self.soft_wrap_mode(cx) {
19083                SoftWrap::GitDiff => return,
19084                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19085                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19086                    language_settings::SoftWrap::None
19087                }
19088            };
19089            self.soft_wrap_mode_override = Some(soft_wrap);
19090        }
19091        cx.notify();
19092    }
19093
19094    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19095        let Some(workspace) = self.workspace() else {
19096            return;
19097        };
19098        let fs = workspace.read(cx).app_state().fs.clone();
19099        let current_show = TabBarSettings::get_global(cx).show;
19100        update_settings_file(fs, cx, move |setting, _| {
19101            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19102        });
19103    }
19104
19105    pub fn toggle_indent_guides(
19106        &mut self,
19107        _: &ToggleIndentGuides,
19108        _: &mut Window,
19109        cx: &mut Context<Self>,
19110    ) {
19111        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19112            self.buffer
19113                .read(cx)
19114                .language_settings(cx)
19115                .indent_guides
19116                .enabled
19117        });
19118        self.show_indent_guides = Some(!currently_enabled);
19119        cx.notify();
19120    }
19121
19122    fn should_show_indent_guides(&self) -> Option<bool> {
19123        self.show_indent_guides
19124    }
19125
19126    pub fn toggle_line_numbers(
19127        &mut self,
19128        _: &ToggleLineNumbers,
19129        _: &mut Window,
19130        cx: &mut Context<Self>,
19131    ) {
19132        let mut editor_settings = EditorSettings::get_global(cx).clone();
19133        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19134        EditorSettings::override_global(editor_settings, cx);
19135    }
19136
19137    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19138        if let Some(show_line_numbers) = self.show_line_numbers {
19139            return show_line_numbers;
19140        }
19141        EditorSettings::get_global(cx).gutter.line_numbers
19142    }
19143
19144    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19145        self.use_relative_line_numbers
19146            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19147    }
19148
19149    pub fn toggle_relative_line_numbers(
19150        &mut self,
19151        _: &ToggleRelativeLineNumbers,
19152        _: &mut Window,
19153        cx: &mut Context<Self>,
19154    ) {
19155        let is_relative = self.should_use_relative_line_numbers(cx);
19156        self.set_relative_line_number(Some(!is_relative), cx)
19157    }
19158
19159    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19160        self.use_relative_line_numbers = is_relative;
19161        cx.notify();
19162    }
19163
19164    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19165        self.show_gutter = show_gutter;
19166        cx.notify();
19167    }
19168
19169    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19170        self.show_scrollbars = ScrollbarAxes {
19171            horizontal: show,
19172            vertical: show,
19173        };
19174        cx.notify();
19175    }
19176
19177    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19178        self.show_scrollbars.vertical = show;
19179        cx.notify();
19180    }
19181
19182    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19183        self.show_scrollbars.horizontal = show;
19184        cx.notify();
19185    }
19186
19187    pub fn set_minimap_visibility(
19188        &mut self,
19189        minimap_visibility: MinimapVisibility,
19190        window: &mut Window,
19191        cx: &mut Context<Self>,
19192    ) {
19193        if self.minimap_visibility != minimap_visibility {
19194            if minimap_visibility.visible() && self.minimap.is_none() {
19195                let minimap_settings = EditorSettings::get_global(cx).minimap;
19196                self.minimap =
19197                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19198            }
19199            self.minimap_visibility = minimap_visibility;
19200            cx.notify();
19201        }
19202    }
19203
19204    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19205        self.set_show_scrollbars(false, cx);
19206        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19207    }
19208
19209    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19210        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19211    }
19212
19213    /// Normally the text in full mode and auto height editors is padded on the
19214    /// left side by roughly half a character width for improved hit testing.
19215    ///
19216    /// Use this method to disable this for cases where this is not wanted (e.g.
19217    /// if you want to align the editor text with some other text above or below)
19218    /// or if you want to add this padding to single-line editors.
19219    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19220        self.offset_content = offset_content;
19221        cx.notify();
19222    }
19223
19224    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19225        self.show_line_numbers = Some(show_line_numbers);
19226        cx.notify();
19227    }
19228
19229    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19230        self.disable_expand_excerpt_buttons = true;
19231        cx.notify();
19232    }
19233
19234    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19235        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19236        cx.notify();
19237    }
19238
19239    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19240        self.show_code_actions = Some(show_code_actions);
19241        cx.notify();
19242    }
19243
19244    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19245        self.show_runnables = Some(show_runnables);
19246        cx.notify();
19247    }
19248
19249    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19250        self.show_breakpoints = Some(show_breakpoints);
19251        cx.notify();
19252    }
19253
19254    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19255        if self.display_map.read(cx).masked != masked {
19256            self.display_map.update(cx, |map, _| map.masked = masked);
19257        }
19258        cx.notify()
19259    }
19260
19261    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19262        self.show_wrap_guides = Some(show_wrap_guides);
19263        cx.notify();
19264    }
19265
19266    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19267        self.show_indent_guides = Some(show_indent_guides);
19268        cx.notify();
19269    }
19270
19271    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19272        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19273            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19274                && let Some(dir) = file.abs_path(cx).parent()
19275            {
19276                return Some(dir.to_owned());
19277            }
19278        }
19279
19280        None
19281    }
19282
19283    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19284        self.active_excerpt(cx)?
19285            .1
19286            .read(cx)
19287            .file()
19288            .and_then(|f| f.as_local())
19289    }
19290
19291    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19292        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19293            let buffer = buffer.read(cx);
19294            if let Some(project_path) = buffer.project_path(cx) {
19295                let project = self.project()?.read(cx);
19296                project.absolute_path(&project_path, cx)
19297            } else {
19298                buffer
19299                    .file()
19300                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19301            }
19302        })
19303    }
19304
19305    pub fn reveal_in_finder(
19306        &mut self,
19307        _: &RevealInFileManager,
19308        _window: &mut Window,
19309        cx: &mut Context<Self>,
19310    ) {
19311        if let Some(target) = self.target_file(cx) {
19312            cx.reveal_path(&target.abs_path(cx));
19313        }
19314    }
19315
19316    pub fn copy_path(
19317        &mut self,
19318        _: &zed_actions::workspace::CopyPath,
19319        _window: &mut Window,
19320        cx: &mut Context<Self>,
19321    ) {
19322        if let Some(path) = self.target_file_abs_path(cx)
19323            && let Some(path) = path.to_str()
19324        {
19325            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19326        } else {
19327            cx.propagate();
19328        }
19329    }
19330
19331    pub fn copy_relative_path(
19332        &mut self,
19333        _: &zed_actions::workspace::CopyRelativePath,
19334        _window: &mut Window,
19335        cx: &mut Context<Self>,
19336    ) {
19337        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19338            let project = self.project()?.read(cx);
19339            let path = buffer.read(cx).file()?.path();
19340            let path = path.display(project.path_style(cx));
19341            Some(path)
19342        }) {
19343            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19344        } else {
19345            cx.propagate();
19346        }
19347    }
19348
19349    /// Returns the project path for the editor's buffer, if any buffer is
19350    /// opened in the editor.
19351    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19352        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19353            buffer.read(cx).project_path(cx)
19354        } else {
19355            None
19356        }
19357    }
19358
19359    // Returns true if the editor handled a go-to-line request
19360    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19361        maybe!({
19362            let breakpoint_store = self.breakpoint_store.as_ref()?;
19363
19364            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19365            else {
19366                self.clear_row_highlights::<ActiveDebugLine>();
19367                return None;
19368            };
19369
19370            let position = active_stack_frame.position;
19371            let buffer_id = position.buffer_id?;
19372            let snapshot = self
19373                .project
19374                .as_ref()?
19375                .read(cx)
19376                .buffer_for_id(buffer_id, cx)?
19377                .read(cx)
19378                .snapshot();
19379
19380            let mut handled = false;
19381            for (id, ExcerptRange { context, .. }) in
19382                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19383            {
19384                if context.start.cmp(&position, &snapshot).is_ge()
19385                    || context.end.cmp(&position, &snapshot).is_lt()
19386                {
19387                    continue;
19388                }
19389                let snapshot = self.buffer.read(cx).snapshot(cx);
19390                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19391
19392                handled = true;
19393                self.clear_row_highlights::<ActiveDebugLine>();
19394
19395                self.go_to_line::<ActiveDebugLine>(
19396                    multibuffer_anchor,
19397                    Some(cx.theme().colors().editor_debugger_active_line_background),
19398                    window,
19399                    cx,
19400                );
19401
19402                cx.notify();
19403            }
19404
19405            handled.then_some(())
19406        })
19407        .is_some()
19408    }
19409
19410    pub fn copy_file_name_without_extension(
19411        &mut self,
19412        _: &CopyFileNameWithoutExtension,
19413        _: &mut Window,
19414        cx: &mut Context<Self>,
19415    ) {
19416        if let Some(file) = self.target_file(cx)
19417            && let Some(file_stem) = file.path().file_stem()
19418        {
19419            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19420        }
19421    }
19422
19423    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19424        if let Some(file) = self.target_file(cx)
19425            && let Some(name) = file.path().file_name()
19426        {
19427            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19428        }
19429    }
19430
19431    pub fn toggle_git_blame(
19432        &mut self,
19433        _: &::git::Blame,
19434        window: &mut Window,
19435        cx: &mut Context<Self>,
19436    ) {
19437        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19438
19439        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19440            self.start_git_blame(true, window, cx);
19441        }
19442
19443        cx.notify();
19444    }
19445
19446    pub fn toggle_git_blame_inline(
19447        &mut self,
19448        _: &ToggleGitBlameInline,
19449        window: &mut Window,
19450        cx: &mut Context<Self>,
19451    ) {
19452        self.toggle_git_blame_inline_internal(true, window, cx);
19453        cx.notify();
19454    }
19455
19456    pub fn open_git_blame_commit(
19457        &mut self,
19458        _: &OpenGitBlameCommit,
19459        window: &mut Window,
19460        cx: &mut Context<Self>,
19461    ) {
19462        self.open_git_blame_commit_internal(window, cx);
19463    }
19464
19465    fn open_git_blame_commit_internal(
19466        &mut self,
19467        window: &mut Window,
19468        cx: &mut Context<Self>,
19469    ) -> Option<()> {
19470        let blame = self.blame.as_ref()?;
19471        let snapshot = self.snapshot(window, cx);
19472        let cursor = self.selections.newest::<Point>(cx).head();
19473        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19474        let (_, blame_entry) = blame
19475            .update(cx, |blame, cx| {
19476                blame
19477                    .blame_for_rows(
19478                        &[RowInfo {
19479                            buffer_id: Some(buffer.remote_id()),
19480                            buffer_row: Some(point.row),
19481                            ..Default::default()
19482                        }],
19483                        cx,
19484                    )
19485                    .next()
19486            })
19487            .flatten()?;
19488        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19489        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19490        let workspace = self.workspace()?.downgrade();
19491        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19492        None
19493    }
19494
19495    pub fn git_blame_inline_enabled(&self) -> bool {
19496        self.git_blame_inline_enabled
19497    }
19498
19499    pub fn toggle_selection_menu(
19500        &mut self,
19501        _: &ToggleSelectionMenu,
19502        _: &mut Window,
19503        cx: &mut Context<Self>,
19504    ) {
19505        self.show_selection_menu = self
19506            .show_selection_menu
19507            .map(|show_selections_menu| !show_selections_menu)
19508            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19509
19510        cx.notify();
19511    }
19512
19513    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19514        self.show_selection_menu
19515            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19516    }
19517
19518    fn start_git_blame(
19519        &mut self,
19520        user_triggered: bool,
19521        window: &mut Window,
19522        cx: &mut Context<Self>,
19523    ) {
19524        if let Some(project) = self.project() {
19525            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19526                && buffer.read(cx).file().is_none()
19527            {
19528                return;
19529            }
19530
19531            let focused = self.focus_handle(cx).contains_focused(window, cx);
19532
19533            let project = project.clone();
19534            let blame = cx
19535                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19536            self.blame_subscription =
19537                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19538            self.blame = Some(blame);
19539        }
19540    }
19541
19542    fn toggle_git_blame_inline_internal(
19543        &mut self,
19544        user_triggered: bool,
19545        window: &mut Window,
19546        cx: &mut Context<Self>,
19547    ) {
19548        if self.git_blame_inline_enabled {
19549            self.git_blame_inline_enabled = false;
19550            self.show_git_blame_inline = false;
19551            self.show_git_blame_inline_delay_task.take();
19552        } else {
19553            self.git_blame_inline_enabled = true;
19554            self.start_git_blame_inline(user_triggered, window, cx);
19555        }
19556
19557        cx.notify();
19558    }
19559
19560    fn start_git_blame_inline(
19561        &mut self,
19562        user_triggered: bool,
19563        window: &mut Window,
19564        cx: &mut Context<Self>,
19565    ) {
19566        self.start_git_blame(user_triggered, window, cx);
19567
19568        if ProjectSettings::get_global(cx)
19569            .git
19570            .inline_blame_delay()
19571            .is_some()
19572        {
19573            self.start_inline_blame_timer(window, cx);
19574        } else {
19575            self.show_git_blame_inline = true
19576        }
19577    }
19578
19579    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19580        self.blame.as_ref()
19581    }
19582
19583    pub fn show_git_blame_gutter(&self) -> bool {
19584        self.show_git_blame_gutter
19585    }
19586
19587    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19588        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19589    }
19590
19591    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19592        self.show_git_blame_inline
19593            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19594            && !self.newest_selection_head_on_empty_line(cx)
19595            && self.has_blame_entries(cx)
19596    }
19597
19598    fn has_blame_entries(&self, cx: &App) -> bool {
19599        self.blame()
19600            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19601    }
19602
19603    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19604        let cursor_anchor = self.selections.newest_anchor().head();
19605
19606        let snapshot = self.buffer.read(cx).snapshot(cx);
19607        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19608
19609        snapshot.line_len(buffer_row) == 0
19610    }
19611
19612    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19613        let buffer_and_selection = maybe!({
19614            let selection = self.selections.newest::<Point>(cx);
19615            let selection_range = selection.range();
19616
19617            let multi_buffer = self.buffer().read(cx);
19618            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19619            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19620
19621            let (buffer, range, _) = if selection.reversed {
19622                buffer_ranges.first()
19623            } else {
19624                buffer_ranges.last()
19625            }?;
19626
19627            let selection = text::ToPoint::to_point(&range.start, buffer).row
19628                ..text::ToPoint::to_point(&range.end, buffer).row;
19629            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19630        });
19631
19632        let Some((buffer, selection)) = buffer_and_selection else {
19633            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19634        };
19635
19636        let Some(project) = self.project() else {
19637            return Task::ready(Err(anyhow!("editor does not have project")));
19638        };
19639
19640        project.update(cx, |project, cx| {
19641            project.get_permalink_to_line(&buffer, selection, cx)
19642        })
19643    }
19644
19645    pub fn copy_permalink_to_line(
19646        &mut self,
19647        _: &CopyPermalinkToLine,
19648        window: &mut Window,
19649        cx: &mut Context<Self>,
19650    ) {
19651        let permalink_task = self.get_permalink_to_line(cx);
19652        let workspace = self.workspace();
19653
19654        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19655            Ok(permalink) => {
19656                cx.update(|_, cx| {
19657                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19658                })
19659                .ok();
19660            }
19661            Err(err) => {
19662                let message = format!("Failed to copy permalink: {err}");
19663
19664                anyhow::Result::<()>::Err(err).log_err();
19665
19666                if let Some(workspace) = workspace {
19667                    workspace
19668                        .update_in(cx, |workspace, _, cx| {
19669                            struct CopyPermalinkToLine;
19670
19671                            workspace.show_toast(
19672                                Toast::new(
19673                                    NotificationId::unique::<CopyPermalinkToLine>(),
19674                                    message,
19675                                ),
19676                                cx,
19677                            )
19678                        })
19679                        .ok();
19680                }
19681            }
19682        })
19683        .detach();
19684    }
19685
19686    pub fn copy_file_location(
19687        &mut self,
19688        _: &CopyFileLocation,
19689        _: &mut Window,
19690        cx: &mut Context<Self>,
19691    ) {
19692        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19693        if let Some(file) = self.target_file(cx) {
19694            let path = file.path().display(file.path_style(cx));
19695            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19696        }
19697    }
19698
19699    pub fn open_permalink_to_line(
19700        &mut self,
19701        _: &OpenPermalinkToLine,
19702        window: &mut Window,
19703        cx: &mut Context<Self>,
19704    ) {
19705        let permalink_task = self.get_permalink_to_line(cx);
19706        let workspace = self.workspace();
19707
19708        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19709            Ok(permalink) => {
19710                cx.update(|_, cx| {
19711                    cx.open_url(permalink.as_ref());
19712                })
19713                .ok();
19714            }
19715            Err(err) => {
19716                let message = format!("Failed to open permalink: {err}");
19717
19718                anyhow::Result::<()>::Err(err).log_err();
19719
19720                if let Some(workspace) = workspace {
19721                    workspace
19722                        .update(cx, |workspace, cx| {
19723                            struct OpenPermalinkToLine;
19724
19725                            workspace.show_toast(
19726                                Toast::new(
19727                                    NotificationId::unique::<OpenPermalinkToLine>(),
19728                                    message,
19729                                ),
19730                                cx,
19731                            )
19732                        })
19733                        .ok();
19734                }
19735            }
19736        })
19737        .detach();
19738    }
19739
19740    pub fn insert_uuid_v4(
19741        &mut self,
19742        _: &InsertUuidV4,
19743        window: &mut Window,
19744        cx: &mut Context<Self>,
19745    ) {
19746        self.insert_uuid(UuidVersion::V4, window, cx);
19747    }
19748
19749    pub fn insert_uuid_v7(
19750        &mut self,
19751        _: &InsertUuidV7,
19752        window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        self.insert_uuid(UuidVersion::V7, window, cx);
19756    }
19757
19758    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19760        self.transact(window, cx, |this, window, cx| {
19761            let edits = this
19762                .selections
19763                .all::<Point>(cx)
19764                .into_iter()
19765                .map(|selection| {
19766                    let uuid = match version {
19767                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19768                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19769                    };
19770
19771                    (selection.range(), uuid.to_string())
19772                });
19773            this.edit(edits, cx);
19774            this.refresh_edit_prediction(true, false, window, cx);
19775        });
19776    }
19777
19778    pub fn open_selections_in_multibuffer(
19779        &mut self,
19780        _: &OpenSelectionsInMultibuffer,
19781        window: &mut Window,
19782        cx: &mut Context<Self>,
19783    ) {
19784        let multibuffer = self.buffer.read(cx);
19785
19786        let Some(buffer) = multibuffer.as_singleton() else {
19787            return;
19788        };
19789
19790        let Some(workspace) = self.workspace() else {
19791            return;
19792        };
19793
19794        let title = multibuffer.title(cx).to_string();
19795
19796        let locations = self
19797            .selections
19798            .all_anchors(cx)
19799            .iter()
19800            .map(|selection| {
19801                (
19802                    buffer.clone(),
19803                    (selection.start.text_anchor..selection.end.text_anchor)
19804                        .to_point(buffer.read(cx)),
19805                )
19806            })
19807            .into_group_map();
19808
19809        cx.spawn_in(window, async move |_, cx| {
19810            workspace.update_in(cx, |workspace, window, cx| {
19811                Self::open_locations_in_multibuffer(
19812                    workspace,
19813                    locations,
19814                    format!("Selections for '{title}'"),
19815                    false,
19816                    MultibufferSelectionMode::All,
19817                    window,
19818                    cx,
19819                );
19820            })
19821        })
19822        .detach();
19823    }
19824
19825    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19826    /// last highlight added will be used.
19827    ///
19828    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19829    pub fn highlight_rows<T: 'static>(
19830        &mut self,
19831        range: Range<Anchor>,
19832        color: Hsla,
19833        options: RowHighlightOptions,
19834        cx: &mut Context<Self>,
19835    ) {
19836        let snapshot = self.buffer().read(cx).snapshot(cx);
19837        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19838        let ix = row_highlights.binary_search_by(|highlight| {
19839            Ordering::Equal
19840                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19841                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19842        });
19843
19844        if let Err(mut ix) = ix {
19845            let index = post_inc(&mut self.highlight_order);
19846
19847            // If this range intersects with the preceding highlight, then merge it with
19848            // the preceding highlight. Otherwise insert a new highlight.
19849            let mut merged = false;
19850            if ix > 0 {
19851                let prev_highlight = &mut row_highlights[ix - 1];
19852                if prev_highlight
19853                    .range
19854                    .end
19855                    .cmp(&range.start, &snapshot)
19856                    .is_ge()
19857                {
19858                    ix -= 1;
19859                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19860                        prev_highlight.range.end = range.end;
19861                    }
19862                    merged = true;
19863                    prev_highlight.index = index;
19864                    prev_highlight.color = color;
19865                    prev_highlight.options = options;
19866                }
19867            }
19868
19869            if !merged {
19870                row_highlights.insert(
19871                    ix,
19872                    RowHighlight {
19873                        range,
19874                        index,
19875                        color,
19876                        options,
19877                        type_id: TypeId::of::<T>(),
19878                    },
19879                );
19880            }
19881
19882            // If any of the following highlights intersect with this one, merge them.
19883            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19884                let highlight = &row_highlights[ix];
19885                if next_highlight
19886                    .range
19887                    .start
19888                    .cmp(&highlight.range.end, &snapshot)
19889                    .is_le()
19890                {
19891                    if next_highlight
19892                        .range
19893                        .end
19894                        .cmp(&highlight.range.end, &snapshot)
19895                        .is_gt()
19896                    {
19897                        row_highlights[ix].range.end = next_highlight.range.end;
19898                    }
19899                    row_highlights.remove(ix + 1);
19900                } else {
19901                    break;
19902                }
19903            }
19904        }
19905    }
19906
19907    /// Remove any highlighted row ranges of the given type that intersect the
19908    /// given ranges.
19909    pub fn remove_highlighted_rows<T: 'static>(
19910        &mut self,
19911        ranges_to_remove: Vec<Range<Anchor>>,
19912        cx: &mut Context<Self>,
19913    ) {
19914        let snapshot = self.buffer().read(cx).snapshot(cx);
19915        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19916        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19917        row_highlights.retain(|highlight| {
19918            while let Some(range_to_remove) = ranges_to_remove.peek() {
19919                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19920                    Ordering::Less | Ordering::Equal => {
19921                        ranges_to_remove.next();
19922                    }
19923                    Ordering::Greater => {
19924                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19925                            Ordering::Less | Ordering::Equal => {
19926                                return false;
19927                            }
19928                            Ordering::Greater => break,
19929                        }
19930                    }
19931                }
19932            }
19933
19934            true
19935        })
19936    }
19937
19938    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19939    pub fn clear_row_highlights<T: 'static>(&mut self) {
19940        self.highlighted_rows.remove(&TypeId::of::<T>());
19941    }
19942
19943    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19944    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19945        self.highlighted_rows
19946            .get(&TypeId::of::<T>())
19947            .map_or(&[] as &[_], |vec| vec.as_slice())
19948            .iter()
19949            .map(|highlight| (highlight.range.clone(), highlight.color))
19950    }
19951
19952    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19953    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19954    /// Allows to ignore certain kinds of highlights.
19955    pub fn highlighted_display_rows(
19956        &self,
19957        window: &mut Window,
19958        cx: &mut App,
19959    ) -> BTreeMap<DisplayRow, LineHighlight> {
19960        let snapshot = self.snapshot(window, cx);
19961        let mut used_highlight_orders = HashMap::default();
19962        self.highlighted_rows
19963            .iter()
19964            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19965            .fold(
19966                BTreeMap::<DisplayRow, LineHighlight>::new(),
19967                |mut unique_rows, highlight| {
19968                    let start = highlight.range.start.to_display_point(&snapshot);
19969                    let end = highlight.range.end.to_display_point(&snapshot);
19970                    let start_row = start.row().0;
19971                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19972                        && end.column() == 0
19973                    {
19974                        end.row().0.saturating_sub(1)
19975                    } else {
19976                        end.row().0
19977                    };
19978                    for row in start_row..=end_row {
19979                        let used_index =
19980                            used_highlight_orders.entry(row).or_insert(highlight.index);
19981                        if highlight.index >= *used_index {
19982                            *used_index = highlight.index;
19983                            unique_rows.insert(
19984                                DisplayRow(row),
19985                                LineHighlight {
19986                                    include_gutter: highlight.options.include_gutter,
19987                                    border: None,
19988                                    background: highlight.color.into(),
19989                                    type_id: Some(highlight.type_id),
19990                                },
19991                            );
19992                        }
19993                    }
19994                    unique_rows
19995                },
19996            )
19997    }
19998
19999    pub fn highlighted_display_row_for_autoscroll(
20000        &self,
20001        snapshot: &DisplaySnapshot,
20002    ) -> Option<DisplayRow> {
20003        self.highlighted_rows
20004            .values()
20005            .flat_map(|highlighted_rows| highlighted_rows.iter())
20006            .filter_map(|highlight| {
20007                if highlight.options.autoscroll {
20008                    Some(highlight.range.start.to_display_point(snapshot).row())
20009                } else {
20010                    None
20011                }
20012            })
20013            .min()
20014    }
20015
20016    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20017        self.highlight_background::<SearchWithinRange>(
20018            ranges,
20019            |colors| colors.colors().editor_document_highlight_read_background,
20020            cx,
20021        )
20022    }
20023
20024    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20025        self.breadcrumb_header = Some(new_header);
20026    }
20027
20028    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20029        self.clear_background_highlights::<SearchWithinRange>(cx);
20030    }
20031
20032    pub fn highlight_background<T: 'static>(
20033        &mut self,
20034        ranges: &[Range<Anchor>],
20035        color_fetcher: fn(&Theme) -> Hsla,
20036        cx: &mut Context<Self>,
20037    ) {
20038        self.background_highlights.insert(
20039            HighlightKey::Type(TypeId::of::<T>()),
20040            (color_fetcher, Arc::from(ranges)),
20041        );
20042        self.scrollbar_marker_state.dirty = true;
20043        cx.notify();
20044    }
20045
20046    pub fn highlight_background_key<T: 'static>(
20047        &mut self,
20048        key: usize,
20049        ranges: &[Range<Anchor>],
20050        color_fetcher: fn(&Theme) -> Hsla,
20051        cx: &mut Context<Self>,
20052    ) {
20053        self.background_highlights.insert(
20054            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20055            (color_fetcher, Arc::from(ranges)),
20056        );
20057        self.scrollbar_marker_state.dirty = true;
20058        cx.notify();
20059    }
20060
20061    pub fn clear_background_highlights<T: 'static>(
20062        &mut self,
20063        cx: &mut Context<Self>,
20064    ) -> Option<BackgroundHighlight> {
20065        let text_highlights = self
20066            .background_highlights
20067            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20068        if !text_highlights.1.is_empty() {
20069            self.scrollbar_marker_state.dirty = true;
20070            cx.notify();
20071        }
20072        Some(text_highlights)
20073    }
20074
20075    pub fn highlight_gutter<T: 'static>(
20076        &mut self,
20077        ranges: impl Into<Vec<Range<Anchor>>>,
20078        color_fetcher: fn(&App) -> Hsla,
20079        cx: &mut Context<Self>,
20080    ) {
20081        self.gutter_highlights
20082            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20083        cx.notify();
20084    }
20085
20086    pub fn clear_gutter_highlights<T: 'static>(
20087        &mut self,
20088        cx: &mut Context<Self>,
20089    ) -> Option<GutterHighlight> {
20090        cx.notify();
20091        self.gutter_highlights.remove(&TypeId::of::<T>())
20092    }
20093
20094    pub fn insert_gutter_highlight<T: 'static>(
20095        &mut self,
20096        range: Range<Anchor>,
20097        color_fetcher: fn(&App) -> Hsla,
20098        cx: &mut Context<Self>,
20099    ) {
20100        let snapshot = self.buffer().read(cx).snapshot(cx);
20101        let mut highlights = self
20102            .gutter_highlights
20103            .remove(&TypeId::of::<T>())
20104            .map(|(_, highlights)| highlights)
20105            .unwrap_or_default();
20106        let ix = highlights.binary_search_by(|highlight| {
20107            Ordering::Equal
20108                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20109                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20110        });
20111        if let Err(ix) = ix {
20112            highlights.insert(ix, range);
20113        }
20114        self.gutter_highlights
20115            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20116    }
20117
20118    pub fn remove_gutter_highlights<T: 'static>(
20119        &mut self,
20120        ranges_to_remove: Vec<Range<Anchor>>,
20121        cx: &mut Context<Self>,
20122    ) {
20123        let snapshot = self.buffer().read(cx).snapshot(cx);
20124        let Some((color_fetcher, mut gutter_highlights)) =
20125            self.gutter_highlights.remove(&TypeId::of::<T>())
20126        else {
20127            return;
20128        };
20129        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20130        gutter_highlights.retain(|highlight| {
20131            while let Some(range_to_remove) = ranges_to_remove.peek() {
20132                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20133                    Ordering::Less | Ordering::Equal => {
20134                        ranges_to_remove.next();
20135                    }
20136                    Ordering::Greater => {
20137                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20138                            Ordering::Less | Ordering::Equal => {
20139                                return false;
20140                            }
20141                            Ordering::Greater => break,
20142                        }
20143                    }
20144                }
20145            }
20146
20147            true
20148        });
20149        self.gutter_highlights
20150            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20151    }
20152
20153    #[cfg(feature = "test-support")]
20154    pub fn all_text_highlights(
20155        &self,
20156        window: &mut Window,
20157        cx: &mut Context<Self>,
20158    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20159        let snapshot = self.snapshot(window, cx);
20160        self.display_map.update(cx, |display_map, _| {
20161            display_map
20162                .all_text_highlights()
20163                .map(|highlight| {
20164                    let (style, ranges) = highlight.as_ref();
20165                    (
20166                        *style,
20167                        ranges
20168                            .iter()
20169                            .map(|range| range.clone().to_display_points(&snapshot))
20170                            .collect(),
20171                    )
20172                })
20173                .collect()
20174        })
20175    }
20176
20177    #[cfg(feature = "test-support")]
20178    pub fn all_text_background_highlights(
20179        &self,
20180        window: &mut Window,
20181        cx: &mut Context<Self>,
20182    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20183        let snapshot = self.snapshot(window, cx);
20184        let buffer = &snapshot.buffer_snapshot;
20185        let start = buffer.anchor_before(0);
20186        let end = buffer.anchor_after(buffer.len());
20187        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20188    }
20189
20190    #[cfg(any(test, feature = "test-support"))]
20191    pub fn sorted_background_highlights_in_range(
20192        &self,
20193        search_range: Range<Anchor>,
20194        display_snapshot: &DisplaySnapshot,
20195        theme: &Theme,
20196    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20197        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20198        res.sort_by(|a, b| {
20199            a.0.start
20200                .cmp(&b.0.start)
20201                .then_with(|| a.0.end.cmp(&b.0.end))
20202                .then_with(|| a.1.cmp(&b.1))
20203        });
20204        res
20205    }
20206
20207    #[cfg(feature = "test-support")]
20208    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20209        let snapshot = self.buffer().read(cx).snapshot(cx);
20210
20211        let highlights = self
20212            .background_highlights
20213            .get(&HighlightKey::Type(TypeId::of::<
20214                items::BufferSearchHighlights,
20215            >()));
20216
20217        if let Some((_color, ranges)) = highlights {
20218            ranges
20219                .iter()
20220                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20221                .collect_vec()
20222        } else {
20223            vec![]
20224        }
20225    }
20226
20227    fn document_highlights_for_position<'a>(
20228        &'a self,
20229        position: Anchor,
20230        buffer: &'a MultiBufferSnapshot,
20231    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20232        let read_highlights = self
20233            .background_highlights
20234            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20235            .map(|h| &h.1);
20236        let write_highlights = self
20237            .background_highlights
20238            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20239            .map(|h| &h.1);
20240        let left_position = position.bias_left(buffer);
20241        let right_position = position.bias_right(buffer);
20242        read_highlights
20243            .into_iter()
20244            .chain(write_highlights)
20245            .flat_map(move |ranges| {
20246                let start_ix = match ranges.binary_search_by(|probe| {
20247                    let cmp = probe.end.cmp(&left_position, buffer);
20248                    if cmp.is_ge() {
20249                        Ordering::Greater
20250                    } else {
20251                        Ordering::Less
20252                    }
20253                }) {
20254                    Ok(i) | Err(i) => i,
20255                };
20256
20257                ranges[start_ix..]
20258                    .iter()
20259                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20260            })
20261    }
20262
20263    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20264        self.background_highlights
20265            .get(&HighlightKey::Type(TypeId::of::<T>()))
20266            .is_some_and(|(_, highlights)| !highlights.is_empty())
20267    }
20268
20269    /// Returns all background highlights for a given range.
20270    ///
20271    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20272    pub fn background_highlights_in_range(
20273        &self,
20274        search_range: Range<Anchor>,
20275        display_snapshot: &DisplaySnapshot,
20276        theme: &Theme,
20277    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20278        let mut results = Vec::new();
20279        for (color_fetcher, ranges) in self.background_highlights.values() {
20280            let color = color_fetcher(theme);
20281            let start_ix = match ranges.binary_search_by(|probe| {
20282                let cmp = probe
20283                    .end
20284                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20285                if cmp.is_gt() {
20286                    Ordering::Greater
20287                } else {
20288                    Ordering::Less
20289                }
20290            }) {
20291                Ok(i) | Err(i) => i,
20292            };
20293            for range in &ranges[start_ix..] {
20294                if range
20295                    .start
20296                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20297                    .is_ge()
20298                {
20299                    break;
20300                }
20301
20302                let start = range.start.to_display_point(display_snapshot);
20303                let end = range.end.to_display_point(display_snapshot);
20304                results.push((start..end, color))
20305            }
20306        }
20307        results
20308    }
20309
20310    pub fn gutter_highlights_in_range(
20311        &self,
20312        search_range: Range<Anchor>,
20313        display_snapshot: &DisplaySnapshot,
20314        cx: &App,
20315    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20316        let mut results = Vec::new();
20317        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20318            let color = color_fetcher(cx);
20319            let start_ix = match ranges.binary_search_by(|probe| {
20320                let cmp = probe
20321                    .end
20322                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20323                if cmp.is_gt() {
20324                    Ordering::Greater
20325                } else {
20326                    Ordering::Less
20327                }
20328            }) {
20329                Ok(i) | Err(i) => i,
20330            };
20331            for range in &ranges[start_ix..] {
20332                if range
20333                    .start
20334                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20335                    .is_ge()
20336                {
20337                    break;
20338                }
20339
20340                let start = range.start.to_display_point(display_snapshot);
20341                let end = range.end.to_display_point(display_snapshot);
20342                results.push((start..end, color))
20343            }
20344        }
20345        results
20346    }
20347
20348    /// Get the text ranges corresponding to the redaction query
20349    pub fn redacted_ranges(
20350        &self,
20351        search_range: Range<Anchor>,
20352        display_snapshot: &DisplaySnapshot,
20353        cx: &App,
20354    ) -> Vec<Range<DisplayPoint>> {
20355        display_snapshot
20356            .buffer_snapshot
20357            .redacted_ranges(search_range, |file| {
20358                if let Some(file) = file {
20359                    file.is_private()
20360                        && EditorSettings::get(
20361                            Some(SettingsLocation {
20362                                worktree_id: file.worktree_id(cx),
20363                                path: file.path().as_ref(),
20364                            }),
20365                            cx,
20366                        )
20367                        .redact_private_values
20368                } else {
20369                    false
20370                }
20371            })
20372            .map(|range| {
20373                range.start.to_display_point(display_snapshot)
20374                    ..range.end.to_display_point(display_snapshot)
20375            })
20376            .collect()
20377    }
20378
20379    pub fn highlight_text_key<T: 'static>(
20380        &mut self,
20381        key: usize,
20382        ranges: Vec<Range<Anchor>>,
20383        style: HighlightStyle,
20384        cx: &mut Context<Self>,
20385    ) {
20386        self.display_map.update(cx, |map, _| {
20387            map.highlight_text(
20388                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20389                ranges,
20390                style,
20391            );
20392        });
20393        cx.notify();
20394    }
20395
20396    pub fn highlight_text<T: 'static>(
20397        &mut self,
20398        ranges: Vec<Range<Anchor>>,
20399        style: HighlightStyle,
20400        cx: &mut Context<Self>,
20401    ) {
20402        self.display_map.update(cx, |map, _| {
20403            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20404        });
20405        cx.notify();
20406    }
20407
20408    pub(crate) fn highlight_inlays<T: 'static>(
20409        &mut self,
20410        highlights: Vec<InlayHighlight>,
20411        style: HighlightStyle,
20412        cx: &mut Context<Self>,
20413    ) {
20414        self.display_map.update(cx, |map, _| {
20415            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20416        });
20417        cx.notify();
20418    }
20419
20420    pub fn text_highlights<'a, T: 'static>(
20421        &'a self,
20422        cx: &'a App,
20423    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20424        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20425    }
20426
20427    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20428        let cleared = self
20429            .display_map
20430            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20431        if cleared {
20432            cx.notify();
20433        }
20434    }
20435
20436    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20437        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20438            && self.focus_handle.is_focused(window)
20439    }
20440
20441    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20442        self.show_cursor_when_unfocused = is_enabled;
20443        cx.notify();
20444    }
20445
20446    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20447        cx.notify();
20448    }
20449
20450    fn on_debug_session_event(
20451        &mut self,
20452        _session: Entity<Session>,
20453        event: &SessionEvent,
20454        cx: &mut Context<Self>,
20455    ) {
20456        if let SessionEvent::InvalidateInlineValue = event {
20457            self.refresh_inline_values(cx);
20458        }
20459    }
20460
20461    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20462        let Some(project) = self.project.clone() else {
20463            return;
20464        };
20465
20466        if !self.inline_value_cache.enabled {
20467            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20468            self.splice_inlays(&inlays, Vec::new(), cx);
20469            return;
20470        }
20471
20472        let current_execution_position = self
20473            .highlighted_rows
20474            .get(&TypeId::of::<ActiveDebugLine>())
20475            .and_then(|lines| lines.last().map(|line| line.range.end));
20476
20477        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20478            let inline_values = editor
20479                .update(cx, |editor, cx| {
20480                    let Some(current_execution_position) = current_execution_position else {
20481                        return Some(Task::ready(Ok(Vec::new())));
20482                    };
20483
20484                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20485                        let snapshot = buffer.snapshot(cx);
20486
20487                        let excerpt = snapshot.excerpt_containing(
20488                            current_execution_position..current_execution_position,
20489                        )?;
20490
20491                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20492                    })?;
20493
20494                    let range =
20495                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20496
20497                    project.inline_values(buffer, range, cx)
20498                })
20499                .ok()
20500                .flatten()?
20501                .await
20502                .context("refreshing debugger inlays")
20503                .log_err()?;
20504
20505            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20506
20507            for (buffer_id, inline_value) in inline_values
20508                .into_iter()
20509                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20510            {
20511                buffer_inline_values
20512                    .entry(buffer_id)
20513                    .or_default()
20514                    .push(inline_value);
20515            }
20516
20517            editor
20518                .update(cx, |editor, cx| {
20519                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20520                    let mut new_inlays = Vec::default();
20521
20522                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20523                        let buffer_id = buffer_snapshot.remote_id();
20524                        buffer_inline_values
20525                            .get(&buffer_id)
20526                            .into_iter()
20527                            .flatten()
20528                            .for_each(|hint| {
20529                                let inlay = Inlay::debugger(
20530                                    post_inc(&mut editor.next_inlay_id),
20531                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20532                                    hint.text(),
20533                                );
20534                                if !inlay.text().chars().contains(&'\n') {
20535                                    new_inlays.push(inlay);
20536                                }
20537                            });
20538                    }
20539
20540                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20541                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20542
20543                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20544                })
20545                .ok()?;
20546            Some(())
20547        });
20548    }
20549
20550    fn on_buffer_event(
20551        &mut self,
20552        multibuffer: &Entity<MultiBuffer>,
20553        event: &multi_buffer::Event,
20554        window: &mut Window,
20555        cx: &mut Context<Self>,
20556    ) {
20557        match event {
20558            multi_buffer::Event::Edited {
20559                singleton_buffer_edited,
20560                edited_buffer,
20561            } => {
20562                self.scrollbar_marker_state.dirty = true;
20563                self.active_indent_guides_state.dirty = true;
20564                self.refresh_active_diagnostics(cx);
20565                self.refresh_code_actions(window, cx);
20566                self.refresh_selected_text_highlights(true, window, cx);
20567                self.refresh_single_line_folds(window, cx);
20568                refresh_matching_bracket_highlights(self, window, cx);
20569                if self.has_active_edit_prediction() {
20570                    self.update_visible_edit_prediction(window, cx);
20571                }
20572                if let Some(project) = self.project.as_ref()
20573                    && let Some(edited_buffer) = edited_buffer
20574                {
20575                    project.update(cx, |project, cx| {
20576                        self.registered_buffers
20577                            .entry(edited_buffer.read(cx).remote_id())
20578                            .or_insert_with(|| {
20579                                project.register_buffer_with_language_servers(edited_buffer, cx)
20580                            });
20581                    });
20582                }
20583                cx.emit(EditorEvent::BufferEdited);
20584                cx.emit(SearchEvent::MatchesInvalidated);
20585
20586                if let Some(buffer) = edited_buffer {
20587                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20588                }
20589
20590                if *singleton_buffer_edited {
20591                    if let Some(buffer) = edited_buffer
20592                        && buffer.read(cx).file().is_none()
20593                    {
20594                        cx.emit(EditorEvent::TitleChanged);
20595                    }
20596                    if let Some(project) = &self.project {
20597                        #[allow(clippy::mutable_key_type)]
20598                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20599                            multibuffer
20600                                .all_buffers()
20601                                .into_iter()
20602                                .filter_map(|buffer| {
20603                                    buffer.update(cx, |buffer, cx| {
20604                                        let language = buffer.language()?;
20605                                        let should_discard = project.update(cx, |project, cx| {
20606                                            project.is_local()
20607                                                && !project.has_language_servers_for(buffer, cx)
20608                                        });
20609                                        should_discard.not().then_some(language.clone())
20610                                    })
20611                                })
20612                                .collect::<HashSet<_>>()
20613                        });
20614                        if !languages_affected.is_empty() {
20615                            self.refresh_inlay_hints(
20616                                InlayHintRefreshReason::BufferEdited(languages_affected),
20617                                cx,
20618                            );
20619                        }
20620                    }
20621                }
20622
20623                let Some(project) = &self.project else { return };
20624                let (telemetry, is_via_ssh) = {
20625                    let project = project.read(cx);
20626                    let telemetry = project.client().telemetry().clone();
20627                    let is_via_ssh = project.is_via_remote_server();
20628                    (telemetry, is_via_ssh)
20629                };
20630                refresh_linked_ranges(self, window, cx);
20631                telemetry.log_edit_event("editor", is_via_ssh);
20632            }
20633            multi_buffer::Event::ExcerptsAdded {
20634                buffer,
20635                predecessor,
20636                excerpts,
20637            } => {
20638                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20639                let buffer_id = buffer.read(cx).remote_id();
20640                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20641                    && let Some(project) = &self.project
20642                {
20643                    update_uncommitted_diff_for_buffer(
20644                        cx.entity(),
20645                        project,
20646                        [buffer.clone()],
20647                        self.buffer.clone(),
20648                        cx,
20649                    )
20650                    .detach();
20651                }
20652                if self.active_diagnostics != ActiveDiagnostic::All {
20653                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20654                }
20655                cx.emit(EditorEvent::ExcerptsAdded {
20656                    buffer: buffer.clone(),
20657                    predecessor: *predecessor,
20658                    excerpts: excerpts.clone(),
20659                });
20660                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20661            }
20662            multi_buffer::Event::ExcerptsRemoved {
20663                ids,
20664                removed_buffer_ids,
20665            } => {
20666                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20667                let buffer = self.buffer.read(cx);
20668                self.registered_buffers
20669                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20670                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20671                cx.emit(EditorEvent::ExcerptsRemoved {
20672                    ids: ids.clone(),
20673                    removed_buffer_ids: removed_buffer_ids.clone(),
20674                });
20675            }
20676            multi_buffer::Event::ExcerptsEdited {
20677                excerpt_ids,
20678                buffer_ids,
20679            } => {
20680                self.display_map.update(cx, |map, cx| {
20681                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20682                });
20683                cx.emit(EditorEvent::ExcerptsEdited {
20684                    ids: excerpt_ids.clone(),
20685                });
20686            }
20687            multi_buffer::Event::ExcerptsExpanded { ids } => {
20688                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20689                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20690            }
20691            multi_buffer::Event::Reparsed(buffer_id) => {
20692                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20693                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20694
20695                cx.emit(EditorEvent::Reparsed(*buffer_id));
20696            }
20697            multi_buffer::Event::DiffHunksToggled => {
20698                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20699            }
20700            multi_buffer::Event::LanguageChanged(buffer_id) => {
20701                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20702                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20703                cx.emit(EditorEvent::Reparsed(*buffer_id));
20704                cx.notify();
20705            }
20706            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20707            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20708            multi_buffer::Event::FileHandleChanged
20709            | multi_buffer::Event::Reloaded
20710            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20711            multi_buffer::Event::DiagnosticsUpdated => {
20712                self.update_diagnostics_state(window, cx);
20713            }
20714            _ => {}
20715        };
20716    }
20717
20718    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20719        if !self.diagnostics_enabled() {
20720            return;
20721        }
20722        self.refresh_active_diagnostics(cx);
20723        self.refresh_inline_diagnostics(true, window, cx);
20724        self.scrollbar_marker_state.dirty = true;
20725        cx.notify();
20726    }
20727
20728    pub fn start_temporary_diff_override(&mut self) {
20729        self.load_diff_task.take();
20730        self.temporary_diff_override = true;
20731    }
20732
20733    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20734        self.temporary_diff_override = false;
20735        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20736        self.buffer.update(cx, |buffer, cx| {
20737            buffer.set_all_diff_hunks_collapsed(cx);
20738        });
20739
20740        if let Some(project) = self.project.clone() {
20741            self.load_diff_task = Some(
20742                update_uncommitted_diff_for_buffer(
20743                    cx.entity(),
20744                    &project,
20745                    self.buffer.read(cx).all_buffers(),
20746                    self.buffer.clone(),
20747                    cx,
20748                )
20749                .shared(),
20750            );
20751        }
20752    }
20753
20754    fn on_display_map_changed(
20755        &mut self,
20756        _: Entity<DisplayMap>,
20757        _: &mut Window,
20758        cx: &mut Context<Self>,
20759    ) {
20760        cx.notify();
20761    }
20762
20763    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20764        if self.diagnostics_enabled() {
20765            let new_severity = EditorSettings::get_global(cx)
20766                .diagnostics_max_severity
20767                .unwrap_or(DiagnosticSeverity::Hint);
20768            self.set_max_diagnostics_severity(new_severity, cx);
20769        }
20770        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20771        self.update_edit_prediction_settings(cx);
20772        self.refresh_edit_prediction(true, false, window, cx);
20773        self.refresh_inline_values(cx);
20774        self.refresh_inlay_hints(
20775            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20776                self.selections.newest_anchor().head(),
20777                &self.buffer.read(cx).snapshot(cx),
20778                cx,
20779            )),
20780            cx,
20781        );
20782
20783        let old_cursor_shape = self.cursor_shape;
20784        let old_show_breadcrumbs = self.show_breadcrumbs;
20785
20786        {
20787            let editor_settings = EditorSettings::get_global(cx);
20788            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20789            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20790            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20791            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20792        }
20793
20794        if old_cursor_shape != self.cursor_shape {
20795            cx.emit(EditorEvent::CursorShapeChanged);
20796        }
20797
20798        if old_show_breadcrumbs != self.show_breadcrumbs {
20799            cx.emit(EditorEvent::BreadcrumbsChanged);
20800        }
20801
20802        let project_settings = ProjectSettings::get_global(cx);
20803        self.serialize_dirty_buffers =
20804            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20805
20806        if self.mode.is_full() {
20807            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20808            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20809            if self.show_inline_diagnostics != show_inline_diagnostics {
20810                self.show_inline_diagnostics = show_inline_diagnostics;
20811                self.refresh_inline_diagnostics(false, window, cx);
20812            }
20813
20814            if self.git_blame_inline_enabled != inline_blame_enabled {
20815                self.toggle_git_blame_inline_internal(false, window, cx);
20816            }
20817
20818            let minimap_settings = EditorSettings::get_global(cx).minimap;
20819            if self.minimap_visibility != MinimapVisibility::Disabled {
20820                if self.minimap_visibility.settings_visibility()
20821                    != minimap_settings.minimap_enabled()
20822                {
20823                    self.set_minimap_visibility(
20824                        MinimapVisibility::for_mode(self.mode(), cx),
20825                        window,
20826                        cx,
20827                    );
20828                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20829                    minimap_entity.update(cx, |minimap_editor, cx| {
20830                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20831                    })
20832                }
20833            }
20834        }
20835
20836        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20837            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20838        }) {
20839            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20840                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20841            }
20842            self.refresh_colors(false, None, window, cx);
20843        }
20844
20845        cx.notify();
20846    }
20847
20848    pub fn set_searchable(&mut self, searchable: bool) {
20849        self.searchable = searchable;
20850    }
20851
20852    pub fn searchable(&self) -> bool {
20853        self.searchable
20854    }
20855
20856    fn open_proposed_changes_editor(
20857        &mut self,
20858        _: &OpenProposedChangesEditor,
20859        window: &mut Window,
20860        cx: &mut Context<Self>,
20861    ) {
20862        let Some(workspace) = self.workspace() else {
20863            cx.propagate();
20864            return;
20865        };
20866
20867        let selections = self.selections.all::<usize>(cx);
20868        let multi_buffer = self.buffer.read(cx);
20869        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20870        let mut new_selections_by_buffer = HashMap::default();
20871        for selection in selections {
20872            for (buffer, range, _) in
20873                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20874            {
20875                let mut range = range.to_point(buffer);
20876                range.start.column = 0;
20877                range.end.column = buffer.line_len(range.end.row);
20878                new_selections_by_buffer
20879                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20880                    .or_insert(Vec::new())
20881                    .push(range)
20882            }
20883        }
20884
20885        let proposed_changes_buffers = new_selections_by_buffer
20886            .into_iter()
20887            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20888            .collect::<Vec<_>>();
20889        let proposed_changes_editor = cx.new(|cx| {
20890            ProposedChangesEditor::new(
20891                "Proposed changes",
20892                proposed_changes_buffers,
20893                self.project.clone(),
20894                window,
20895                cx,
20896            )
20897        });
20898
20899        window.defer(cx, move |window, cx| {
20900            workspace.update(cx, |workspace, cx| {
20901                workspace.active_pane().update(cx, |pane, cx| {
20902                    pane.add_item(
20903                        Box::new(proposed_changes_editor),
20904                        true,
20905                        true,
20906                        None,
20907                        window,
20908                        cx,
20909                    );
20910                });
20911            });
20912        });
20913    }
20914
20915    pub fn open_excerpts_in_split(
20916        &mut self,
20917        _: &OpenExcerptsSplit,
20918        window: &mut Window,
20919        cx: &mut Context<Self>,
20920    ) {
20921        self.open_excerpts_common(None, true, window, cx)
20922    }
20923
20924    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20925        self.open_excerpts_common(None, false, window, cx)
20926    }
20927
20928    fn open_excerpts_common(
20929        &mut self,
20930        jump_data: Option<JumpData>,
20931        split: bool,
20932        window: &mut Window,
20933        cx: &mut Context<Self>,
20934    ) {
20935        let Some(workspace) = self.workspace() else {
20936            cx.propagate();
20937            return;
20938        };
20939
20940        if self.buffer.read(cx).is_singleton() {
20941            cx.propagate();
20942            return;
20943        }
20944
20945        let mut new_selections_by_buffer = HashMap::default();
20946        match &jump_data {
20947            Some(JumpData::MultiBufferPoint {
20948                excerpt_id,
20949                position,
20950                anchor,
20951                line_offset_from_top,
20952            }) => {
20953                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20954                if let Some(buffer) = multi_buffer_snapshot
20955                    .buffer_id_for_excerpt(*excerpt_id)
20956                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20957                {
20958                    let buffer_snapshot = buffer.read(cx).snapshot();
20959                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20960                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20961                    } else {
20962                        buffer_snapshot.clip_point(*position, Bias::Left)
20963                    };
20964                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20965                    new_selections_by_buffer.insert(
20966                        buffer,
20967                        (
20968                            vec![jump_to_offset..jump_to_offset],
20969                            Some(*line_offset_from_top),
20970                        ),
20971                    );
20972                }
20973            }
20974            Some(JumpData::MultiBufferRow {
20975                row,
20976                line_offset_from_top,
20977            }) => {
20978                let point = MultiBufferPoint::new(row.0, 0);
20979                if let Some((buffer, buffer_point, _)) =
20980                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20981                {
20982                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20983                    new_selections_by_buffer
20984                        .entry(buffer)
20985                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20986                        .0
20987                        .push(buffer_offset..buffer_offset)
20988                }
20989            }
20990            None => {
20991                let selections = self.selections.all::<usize>(cx);
20992                let multi_buffer = self.buffer.read(cx);
20993                for selection in selections {
20994                    for (snapshot, range, _, anchor) in multi_buffer
20995                        .snapshot(cx)
20996                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20997                    {
20998                        if let Some(anchor) = anchor {
20999                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21000                            else {
21001                                continue;
21002                            };
21003                            let offset = text::ToOffset::to_offset(
21004                                &anchor.text_anchor,
21005                                &buffer_handle.read(cx).snapshot(),
21006                            );
21007                            let range = offset..offset;
21008                            new_selections_by_buffer
21009                                .entry(buffer_handle)
21010                                .or_insert((Vec::new(), None))
21011                                .0
21012                                .push(range)
21013                        } else {
21014                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21015                            else {
21016                                continue;
21017                            };
21018                            new_selections_by_buffer
21019                                .entry(buffer_handle)
21020                                .or_insert((Vec::new(), None))
21021                                .0
21022                                .push(range)
21023                        }
21024                    }
21025                }
21026            }
21027        }
21028
21029        new_selections_by_buffer
21030            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21031
21032        if new_selections_by_buffer.is_empty() {
21033            return;
21034        }
21035
21036        // We defer the pane interaction because we ourselves are a workspace item
21037        // and activating a new item causes the pane to call a method on us reentrantly,
21038        // which panics if we're on the stack.
21039        window.defer(cx, move |window, cx| {
21040            workspace.update(cx, |workspace, cx| {
21041                let pane = if split {
21042                    workspace.adjacent_pane(window, cx)
21043                } else {
21044                    workspace.active_pane().clone()
21045                };
21046
21047                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21048                    let editor = buffer
21049                        .read(cx)
21050                        .file()
21051                        .is_none()
21052                        .then(|| {
21053                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21054                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21055                            // Instead, we try to activate the existing editor in the pane first.
21056                            let (editor, pane_item_index) =
21057                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21058                                    let editor = item.downcast::<Editor>()?;
21059                                    let singleton_buffer =
21060                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21061                                    if singleton_buffer == buffer {
21062                                        Some((editor, i))
21063                                    } else {
21064                                        None
21065                                    }
21066                                })?;
21067                            pane.update(cx, |pane, cx| {
21068                                pane.activate_item(pane_item_index, true, true, window, cx)
21069                            });
21070                            Some(editor)
21071                        })
21072                        .flatten()
21073                        .unwrap_or_else(|| {
21074                            workspace.open_project_item::<Self>(
21075                                pane.clone(),
21076                                buffer,
21077                                true,
21078                                true,
21079                                window,
21080                                cx,
21081                            )
21082                        });
21083
21084                    editor.update(cx, |editor, cx| {
21085                        let autoscroll = match scroll_offset {
21086                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21087                            None => Autoscroll::newest(),
21088                        };
21089                        let nav_history = editor.nav_history.take();
21090                        editor.change_selections(
21091                            SelectionEffects::scroll(autoscroll),
21092                            window,
21093                            cx,
21094                            |s| {
21095                                s.select_ranges(ranges);
21096                            },
21097                        );
21098                        editor.nav_history = nav_history;
21099                    });
21100                }
21101            })
21102        });
21103    }
21104
21105    // For now, don't allow opening excerpts in buffers that aren't backed by
21106    // regular project files.
21107    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21108        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21109    }
21110
21111    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21112        let snapshot = self.buffer.read(cx).read(cx);
21113        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21114        Some(
21115            ranges
21116                .iter()
21117                .map(move |range| {
21118                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21119                })
21120                .collect(),
21121        )
21122    }
21123
21124    fn selection_replacement_ranges(
21125        &self,
21126        range: Range<OffsetUtf16>,
21127        cx: &mut App,
21128    ) -> Vec<Range<OffsetUtf16>> {
21129        let selections = self.selections.all::<OffsetUtf16>(cx);
21130        let newest_selection = selections
21131            .iter()
21132            .max_by_key(|selection| selection.id)
21133            .unwrap();
21134        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21135        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21136        let snapshot = self.buffer.read(cx).read(cx);
21137        selections
21138            .into_iter()
21139            .map(|mut selection| {
21140                selection.start.0 =
21141                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21142                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21143                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21144                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21145            })
21146            .collect()
21147    }
21148
21149    fn report_editor_event(
21150        &self,
21151        reported_event: ReportEditorEvent,
21152        file_extension: Option<String>,
21153        cx: &App,
21154    ) {
21155        if cfg!(any(test, feature = "test-support")) {
21156            return;
21157        }
21158
21159        let Some(project) = &self.project else { return };
21160
21161        // If None, we are in a file without an extension
21162        let file = self
21163            .buffer
21164            .read(cx)
21165            .as_singleton()
21166            .and_then(|b| b.read(cx).file());
21167        let file_extension = file_extension.or(file
21168            .as_ref()
21169            .and_then(|file| Path::new(file.file_name(cx)).extension())
21170            .and_then(|e| e.to_str())
21171            .map(|a| a.to_string()));
21172
21173        let vim_mode = vim_enabled(cx);
21174
21175        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21176        let copilot_enabled = edit_predictions_provider
21177            == language::language_settings::EditPredictionProvider::Copilot;
21178        let copilot_enabled_for_language = self
21179            .buffer
21180            .read(cx)
21181            .language_settings(cx)
21182            .show_edit_predictions;
21183
21184        let project = project.read(cx);
21185        let event_type = reported_event.event_type();
21186
21187        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21188            telemetry::event!(
21189                event_type,
21190                type = if auto_saved {"autosave"} else {"manual"},
21191                file_extension,
21192                vim_mode,
21193                copilot_enabled,
21194                copilot_enabled_for_language,
21195                edit_predictions_provider,
21196                is_via_ssh = project.is_via_remote_server(),
21197            );
21198        } else {
21199            telemetry::event!(
21200                event_type,
21201                file_extension,
21202                vim_mode,
21203                copilot_enabled,
21204                copilot_enabled_for_language,
21205                edit_predictions_provider,
21206                is_via_ssh = project.is_via_remote_server(),
21207            );
21208        };
21209    }
21210
21211    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21212    /// with each line being an array of {text, highlight} objects.
21213    fn copy_highlight_json(
21214        &mut self,
21215        _: &CopyHighlightJson,
21216        window: &mut Window,
21217        cx: &mut Context<Self>,
21218    ) {
21219        #[derive(Serialize)]
21220        struct Chunk<'a> {
21221            text: String,
21222            highlight: Option<&'a str>,
21223        }
21224
21225        let snapshot = self.buffer.read(cx).snapshot(cx);
21226        let range = self
21227            .selected_text_range(false, window, cx)
21228            .and_then(|selection| {
21229                if selection.range.is_empty() {
21230                    None
21231                } else {
21232                    Some(selection.range)
21233                }
21234            })
21235            .unwrap_or_else(|| 0..snapshot.len());
21236
21237        let chunks = snapshot.chunks(range, true);
21238        let mut lines = Vec::new();
21239        let mut line: VecDeque<Chunk> = VecDeque::new();
21240
21241        let Some(style) = self.style.as_ref() else {
21242            return;
21243        };
21244
21245        for chunk in chunks {
21246            let highlight = chunk
21247                .syntax_highlight_id
21248                .and_then(|id| id.name(&style.syntax));
21249            let mut chunk_lines = chunk.text.split('\n').peekable();
21250            while let Some(text) = chunk_lines.next() {
21251                let mut merged_with_last_token = false;
21252                if let Some(last_token) = line.back_mut()
21253                    && last_token.highlight == highlight
21254                {
21255                    last_token.text.push_str(text);
21256                    merged_with_last_token = true;
21257                }
21258
21259                if !merged_with_last_token {
21260                    line.push_back(Chunk {
21261                        text: text.into(),
21262                        highlight,
21263                    });
21264                }
21265
21266                if chunk_lines.peek().is_some() {
21267                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21268                        line.pop_front();
21269                    }
21270                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21271                        line.pop_back();
21272                    }
21273
21274                    lines.push(mem::take(&mut line));
21275                }
21276            }
21277        }
21278
21279        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21280            return;
21281        };
21282        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21283    }
21284
21285    pub fn open_context_menu(
21286        &mut self,
21287        _: &OpenContextMenu,
21288        window: &mut Window,
21289        cx: &mut Context<Self>,
21290    ) {
21291        self.request_autoscroll(Autoscroll::newest(), cx);
21292        let position = self.selections.newest_display(cx).start;
21293        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21294    }
21295
21296    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21297        &self.inlay_hint_cache
21298    }
21299
21300    pub fn replay_insert_event(
21301        &mut self,
21302        text: &str,
21303        relative_utf16_range: Option<Range<isize>>,
21304        window: &mut Window,
21305        cx: &mut Context<Self>,
21306    ) {
21307        if !self.input_enabled {
21308            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21309            return;
21310        }
21311        if let Some(relative_utf16_range) = relative_utf16_range {
21312            let selections = self.selections.all::<OffsetUtf16>(cx);
21313            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21314                let new_ranges = selections.into_iter().map(|range| {
21315                    let start = OffsetUtf16(
21316                        range
21317                            .head()
21318                            .0
21319                            .saturating_add_signed(relative_utf16_range.start),
21320                    );
21321                    let end = OffsetUtf16(
21322                        range
21323                            .head()
21324                            .0
21325                            .saturating_add_signed(relative_utf16_range.end),
21326                    );
21327                    start..end
21328                });
21329                s.select_ranges(new_ranges);
21330            });
21331        }
21332
21333        self.handle_input(text, window, cx);
21334    }
21335
21336    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21337        let Some(provider) = self.semantics_provider.as_ref() else {
21338            return false;
21339        };
21340
21341        let mut supports = false;
21342        self.buffer().update(cx, |this, cx| {
21343            this.for_each_buffer(|buffer| {
21344                supports |= provider.supports_inlay_hints(buffer, cx);
21345            });
21346        });
21347
21348        supports
21349    }
21350
21351    pub fn is_focused(&self, window: &Window) -> bool {
21352        self.focus_handle.is_focused(window)
21353    }
21354
21355    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21356        cx.emit(EditorEvent::Focused);
21357
21358        if let Some(descendant) = self
21359            .last_focused_descendant
21360            .take()
21361            .and_then(|descendant| descendant.upgrade())
21362        {
21363            window.focus(&descendant);
21364        } else {
21365            if let Some(blame) = self.blame.as_ref() {
21366                blame.update(cx, GitBlame::focus)
21367            }
21368
21369            self.blink_manager.update(cx, BlinkManager::enable);
21370            self.show_cursor_names(window, cx);
21371            self.buffer.update(cx, |buffer, cx| {
21372                buffer.finalize_last_transaction(cx);
21373                if self.leader_id.is_none() {
21374                    buffer.set_active_selections(
21375                        &self.selections.disjoint_anchors_arc(),
21376                        self.selections.line_mode(),
21377                        self.cursor_shape,
21378                        cx,
21379                    );
21380                }
21381            });
21382        }
21383    }
21384
21385    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21386        cx.emit(EditorEvent::FocusedIn)
21387    }
21388
21389    fn handle_focus_out(
21390        &mut self,
21391        event: FocusOutEvent,
21392        _window: &mut Window,
21393        cx: &mut Context<Self>,
21394    ) {
21395        if event.blurred != self.focus_handle {
21396            self.last_focused_descendant = Some(event.blurred);
21397        }
21398        self.selection_drag_state = SelectionDragState::None;
21399        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21400    }
21401
21402    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21403        self.blink_manager.update(cx, BlinkManager::disable);
21404        self.buffer
21405            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21406
21407        if let Some(blame) = self.blame.as_ref() {
21408            blame.update(cx, GitBlame::blur)
21409        }
21410        if !self.hover_state.focused(window, cx) {
21411            hide_hover(self, cx);
21412        }
21413        if !self
21414            .context_menu
21415            .borrow()
21416            .as_ref()
21417            .is_some_and(|context_menu| context_menu.focused(window, cx))
21418        {
21419            self.hide_context_menu(window, cx);
21420        }
21421        self.discard_edit_prediction(false, cx);
21422        cx.emit(EditorEvent::Blurred);
21423        cx.notify();
21424    }
21425
21426    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21427        let mut pending: String = window
21428            .pending_input_keystrokes()
21429            .into_iter()
21430            .flatten()
21431            .filter_map(|keystroke| {
21432                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21433                    keystroke.key_char.clone()
21434                } else {
21435                    None
21436                }
21437            })
21438            .collect();
21439
21440        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21441            pending = "".to_string();
21442        }
21443
21444        let existing_pending = self
21445            .text_highlights::<PendingInput>(cx)
21446            .map(|(_, ranges)| ranges.to_vec());
21447        if existing_pending.is_none() && pending.is_empty() {
21448            return;
21449        }
21450        let transaction =
21451            self.transact(window, cx, |this, window, cx| {
21452                let selections = this.selections.all::<usize>(cx);
21453                let edits = selections
21454                    .iter()
21455                    .map(|selection| (selection.end..selection.end, pending.clone()));
21456                this.edit(edits, cx);
21457                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21458                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21459                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21460                    }));
21461                });
21462                if let Some(existing_ranges) = existing_pending {
21463                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21464                    this.edit(edits, cx);
21465                }
21466            });
21467
21468        let snapshot = self.snapshot(window, cx);
21469        let ranges = self
21470            .selections
21471            .all::<usize>(cx)
21472            .into_iter()
21473            .map(|selection| {
21474                snapshot.buffer_snapshot.anchor_after(selection.end)
21475                    ..snapshot
21476                        .buffer_snapshot
21477                        .anchor_before(selection.end + pending.len())
21478            })
21479            .collect();
21480
21481        if pending.is_empty() {
21482            self.clear_highlights::<PendingInput>(cx);
21483        } else {
21484            self.highlight_text::<PendingInput>(
21485                ranges,
21486                HighlightStyle {
21487                    underline: Some(UnderlineStyle {
21488                        thickness: px(1.),
21489                        color: None,
21490                        wavy: false,
21491                    }),
21492                    ..Default::default()
21493                },
21494                cx,
21495            );
21496        }
21497
21498        self.ime_transaction = self.ime_transaction.or(transaction);
21499        if let Some(transaction) = self.ime_transaction {
21500            self.buffer.update(cx, |buffer, cx| {
21501                buffer.group_until_transaction(transaction, cx);
21502            });
21503        }
21504
21505        if self.text_highlights::<PendingInput>(cx).is_none() {
21506            self.ime_transaction.take();
21507        }
21508    }
21509
21510    pub fn register_action_renderer(
21511        &mut self,
21512        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21513    ) -> Subscription {
21514        let id = self.next_editor_action_id.post_inc();
21515        self.editor_actions
21516            .borrow_mut()
21517            .insert(id, Box::new(listener));
21518
21519        let editor_actions = self.editor_actions.clone();
21520        Subscription::new(move || {
21521            editor_actions.borrow_mut().remove(&id);
21522        })
21523    }
21524
21525    pub fn register_action<A: Action>(
21526        &mut self,
21527        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21528    ) -> Subscription {
21529        let id = self.next_editor_action_id.post_inc();
21530        let listener = Arc::new(listener);
21531        self.editor_actions.borrow_mut().insert(
21532            id,
21533            Box::new(move |_, window, _| {
21534                let listener = listener.clone();
21535                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21536                    let action = action.downcast_ref().unwrap();
21537                    if phase == DispatchPhase::Bubble {
21538                        listener(action, window, cx)
21539                    }
21540                })
21541            }),
21542        );
21543
21544        let editor_actions = self.editor_actions.clone();
21545        Subscription::new(move || {
21546            editor_actions.borrow_mut().remove(&id);
21547        })
21548    }
21549
21550    pub fn file_header_size(&self) -> u32 {
21551        FILE_HEADER_HEIGHT
21552    }
21553
21554    pub fn restore(
21555        &mut self,
21556        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21557        window: &mut Window,
21558        cx: &mut Context<Self>,
21559    ) {
21560        let workspace = self.workspace();
21561        let project = self.project();
21562        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21563            let mut tasks = Vec::new();
21564            for (buffer_id, changes) in revert_changes {
21565                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21566                    buffer.update(cx, |buffer, cx| {
21567                        buffer.edit(
21568                            changes
21569                                .into_iter()
21570                                .map(|(range, text)| (range, text.to_string())),
21571                            None,
21572                            cx,
21573                        );
21574                    });
21575
21576                    if let Some(project) =
21577                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21578                    {
21579                        project.update(cx, |project, cx| {
21580                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21581                        })
21582                    }
21583                }
21584            }
21585            tasks
21586        });
21587        cx.spawn_in(window, async move |_, cx| {
21588            for (buffer, task) in save_tasks {
21589                let result = task.await;
21590                if result.is_err() {
21591                    let Some(path) = buffer
21592                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21593                        .ok()
21594                    else {
21595                        continue;
21596                    };
21597                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21598                        let Some(task) = cx
21599                            .update_window_entity(workspace, |workspace, window, cx| {
21600                                workspace
21601                                    .open_path_preview(path, None, false, false, false, window, cx)
21602                            })
21603                            .ok()
21604                        else {
21605                            continue;
21606                        };
21607                        task.await.log_err();
21608                    }
21609                }
21610            }
21611        })
21612        .detach();
21613        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21614            selections.refresh()
21615        });
21616    }
21617
21618    pub fn to_pixel_point(
21619        &self,
21620        source: multi_buffer::Anchor,
21621        editor_snapshot: &EditorSnapshot,
21622        window: &mut Window,
21623    ) -> Option<gpui::Point<Pixels>> {
21624        let source_point = source.to_display_point(editor_snapshot);
21625        self.display_to_pixel_point(source_point, editor_snapshot, window)
21626    }
21627
21628    pub fn display_to_pixel_point(
21629        &self,
21630        source: DisplayPoint,
21631        editor_snapshot: &EditorSnapshot,
21632        window: &mut Window,
21633    ) -> Option<gpui::Point<Pixels>> {
21634        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21635        let text_layout_details = self.text_layout_details(window);
21636        let scroll_top = text_layout_details
21637            .scroll_anchor
21638            .scroll_position(editor_snapshot)
21639            .y;
21640
21641        if source.row().as_f32() < scroll_top.floor() {
21642            return None;
21643        }
21644        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21645        let source_y = line_height * (source.row().as_f32() - scroll_top);
21646        Some(gpui::Point::new(source_x, source_y))
21647    }
21648
21649    pub fn has_visible_completions_menu(&self) -> bool {
21650        !self.edit_prediction_preview_is_active()
21651            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21652                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21653            })
21654    }
21655
21656    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21657        if self.mode.is_minimap() {
21658            return;
21659        }
21660        self.addons
21661            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21662    }
21663
21664    pub fn unregister_addon<T: Addon>(&mut self) {
21665        self.addons.remove(&std::any::TypeId::of::<T>());
21666    }
21667
21668    pub fn addon<T: Addon>(&self) -> Option<&T> {
21669        let type_id = std::any::TypeId::of::<T>();
21670        self.addons
21671            .get(&type_id)
21672            .and_then(|item| item.to_any().downcast_ref::<T>())
21673    }
21674
21675    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21676        let type_id = std::any::TypeId::of::<T>();
21677        self.addons
21678            .get_mut(&type_id)
21679            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21680    }
21681
21682    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21683        let text_layout_details = self.text_layout_details(window);
21684        let style = &text_layout_details.editor_style;
21685        let font_id = window.text_system().resolve_font(&style.text.font());
21686        let font_size = style.text.font_size.to_pixels(window.rem_size());
21687        let line_height = style.text.line_height_in_pixels(window.rem_size());
21688        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21689        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21690
21691        CharacterDimensions {
21692            em_width,
21693            em_advance,
21694            line_height,
21695        }
21696    }
21697
21698    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21699        self.load_diff_task.clone()
21700    }
21701
21702    fn read_metadata_from_db(
21703        &mut self,
21704        item_id: u64,
21705        workspace_id: WorkspaceId,
21706        window: &mut Window,
21707        cx: &mut Context<Editor>,
21708    ) {
21709        if self.is_singleton(cx)
21710            && !self.mode.is_minimap()
21711            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21712        {
21713            let buffer_snapshot = OnceCell::new();
21714
21715            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21716                && !folds.is_empty()
21717            {
21718                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21719                self.fold_ranges(
21720                    folds
21721                        .into_iter()
21722                        .map(|(start, end)| {
21723                            snapshot.clip_offset(start, Bias::Left)
21724                                ..snapshot.clip_offset(end, Bias::Right)
21725                        })
21726                        .collect(),
21727                    false,
21728                    window,
21729                    cx,
21730                );
21731            }
21732
21733            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21734                && !selections.is_empty()
21735            {
21736                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21737                // skip adding the initial selection to selection history
21738                self.selection_history.mode = SelectionHistoryMode::Skipping;
21739                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21740                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21741                        snapshot.clip_offset(start, Bias::Left)
21742                            ..snapshot.clip_offset(end, Bias::Right)
21743                    }));
21744                });
21745                self.selection_history.mode = SelectionHistoryMode::Normal;
21746            };
21747        }
21748
21749        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21750    }
21751
21752    fn update_lsp_data(
21753        &mut self,
21754        ignore_cache: bool,
21755        for_buffer: Option<BufferId>,
21756        window: &mut Window,
21757        cx: &mut Context<'_, Self>,
21758    ) {
21759        self.pull_diagnostics(for_buffer, window, cx);
21760        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21761    }
21762}
21763
21764fn edit_for_markdown_paste<'a>(
21765    buffer: &MultiBufferSnapshot,
21766    range: Range<usize>,
21767    to_insert: &'a str,
21768    url: Option<url::Url>,
21769) -> (Range<usize>, Cow<'a, str>) {
21770    if url.is_none() {
21771        return (range, Cow::Borrowed(to_insert));
21772    };
21773
21774    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21775
21776    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21777        Cow::Borrowed(to_insert)
21778    } else {
21779        Cow::Owned(format!("[{old_text}]({to_insert})"))
21780    };
21781    (range, new_text)
21782}
21783
21784fn vim_enabled(cx: &App) -> bool {
21785    vim_mode_setting::VimModeSetting::try_get(cx)
21786        .map(|vim_mode| vim_mode.0)
21787        .unwrap_or(false)
21788}
21789
21790fn process_completion_for_edit(
21791    completion: &Completion,
21792    intent: CompletionIntent,
21793    buffer: &Entity<Buffer>,
21794    cursor_position: &text::Anchor,
21795    cx: &mut Context<Editor>,
21796) -> CompletionEdit {
21797    let buffer = buffer.read(cx);
21798    let buffer_snapshot = buffer.snapshot();
21799    let (snippet, new_text) = if completion.is_snippet() {
21800        // Workaround for typescript language server issues so that methods don't expand within
21801        // strings and functions with type expressions. The previous point is used because the query
21802        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21803        let mut snippet_source = completion.new_text.clone();
21804        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21805        previous_point.column = previous_point.column.saturating_sub(1);
21806        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21807            && scope.prefers_label_for_snippet_in_completion()
21808            && let Some(label) = completion.label()
21809            && matches!(
21810                completion.kind(),
21811                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21812            )
21813        {
21814            snippet_source = label;
21815        }
21816        match Snippet::parse(&snippet_source).log_err() {
21817            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21818            None => (None, completion.new_text.clone()),
21819        }
21820    } else {
21821        (None, completion.new_text.clone())
21822    };
21823
21824    let mut range_to_replace = {
21825        let replace_range = &completion.replace_range;
21826        if let CompletionSource::Lsp {
21827            insert_range: Some(insert_range),
21828            ..
21829        } = &completion.source
21830        {
21831            debug_assert_eq!(
21832                insert_range.start, replace_range.start,
21833                "insert_range and replace_range should start at the same position"
21834            );
21835            debug_assert!(
21836                insert_range
21837                    .start
21838                    .cmp(cursor_position, &buffer_snapshot)
21839                    .is_le(),
21840                "insert_range should start before or at cursor position"
21841            );
21842            debug_assert!(
21843                replace_range
21844                    .start
21845                    .cmp(cursor_position, &buffer_snapshot)
21846                    .is_le(),
21847                "replace_range should start before or at cursor position"
21848            );
21849
21850            let should_replace = match intent {
21851                CompletionIntent::CompleteWithInsert => false,
21852                CompletionIntent::CompleteWithReplace => true,
21853                CompletionIntent::Complete | CompletionIntent::Compose => {
21854                    let insert_mode =
21855                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21856                            .completions
21857                            .lsp_insert_mode;
21858                    match insert_mode {
21859                        LspInsertMode::Insert => false,
21860                        LspInsertMode::Replace => true,
21861                        LspInsertMode::ReplaceSubsequence => {
21862                            let mut text_to_replace = buffer.chars_for_range(
21863                                buffer.anchor_before(replace_range.start)
21864                                    ..buffer.anchor_after(replace_range.end),
21865                            );
21866                            let mut current_needle = text_to_replace.next();
21867                            for haystack_ch in completion.label.text.chars() {
21868                                if let Some(needle_ch) = current_needle
21869                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21870                                {
21871                                    current_needle = text_to_replace.next();
21872                                }
21873                            }
21874                            current_needle.is_none()
21875                        }
21876                        LspInsertMode::ReplaceSuffix => {
21877                            if replace_range
21878                                .end
21879                                .cmp(cursor_position, &buffer_snapshot)
21880                                .is_gt()
21881                            {
21882                                let range_after_cursor = *cursor_position..replace_range.end;
21883                                let text_after_cursor = buffer
21884                                    .text_for_range(
21885                                        buffer.anchor_before(range_after_cursor.start)
21886                                            ..buffer.anchor_after(range_after_cursor.end),
21887                                    )
21888                                    .collect::<String>()
21889                                    .to_ascii_lowercase();
21890                                completion
21891                                    .label
21892                                    .text
21893                                    .to_ascii_lowercase()
21894                                    .ends_with(&text_after_cursor)
21895                            } else {
21896                                true
21897                            }
21898                        }
21899                    }
21900                }
21901            };
21902
21903            if should_replace {
21904                replace_range.clone()
21905            } else {
21906                insert_range.clone()
21907            }
21908        } else {
21909            replace_range.clone()
21910        }
21911    };
21912
21913    if range_to_replace
21914        .end
21915        .cmp(cursor_position, &buffer_snapshot)
21916        .is_lt()
21917    {
21918        range_to_replace.end = *cursor_position;
21919    }
21920
21921    CompletionEdit {
21922        new_text,
21923        replace_range: range_to_replace.to_offset(buffer),
21924        snippet,
21925    }
21926}
21927
21928struct CompletionEdit {
21929    new_text: String,
21930    replace_range: Range<usize>,
21931    snippet: Option<Snippet>,
21932}
21933
21934fn insert_extra_newline_brackets(
21935    buffer: &MultiBufferSnapshot,
21936    range: Range<usize>,
21937    language: &language::LanguageScope,
21938) -> bool {
21939    let leading_whitespace_len = buffer
21940        .reversed_chars_at(range.start)
21941        .take_while(|c| c.is_whitespace() && *c != '\n')
21942        .map(|c| c.len_utf8())
21943        .sum::<usize>();
21944    let trailing_whitespace_len = buffer
21945        .chars_at(range.end)
21946        .take_while(|c| c.is_whitespace() && *c != '\n')
21947        .map(|c| c.len_utf8())
21948        .sum::<usize>();
21949    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21950
21951    language.brackets().any(|(pair, enabled)| {
21952        let pair_start = pair.start.trim_end();
21953        let pair_end = pair.end.trim_start();
21954
21955        enabled
21956            && pair.newline
21957            && buffer.contains_str_at(range.end, pair_end)
21958            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21959    })
21960}
21961
21962fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21963    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21964        [(buffer, range, _)] => (*buffer, range.clone()),
21965        _ => return false,
21966    };
21967    let pair = {
21968        let mut result: Option<BracketMatch> = None;
21969
21970        for pair in buffer
21971            .all_bracket_ranges(range.clone())
21972            .filter(move |pair| {
21973                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21974            })
21975        {
21976            let len = pair.close_range.end - pair.open_range.start;
21977
21978            if let Some(existing) = &result {
21979                let existing_len = existing.close_range.end - existing.open_range.start;
21980                if len > existing_len {
21981                    continue;
21982                }
21983            }
21984
21985            result = Some(pair);
21986        }
21987
21988        result
21989    };
21990    let Some(pair) = pair else {
21991        return false;
21992    };
21993    pair.newline_only
21994        && buffer
21995            .chars_for_range(pair.open_range.end..range.start)
21996            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21997            .all(|c| c.is_whitespace() && c != '\n')
21998}
21999
22000fn update_uncommitted_diff_for_buffer(
22001    editor: Entity<Editor>,
22002    project: &Entity<Project>,
22003    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22004    buffer: Entity<MultiBuffer>,
22005    cx: &mut App,
22006) -> Task<()> {
22007    let mut tasks = Vec::new();
22008    project.update(cx, |project, cx| {
22009        for buffer in buffers {
22010            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22011                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22012            }
22013        }
22014    });
22015    cx.spawn(async move |cx| {
22016        let diffs = future::join_all(tasks).await;
22017        if editor
22018            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22019            .unwrap_or(false)
22020        {
22021            return;
22022        }
22023
22024        buffer
22025            .update(cx, |buffer, cx| {
22026                for diff in diffs.into_iter().flatten() {
22027                    buffer.add_diff(diff, cx);
22028                }
22029            })
22030            .ok();
22031    })
22032}
22033
22034fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22035    let tab_size = tab_size.get() as usize;
22036    let mut width = offset;
22037
22038    for ch in text.chars() {
22039        width += if ch == '\t' {
22040            tab_size - (width % tab_size)
22041        } else {
22042            1
22043        };
22044    }
22045
22046    width - offset
22047}
22048
22049#[cfg(test)]
22050mod tests {
22051    use super::*;
22052
22053    #[test]
22054    fn test_string_size_with_expanded_tabs() {
22055        let nz = |val| NonZeroU32::new(val).unwrap();
22056        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22057        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22058        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22059        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22060        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22061        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22062        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22063        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22064    }
22065}
22066
22067/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22068struct WordBreakingTokenizer<'a> {
22069    input: &'a str,
22070}
22071
22072impl<'a> WordBreakingTokenizer<'a> {
22073    fn new(input: &'a str) -> Self {
22074        Self { input }
22075    }
22076}
22077
22078fn is_char_ideographic(ch: char) -> bool {
22079    use unicode_script::Script::*;
22080    use unicode_script::UnicodeScript;
22081    matches!(ch.script(), Han | Tangut | Yi)
22082}
22083
22084fn is_grapheme_ideographic(text: &str) -> bool {
22085    text.chars().any(is_char_ideographic)
22086}
22087
22088fn is_grapheme_whitespace(text: &str) -> bool {
22089    text.chars().any(|x| x.is_whitespace())
22090}
22091
22092fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22093    text.chars()
22094        .next()
22095        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22096}
22097
22098#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22099enum WordBreakToken<'a> {
22100    Word { token: &'a str, grapheme_len: usize },
22101    InlineWhitespace { token: &'a str, grapheme_len: usize },
22102    Newline,
22103}
22104
22105impl<'a> Iterator for WordBreakingTokenizer<'a> {
22106    /// Yields a span, the count of graphemes in the token, and whether it was
22107    /// whitespace. Note that it also breaks at word boundaries.
22108    type Item = WordBreakToken<'a>;
22109
22110    fn next(&mut self) -> Option<Self::Item> {
22111        use unicode_segmentation::UnicodeSegmentation;
22112        if self.input.is_empty() {
22113            return None;
22114        }
22115
22116        let mut iter = self.input.graphemes(true).peekable();
22117        let mut offset = 0;
22118        let mut grapheme_len = 0;
22119        if let Some(first_grapheme) = iter.next() {
22120            let is_newline = first_grapheme == "\n";
22121            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22122            offset += first_grapheme.len();
22123            grapheme_len += 1;
22124            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22125                if let Some(grapheme) = iter.peek().copied()
22126                    && should_stay_with_preceding_ideograph(grapheme)
22127                {
22128                    offset += grapheme.len();
22129                    grapheme_len += 1;
22130                }
22131            } else {
22132                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22133                let mut next_word_bound = words.peek().copied();
22134                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22135                    next_word_bound = words.next();
22136                }
22137                while let Some(grapheme) = iter.peek().copied() {
22138                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22139                        break;
22140                    };
22141                    if is_grapheme_whitespace(grapheme) != is_whitespace
22142                        || (grapheme == "\n") != is_newline
22143                    {
22144                        break;
22145                    };
22146                    offset += grapheme.len();
22147                    grapheme_len += 1;
22148                    iter.next();
22149                }
22150            }
22151            let token = &self.input[..offset];
22152            self.input = &self.input[offset..];
22153            if token == "\n" {
22154                Some(WordBreakToken::Newline)
22155            } else if is_whitespace {
22156                Some(WordBreakToken::InlineWhitespace {
22157                    token,
22158                    grapheme_len,
22159                })
22160            } else {
22161                Some(WordBreakToken::Word {
22162                    token,
22163                    grapheme_len,
22164                })
22165            }
22166        } else {
22167            None
22168        }
22169    }
22170}
22171
22172#[test]
22173fn test_word_breaking_tokenizer() {
22174    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22175        ("", &[]),
22176        ("  ", &[whitespace("  ", 2)]),
22177        ("Ʒ", &[word("Ʒ", 1)]),
22178        ("Ǽ", &[word("Ǽ", 1)]),
22179        ("", &[word("", 1)]),
22180        ("⋑⋑", &[word("⋑⋑", 2)]),
22181        (
22182            "原理,进而",
22183            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22184        ),
22185        (
22186            "hello world",
22187            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22188        ),
22189        (
22190            "hello, world",
22191            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22192        ),
22193        (
22194            "  hello world",
22195            &[
22196                whitespace("  ", 2),
22197                word("hello", 5),
22198                whitespace(" ", 1),
22199                word("world", 5),
22200            ],
22201        ),
22202        (
22203            "这是什么 \n 钢笔",
22204            &[
22205                word("", 1),
22206                word("", 1),
22207                word("", 1),
22208                word("", 1),
22209                whitespace(" ", 1),
22210                newline(),
22211                whitespace(" ", 1),
22212                word("", 1),
22213                word("", 1),
22214            ],
22215        ),
22216        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22217    ];
22218
22219    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22220        WordBreakToken::Word {
22221            token,
22222            grapheme_len,
22223        }
22224    }
22225
22226    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22227        WordBreakToken::InlineWhitespace {
22228            token,
22229            grapheme_len,
22230        }
22231    }
22232
22233    fn newline() -> WordBreakToken<'static> {
22234        WordBreakToken::Newline
22235    }
22236
22237    for (input, result) in tests {
22238        assert_eq!(
22239            WordBreakingTokenizer::new(input)
22240                .collect::<Vec<_>>()
22241                .as_slice(),
22242            *result,
22243        );
22244    }
22245}
22246
22247fn wrap_with_prefix(
22248    first_line_prefix: String,
22249    subsequent_lines_prefix: String,
22250    unwrapped_text: String,
22251    wrap_column: usize,
22252    tab_size: NonZeroU32,
22253    preserve_existing_whitespace: bool,
22254) -> String {
22255    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22256    let subsequent_lines_prefix_len =
22257        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22258    let mut wrapped_text = String::new();
22259    let mut current_line = first_line_prefix;
22260    let mut is_first_line = true;
22261
22262    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22263    let mut current_line_len = first_line_prefix_len;
22264    let mut in_whitespace = false;
22265    for token in tokenizer {
22266        let have_preceding_whitespace = in_whitespace;
22267        match token {
22268            WordBreakToken::Word {
22269                token,
22270                grapheme_len,
22271            } => {
22272                in_whitespace = false;
22273                let current_prefix_len = if is_first_line {
22274                    first_line_prefix_len
22275                } else {
22276                    subsequent_lines_prefix_len
22277                };
22278                if current_line_len + grapheme_len > wrap_column
22279                    && current_line_len != current_prefix_len
22280                {
22281                    wrapped_text.push_str(current_line.trim_end());
22282                    wrapped_text.push('\n');
22283                    is_first_line = false;
22284                    current_line = subsequent_lines_prefix.clone();
22285                    current_line_len = subsequent_lines_prefix_len;
22286                }
22287                current_line.push_str(token);
22288                current_line_len += grapheme_len;
22289            }
22290            WordBreakToken::InlineWhitespace {
22291                mut token,
22292                mut grapheme_len,
22293            } => {
22294                in_whitespace = true;
22295                if have_preceding_whitespace && !preserve_existing_whitespace {
22296                    continue;
22297                }
22298                if !preserve_existing_whitespace {
22299                    token = " ";
22300                    grapheme_len = 1;
22301                }
22302                let current_prefix_len = if is_first_line {
22303                    first_line_prefix_len
22304                } else {
22305                    subsequent_lines_prefix_len
22306                };
22307                if current_line_len + grapheme_len > wrap_column {
22308                    wrapped_text.push_str(current_line.trim_end());
22309                    wrapped_text.push('\n');
22310                    is_first_line = false;
22311                    current_line = subsequent_lines_prefix.clone();
22312                    current_line_len = subsequent_lines_prefix_len;
22313                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22314                    current_line.push_str(token);
22315                    current_line_len += grapheme_len;
22316                }
22317            }
22318            WordBreakToken::Newline => {
22319                in_whitespace = true;
22320                let current_prefix_len = if is_first_line {
22321                    first_line_prefix_len
22322                } else {
22323                    subsequent_lines_prefix_len
22324                };
22325                if preserve_existing_whitespace {
22326                    wrapped_text.push_str(current_line.trim_end());
22327                    wrapped_text.push('\n');
22328                    is_first_line = false;
22329                    current_line = subsequent_lines_prefix.clone();
22330                    current_line_len = subsequent_lines_prefix_len;
22331                } else if have_preceding_whitespace {
22332                    continue;
22333                } else if current_line_len + 1 > wrap_column
22334                    && current_line_len != current_prefix_len
22335                {
22336                    wrapped_text.push_str(current_line.trim_end());
22337                    wrapped_text.push('\n');
22338                    is_first_line = false;
22339                    current_line = subsequent_lines_prefix.clone();
22340                    current_line_len = subsequent_lines_prefix_len;
22341                } else if current_line_len != current_prefix_len {
22342                    current_line.push(' ');
22343                    current_line_len += 1;
22344                }
22345            }
22346        }
22347    }
22348
22349    if !current_line.is_empty() {
22350        wrapped_text.push_str(&current_line);
22351    }
22352    wrapped_text
22353}
22354
22355#[test]
22356fn test_wrap_with_prefix() {
22357    assert_eq!(
22358        wrap_with_prefix(
22359            "# ".to_string(),
22360            "# ".to_string(),
22361            "abcdefg".to_string(),
22362            4,
22363            NonZeroU32::new(4).unwrap(),
22364            false,
22365        ),
22366        "# abcdefg"
22367    );
22368    assert_eq!(
22369        wrap_with_prefix(
22370            "".to_string(),
22371            "".to_string(),
22372            "\thello world".to_string(),
22373            8,
22374            NonZeroU32::new(4).unwrap(),
22375            false,
22376        ),
22377        "hello\nworld"
22378    );
22379    assert_eq!(
22380        wrap_with_prefix(
22381            "// ".to_string(),
22382            "// ".to_string(),
22383            "xx \nyy zz aa bb cc".to_string(),
22384            12,
22385            NonZeroU32::new(4).unwrap(),
22386            false,
22387        ),
22388        "// xx yy zz\n// aa bb cc"
22389    );
22390    assert_eq!(
22391        wrap_with_prefix(
22392            String::new(),
22393            String::new(),
22394            "这是什么 \n 钢笔".to_string(),
22395            3,
22396            NonZeroU32::new(4).unwrap(),
22397            false,
22398        ),
22399        "这是什\n么 钢\n"
22400    );
22401}
22402
22403pub trait CollaborationHub {
22404    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22405    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22406    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22407}
22408
22409impl CollaborationHub for Entity<Project> {
22410    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22411        self.read(cx).collaborators()
22412    }
22413
22414    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22415        self.read(cx).user_store().read(cx).participant_indices()
22416    }
22417
22418    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22419        let this = self.read(cx);
22420        let user_ids = this.collaborators().values().map(|c| c.user_id);
22421        this.user_store().read(cx).participant_names(user_ids, cx)
22422    }
22423}
22424
22425pub trait SemanticsProvider {
22426    fn hover(
22427        &self,
22428        buffer: &Entity<Buffer>,
22429        position: text::Anchor,
22430        cx: &mut App,
22431    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22432
22433    fn inline_values(
22434        &self,
22435        buffer_handle: Entity<Buffer>,
22436        range: Range<text::Anchor>,
22437        cx: &mut App,
22438    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22439
22440    fn inlay_hints(
22441        &self,
22442        buffer_handle: Entity<Buffer>,
22443        range: Range<text::Anchor>,
22444        cx: &mut App,
22445    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22446
22447    fn resolve_inlay_hint(
22448        &self,
22449        hint: InlayHint,
22450        buffer_handle: Entity<Buffer>,
22451        server_id: LanguageServerId,
22452        cx: &mut App,
22453    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22454
22455    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22456
22457    fn document_highlights(
22458        &self,
22459        buffer: &Entity<Buffer>,
22460        position: text::Anchor,
22461        cx: &mut App,
22462    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22463
22464    fn definitions(
22465        &self,
22466        buffer: &Entity<Buffer>,
22467        position: text::Anchor,
22468        kind: GotoDefinitionKind,
22469        cx: &mut App,
22470    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22471
22472    fn range_for_rename(
22473        &self,
22474        buffer: &Entity<Buffer>,
22475        position: text::Anchor,
22476        cx: &mut App,
22477    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22478
22479    fn perform_rename(
22480        &self,
22481        buffer: &Entity<Buffer>,
22482        position: text::Anchor,
22483        new_name: String,
22484        cx: &mut App,
22485    ) -> Option<Task<Result<ProjectTransaction>>>;
22486}
22487
22488pub trait CompletionProvider {
22489    fn completions(
22490        &self,
22491        excerpt_id: ExcerptId,
22492        buffer: &Entity<Buffer>,
22493        buffer_position: text::Anchor,
22494        trigger: CompletionContext,
22495        window: &mut Window,
22496        cx: &mut Context<Editor>,
22497    ) -> Task<Result<Vec<CompletionResponse>>>;
22498
22499    fn resolve_completions(
22500        &self,
22501        _buffer: Entity<Buffer>,
22502        _completion_indices: Vec<usize>,
22503        _completions: Rc<RefCell<Box<[Completion]>>>,
22504        _cx: &mut Context<Editor>,
22505    ) -> Task<Result<bool>> {
22506        Task::ready(Ok(false))
22507    }
22508
22509    fn apply_additional_edits_for_completion(
22510        &self,
22511        _buffer: Entity<Buffer>,
22512        _completions: Rc<RefCell<Box<[Completion]>>>,
22513        _completion_index: usize,
22514        _push_to_history: bool,
22515        _cx: &mut Context<Editor>,
22516    ) -> Task<Result<Option<language::Transaction>>> {
22517        Task::ready(Ok(None))
22518    }
22519
22520    fn is_completion_trigger(
22521        &self,
22522        buffer: &Entity<Buffer>,
22523        position: language::Anchor,
22524        text: &str,
22525        trigger_in_words: bool,
22526        menu_is_open: bool,
22527        cx: &mut Context<Editor>,
22528    ) -> bool;
22529
22530    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22531
22532    fn sort_completions(&self) -> bool {
22533        true
22534    }
22535
22536    fn filter_completions(&self) -> bool {
22537        true
22538    }
22539}
22540
22541pub trait CodeActionProvider {
22542    fn id(&self) -> Arc<str>;
22543
22544    fn code_actions(
22545        &self,
22546        buffer: &Entity<Buffer>,
22547        range: Range<text::Anchor>,
22548        window: &mut Window,
22549        cx: &mut App,
22550    ) -> Task<Result<Vec<CodeAction>>>;
22551
22552    fn apply_code_action(
22553        &self,
22554        buffer_handle: Entity<Buffer>,
22555        action: CodeAction,
22556        excerpt_id: ExcerptId,
22557        push_to_history: bool,
22558        window: &mut Window,
22559        cx: &mut App,
22560    ) -> Task<Result<ProjectTransaction>>;
22561}
22562
22563impl CodeActionProvider for Entity<Project> {
22564    fn id(&self) -> Arc<str> {
22565        "project".into()
22566    }
22567
22568    fn code_actions(
22569        &self,
22570        buffer: &Entity<Buffer>,
22571        range: Range<text::Anchor>,
22572        _window: &mut Window,
22573        cx: &mut App,
22574    ) -> Task<Result<Vec<CodeAction>>> {
22575        self.update(cx, |project, cx| {
22576            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22577            let code_actions = project.code_actions(buffer, range, None, cx);
22578            cx.background_spawn(async move {
22579                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22580                Ok(code_lens_actions
22581                    .context("code lens fetch")?
22582                    .into_iter()
22583                    .flatten()
22584                    .chain(
22585                        code_actions
22586                            .context("code action fetch")?
22587                            .into_iter()
22588                            .flatten(),
22589                    )
22590                    .collect())
22591            })
22592        })
22593    }
22594
22595    fn apply_code_action(
22596        &self,
22597        buffer_handle: Entity<Buffer>,
22598        action: CodeAction,
22599        _excerpt_id: ExcerptId,
22600        push_to_history: bool,
22601        _window: &mut Window,
22602        cx: &mut App,
22603    ) -> Task<Result<ProjectTransaction>> {
22604        self.update(cx, |project, cx| {
22605            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22606        })
22607    }
22608}
22609
22610fn snippet_completions(
22611    project: &Project,
22612    buffer: &Entity<Buffer>,
22613    buffer_position: text::Anchor,
22614    cx: &mut App,
22615) -> Task<Result<CompletionResponse>> {
22616    let languages = buffer.read(cx).languages_at(buffer_position);
22617    let snippet_store = project.snippets().read(cx);
22618
22619    let scopes: Vec<_> = languages
22620        .iter()
22621        .filter_map(|language| {
22622            let language_name = language.lsp_id();
22623            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22624
22625            if snippets.is_empty() {
22626                None
22627            } else {
22628                Some((language.default_scope(), snippets))
22629            }
22630        })
22631        .collect();
22632
22633    if scopes.is_empty() {
22634        return Task::ready(Ok(CompletionResponse {
22635            completions: vec![],
22636            display_options: CompletionDisplayOptions::default(),
22637            is_incomplete: false,
22638        }));
22639    }
22640
22641    let snapshot = buffer.read(cx).text_snapshot();
22642    let chars: String = snapshot
22643        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22644        .collect();
22645    let executor = cx.background_executor().clone();
22646
22647    cx.background_spawn(async move {
22648        let mut is_incomplete = false;
22649        let mut completions: Vec<Completion> = Vec::new();
22650        for (scope, snippets) in scopes.into_iter() {
22651            let classifier =
22652                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22653            let mut last_word = chars
22654                .chars()
22655                .take_while(|c| classifier.is_word(*c))
22656                .collect::<String>();
22657            last_word = last_word.chars().rev().collect();
22658
22659            if last_word.is_empty() {
22660                return Ok(CompletionResponse {
22661                    completions: vec![],
22662                    display_options: CompletionDisplayOptions::default(),
22663                    is_incomplete: true,
22664                });
22665            }
22666
22667            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22668            let to_lsp = |point: &text::Anchor| {
22669                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22670                point_to_lsp(end)
22671            };
22672            let lsp_end = to_lsp(&buffer_position);
22673
22674            let candidates = snippets
22675                .iter()
22676                .enumerate()
22677                .flat_map(|(ix, snippet)| {
22678                    snippet
22679                        .prefix
22680                        .iter()
22681                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22682                })
22683                .collect::<Vec<StringMatchCandidate>>();
22684
22685            const MAX_RESULTS: usize = 100;
22686            let mut matches = fuzzy::match_strings(
22687                &candidates,
22688                &last_word,
22689                last_word.chars().any(|c| c.is_uppercase()),
22690                true,
22691                MAX_RESULTS,
22692                &Default::default(),
22693                executor.clone(),
22694            )
22695            .await;
22696
22697            if matches.len() >= MAX_RESULTS {
22698                is_incomplete = true;
22699            }
22700
22701            // Remove all candidates where the query's start does not match the start of any word in the candidate
22702            if let Some(query_start) = last_word.chars().next() {
22703                matches.retain(|string_match| {
22704                    split_words(&string_match.string).any(|word| {
22705                        // Check that the first codepoint of the word as lowercase matches the first
22706                        // codepoint of the query as lowercase
22707                        word.chars()
22708                            .flat_map(|codepoint| codepoint.to_lowercase())
22709                            .zip(query_start.to_lowercase())
22710                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22711                    })
22712                });
22713            }
22714
22715            let matched_strings = matches
22716                .into_iter()
22717                .map(|m| m.string)
22718                .collect::<HashSet<_>>();
22719
22720            completions.extend(snippets.iter().filter_map(|snippet| {
22721                let matching_prefix = snippet
22722                    .prefix
22723                    .iter()
22724                    .find(|prefix| matched_strings.contains(*prefix))?;
22725                let start = as_offset - last_word.len();
22726                let start = snapshot.anchor_before(start);
22727                let range = start..buffer_position;
22728                let lsp_start = to_lsp(&start);
22729                let lsp_range = lsp::Range {
22730                    start: lsp_start,
22731                    end: lsp_end,
22732                };
22733                Some(Completion {
22734                    replace_range: range,
22735                    new_text: snippet.body.clone(),
22736                    source: CompletionSource::Lsp {
22737                        insert_range: None,
22738                        server_id: LanguageServerId(usize::MAX),
22739                        resolved: true,
22740                        lsp_completion: Box::new(lsp::CompletionItem {
22741                            label: snippet.prefix.first().unwrap().clone(),
22742                            kind: Some(CompletionItemKind::SNIPPET),
22743                            label_details: snippet.description.as_ref().map(|description| {
22744                                lsp::CompletionItemLabelDetails {
22745                                    detail: Some(description.clone()),
22746                                    description: None,
22747                                }
22748                            }),
22749                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22750                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22751                                lsp::InsertReplaceEdit {
22752                                    new_text: snippet.body.clone(),
22753                                    insert: lsp_range,
22754                                    replace: lsp_range,
22755                                },
22756                            )),
22757                            filter_text: Some(snippet.body.clone()),
22758                            sort_text: Some(char::MAX.to_string()),
22759                            ..lsp::CompletionItem::default()
22760                        }),
22761                        lsp_defaults: None,
22762                    },
22763                    label: CodeLabel {
22764                        text: matching_prefix.clone(),
22765                        runs: Vec::new(),
22766                        filter_range: 0..matching_prefix.len(),
22767                    },
22768                    icon_path: None,
22769                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22770                        single_line: snippet.name.clone().into(),
22771                        plain_text: snippet
22772                            .description
22773                            .clone()
22774                            .map(|description| description.into()),
22775                    }),
22776                    insert_text_mode: None,
22777                    confirm: None,
22778                })
22779            }))
22780        }
22781
22782        Ok(CompletionResponse {
22783            completions,
22784            display_options: CompletionDisplayOptions::default(),
22785            is_incomplete,
22786        })
22787    })
22788}
22789
22790impl CompletionProvider for Entity<Project> {
22791    fn completions(
22792        &self,
22793        _excerpt_id: ExcerptId,
22794        buffer: &Entity<Buffer>,
22795        buffer_position: text::Anchor,
22796        options: CompletionContext,
22797        _window: &mut Window,
22798        cx: &mut Context<Editor>,
22799    ) -> Task<Result<Vec<CompletionResponse>>> {
22800        self.update(cx, |project, cx| {
22801            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22802            let project_completions = project.completions(buffer, buffer_position, options, cx);
22803            cx.background_spawn(async move {
22804                let mut responses = project_completions.await?;
22805                let snippets = snippets.await?;
22806                if !snippets.completions.is_empty() {
22807                    responses.push(snippets);
22808                }
22809                Ok(responses)
22810            })
22811        })
22812    }
22813
22814    fn resolve_completions(
22815        &self,
22816        buffer: Entity<Buffer>,
22817        completion_indices: Vec<usize>,
22818        completions: Rc<RefCell<Box<[Completion]>>>,
22819        cx: &mut Context<Editor>,
22820    ) -> Task<Result<bool>> {
22821        self.update(cx, |project, cx| {
22822            project.lsp_store().update(cx, |lsp_store, cx| {
22823                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22824            })
22825        })
22826    }
22827
22828    fn apply_additional_edits_for_completion(
22829        &self,
22830        buffer: Entity<Buffer>,
22831        completions: Rc<RefCell<Box<[Completion]>>>,
22832        completion_index: usize,
22833        push_to_history: bool,
22834        cx: &mut Context<Editor>,
22835    ) -> Task<Result<Option<language::Transaction>>> {
22836        self.update(cx, |project, cx| {
22837            project.lsp_store().update(cx, |lsp_store, cx| {
22838                lsp_store.apply_additional_edits_for_completion(
22839                    buffer,
22840                    completions,
22841                    completion_index,
22842                    push_to_history,
22843                    cx,
22844                )
22845            })
22846        })
22847    }
22848
22849    fn is_completion_trigger(
22850        &self,
22851        buffer: &Entity<Buffer>,
22852        position: language::Anchor,
22853        text: &str,
22854        trigger_in_words: bool,
22855        menu_is_open: bool,
22856        cx: &mut Context<Editor>,
22857    ) -> bool {
22858        let mut chars = text.chars();
22859        let char = if let Some(char) = chars.next() {
22860            char
22861        } else {
22862            return false;
22863        };
22864        if chars.next().is_some() {
22865            return false;
22866        }
22867
22868        let buffer = buffer.read(cx);
22869        let snapshot = buffer.snapshot();
22870        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22871            return false;
22872        }
22873        let classifier = snapshot
22874            .char_classifier_at(position)
22875            .scope_context(Some(CharScopeContext::Completion));
22876        if trigger_in_words && classifier.is_word(char) {
22877            return true;
22878        }
22879
22880        buffer.completion_triggers().contains(text)
22881    }
22882}
22883
22884impl SemanticsProvider for Entity<Project> {
22885    fn hover(
22886        &self,
22887        buffer: &Entity<Buffer>,
22888        position: text::Anchor,
22889        cx: &mut App,
22890    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22891        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22892    }
22893
22894    fn document_highlights(
22895        &self,
22896        buffer: &Entity<Buffer>,
22897        position: text::Anchor,
22898        cx: &mut App,
22899    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22900        Some(self.update(cx, |project, cx| {
22901            project.document_highlights(buffer, position, cx)
22902        }))
22903    }
22904
22905    fn definitions(
22906        &self,
22907        buffer: &Entity<Buffer>,
22908        position: text::Anchor,
22909        kind: GotoDefinitionKind,
22910        cx: &mut App,
22911    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22912        Some(self.update(cx, |project, cx| match kind {
22913            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22914            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22915            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22916            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22917        }))
22918    }
22919
22920    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22921        self.update(cx, |project, cx| {
22922            if project
22923                .active_debug_session(cx)
22924                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22925            {
22926                return true;
22927            }
22928
22929            buffer.update(cx, |buffer, cx| {
22930                project.any_language_server_supports_inlay_hints(buffer, cx)
22931            })
22932        })
22933    }
22934
22935    fn inline_values(
22936        &self,
22937        buffer_handle: Entity<Buffer>,
22938        range: Range<text::Anchor>,
22939        cx: &mut App,
22940    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22941        self.update(cx, |project, cx| {
22942            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22943
22944            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22945        })
22946    }
22947
22948    fn inlay_hints(
22949        &self,
22950        buffer_handle: Entity<Buffer>,
22951        range: Range<text::Anchor>,
22952        cx: &mut App,
22953    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22954        Some(self.update(cx, |project, cx| {
22955            project.inlay_hints(buffer_handle, range, cx)
22956        }))
22957    }
22958
22959    fn resolve_inlay_hint(
22960        &self,
22961        hint: InlayHint,
22962        buffer_handle: Entity<Buffer>,
22963        server_id: LanguageServerId,
22964        cx: &mut App,
22965    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22966        Some(self.update(cx, |project, cx| {
22967            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22968        }))
22969    }
22970
22971    fn range_for_rename(
22972        &self,
22973        buffer: &Entity<Buffer>,
22974        position: text::Anchor,
22975        cx: &mut App,
22976    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22977        Some(self.update(cx, |project, cx| {
22978            let buffer = buffer.clone();
22979            let task = project.prepare_rename(buffer.clone(), position, cx);
22980            cx.spawn(async move |_, cx| {
22981                Ok(match task.await? {
22982                    PrepareRenameResponse::Success(range) => Some(range),
22983                    PrepareRenameResponse::InvalidPosition => None,
22984                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22985                        // Fallback on using TreeSitter info to determine identifier range
22986                        buffer.read_with(cx, |buffer, _| {
22987                            let snapshot = buffer.snapshot();
22988                            let (range, kind) = snapshot.surrounding_word(position, None);
22989                            if kind != Some(CharKind::Word) {
22990                                return None;
22991                            }
22992                            Some(
22993                                snapshot.anchor_before(range.start)
22994                                    ..snapshot.anchor_after(range.end),
22995                            )
22996                        })?
22997                    }
22998                })
22999            })
23000        }))
23001    }
23002
23003    fn perform_rename(
23004        &self,
23005        buffer: &Entity<Buffer>,
23006        position: text::Anchor,
23007        new_name: String,
23008        cx: &mut App,
23009    ) -> Option<Task<Result<ProjectTransaction>>> {
23010        Some(self.update(cx, |project, cx| {
23011            project.perform_rename(buffer.clone(), position, new_name, cx)
23012        }))
23013    }
23014}
23015
23016fn inlay_hint_settings(
23017    location: Anchor,
23018    snapshot: &MultiBufferSnapshot,
23019    cx: &mut Context<Editor>,
23020) -> InlayHintSettings {
23021    let file = snapshot.file_at(location);
23022    let language = snapshot.language_at(location).map(|l| l.name());
23023    language_settings(language, file, cx).inlay_hints
23024}
23025
23026fn consume_contiguous_rows(
23027    contiguous_row_selections: &mut Vec<Selection<Point>>,
23028    selection: &Selection<Point>,
23029    display_map: &DisplaySnapshot,
23030    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23031) -> (MultiBufferRow, MultiBufferRow) {
23032    contiguous_row_selections.push(selection.clone());
23033    let start_row = starting_row(selection, display_map);
23034    let mut end_row = ending_row(selection, display_map);
23035
23036    while let Some(next_selection) = selections.peek() {
23037        if next_selection.start.row <= end_row.0 {
23038            end_row = ending_row(next_selection, display_map);
23039            contiguous_row_selections.push(selections.next().unwrap().clone());
23040        } else {
23041            break;
23042        }
23043    }
23044    (start_row, end_row)
23045}
23046
23047fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23048    if selection.start.column > 0 {
23049        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23050    } else {
23051        MultiBufferRow(selection.start.row)
23052    }
23053}
23054
23055fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23056    if next_selection.end.column > 0 || next_selection.is_empty() {
23057        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23058    } else {
23059        MultiBufferRow(next_selection.end.row)
23060    }
23061}
23062
23063impl EditorSnapshot {
23064    pub fn remote_selections_in_range<'a>(
23065        &'a self,
23066        range: &'a Range<Anchor>,
23067        collaboration_hub: &dyn CollaborationHub,
23068        cx: &'a App,
23069    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23070        let participant_names = collaboration_hub.user_names(cx);
23071        let participant_indices = collaboration_hub.user_participant_indices(cx);
23072        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23073        let collaborators_by_replica_id = collaborators_by_peer_id
23074            .values()
23075            .map(|collaborator| (collaborator.replica_id, collaborator))
23076            .collect::<HashMap<_, _>>();
23077        self.buffer_snapshot
23078            .selections_in_range(range, false)
23079            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23080                if replica_id == AGENT_REPLICA_ID {
23081                    Some(RemoteSelection {
23082                        replica_id,
23083                        selection,
23084                        cursor_shape,
23085                        line_mode,
23086                        collaborator_id: CollaboratorId::Agent,
23087                        user_name: Some("Agent".into()),
23088                        color: cx.theme().players().agent(),
23089                    })
23090                } else {
23091                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23092                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23093                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23094                    Some(RemoteSelection {
23095                        replica_id,
23096                        selection,
23097                        cursor_shape,
23098                        line_mode,
23099                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23100                        user_name,
23101                        color: if let Some(index) = participant_index {
23102                            cx.theme().players().color_for_participant(index.0)
23103                        } else {
23104                            cx.theme().players().absent()
23105                        },
23106                    })
23107                }
23108            })
23109    }
23110
23111    pub fn hunks_for_ranges(
23112        &self,
23113        ranges: impl IntoIterator<Item = Range<Point>>,
23114    ) -> Vec<MultiBufferDiffHunk> {
23115        let mut hunks = Vec::new();
23116        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23117            HashMap::default();
23118        for query_range in ranges {
23119            let query_rows =
23120                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23121            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23122                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23123            ) {
23124                // Include deleted hunks that are adjacent to the query range, because
23125                // otherwise they would be missed.
23126                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23127                if hunk.status().is_deleted() {
23128                    intersects_range |= hunk.row_range.start == query_rows.end;
23129                    intersects_range |= hunk.row_range.end == query_rows.start;
23130                }
23131                if intersects_range {
23132                    if !processed_buffer_rows
23133                        .entry(hunk.buffer_id)
23134                        .or_default()
23135                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23136                    {
23137                        continue;
23138                    }
23139                    hunks.push(hunk);
23140                }
23141            }
23142        }
23143
23144        hunks
23145    }
23146
23147    fn display_diff_hunks_for_rows<'a>(
23148        &'a self,
23149        display_rows: Range<DisplayRow>,
23150        folded_buffers: &'a HashSet<BufferId>,
23151    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23152        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23153        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23154
23155        self.buffer_snapshot
23156            .diff_hunks_in_range(buffer_start..buffer_end)
23157            .filter_map(|hunk| {
23158                if folded_buffers.contains(&hunk.buffer_id) {
23159                    return None;
23160                }
23161
23162                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23163                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23164
23165                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23166                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23167
23168                let display_hunk = if hunk_display_start.column() != 0 {
23169                    DisplayDiffHunk::Folded {
23170                        display_row: hunk_display_start.row(),
23171                    }
23172                } else {
23173                    let mut end_row = hunk_display_end.row();
23174                    if hunk_display_end.column() > 0 {
23175                        end_row.0 += 1;
23176                    }
23177                    let is_created_file = hunk.is_created_file();
23178                    DisplayDiffHunk::Unfolded {
23179                        status: hunk.status(),
23180                        diff_base_byte_range: hunk.diff_base_byte_range,
23181                        display_row_range: hunk_display_start.row()..end_row,
23182                        multi_buffer_range: Anchor::range_in_buffer(
23183                            hunk.excerpt_id,
23184                            hunk.buffer_id,
23185                            hunk.buffer_range,
23186                        ),
23187                        is_created_file,
23188                    }
23189                };
23190
23191                Some(display_hunk)
23192            })
23193    }
23194
23195    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23196        self.display_snapshot.buffer_snapshot.language_at(position)
23197    }
23198
23199    pub fn is_focused(&self) -> bool {
23200        self.is_focused
23201    }
23202
23203    pub fn placeholder_text(&self) -> Option<String> {
23204        self.placeholder_display_snapshot
23205            .as_ref()
23206            .map(|display_map| display_map.text())
23207    }
23208
23209    pub fn scroll_position(&self) -> gpui::Point<f32> {
23210        self.scroll_anchor.scroll_position(&self.display_snapshot)
23211    }
23212
23213    fn gutter_dimensions(
23214        &self,
23215        font_id: FontId,
23216        font_size: Pixels,
23217        max_line_number_width: Pixels,
23218        cx: &App,
23219    ) -> Option<GutterDimensions> {
23220        if !self.show_gutter {
23221            return None;
23222        }
23223
23224        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23225        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23226
23227        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23228            matches!(
23229                ProjectSettings::get_global(cx).git.git_gutter,
23230                GitGutterSetting::TrackedFiles
23231            )
23232        });
23233        let gutter_settings = EditorSettings::get_global(cx).gutter;
23234        let show_line_numbers = self
23235            .show_line_numbers
23236            .unwrap_or(gutter_settings.line_numbers);
23237        let line_gutter_width = if show_line_numbers {
23238            // Avoid flicker-like gutter resizes when the line number gains another digit by
23239            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23240            let min_width_for_number_on_gutter =
23241                ch_advance * gutter_settings.min_line_number_digits as f32;
23242            max_line_number_width.max(min_width_for_number_on_gutter)
23243        } else {
23244            0.0.into()
23245        };
23246
23247        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23248        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23249
23250        let git_blame_entries_width =
23251            self.git_blame_gutter_max_author_length
23252                .map(|max_author_length| {
23253                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23254                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23255
23256                    /// The number of characters to dedicate to gaps and margins.
23257                    const SPACING_WIDTH: usize = 4;
23258
23259                    let max_char_count = max_author_length.min(renderer.max_author_length())
23260                        + ::git::SHORT_SHA_LENGTH
23261                        + MAX_RELATIVE_TIMESTAMP.len()
23262                        + SPACING_WIDTH;
23263
23264                    ch_advance * max_char_count
23265                });
23266
23267        let is_singleton = self.buffer_snapshot.is_singleton();
23268
23269        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23270        left_padding += if !is_singleton {
23271            ch_width * 4.0
23272        } else if show_runnables || show_breakpoints {
23273            ch_width * 3.0
23274        } else if show_git_gutter && show_line_numbers {
23275            ch_width * 2.0
23276        } else if show_git_gutter || show_line_numbers {
23277            ch_width
23278        } else {
23279            px(0.)
23280        };
23281
23282        let shows_folds = is_singleton && gutter_settings.folds;
23283
23284        let right_padding = if shows_folds && show_line_numbers {
23285            ch_width * 4.0
23286        } else if shows_folds || (!is_singleton && show_line_numbers) {
23287            ch_width * 3.0
23288        } else if show_line_numbers {
23289            ch_width
23290        } else {
23291            px(0.)
23292        };
23293
23294        Some(GutterDimensions {
23295            left_padding,
23296            right_padding,
23297            width: line_gutter_width + left_padding + right_padding,
23298            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23299            git_blame_entries_width,
23300        })
23301    }
23302
23303    pub fn render_crease_toggle(
23304        &self,
23305        buffer_row: MultiBufferRow,
23306        row_contains_cursor: bool,
23307        editor: Entity<Editor>,
23308        window: &mut Window,
23309        cx: &mut App,
23310    ) -> Option<AnyElement> {
23311        let folded = self.is_line_folded(buffer_row);
23312        let mut is_foldable = false;
23313
23314        if let Some(crease) = self
23315            .crease_snapshot
23316            .query_row(buffer_row, &self.buffer_snapshot)
23317        {
23318            is_foldable = true;
23319            match crease {
23320                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23321                    if let Some(render_toggle) = render_toggle {
23322                        let toggle_callback =
23323                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23324                                if folded {
23325                                    editor.update(cx, |editor, cx| {
23326                                        editor.fold_at(buffer_row, window, cx)
23327                                    });
23328                                } else {
23329                                    editor.update(cx, |editor, cx| {
23330                                        editor.unfold_at(buffer_row, window, cx)
23331                                    });
23332                                }
23333                            });
23334                        return Some((render_toggle)(
23335                            buffer_row,
23336                            folded,
23337                            toggle_callback,
23338                            window,
23339                            cx,
23340                        ));
23341                    }
23342                }
23343            }
23344        }
23345
23346        is_foldable |= self.starts_indent(buffer_row);
23347
23348        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23349            Some(
23350                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23351                    .toggle_state(folded)
23352                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23353                        if folded {
23354                            this.unfold_at(buffer_row, window, cx);
23355                        } else {
23356                            this.fold_at(buffer_row, window, cx);
23357                        }
23358                    }))
23359                    .into_any_element(),
23360            )
23361        } else {
23362            None
23363        }
23364    }
23365
23366    pub fn render_crease_trailer(
23367        &self,
23368        buffer_row: MultiBufferRow,
23369        window: &mut Window,
23370        cx: &mut App,
23371    ) -> Option<AnyElement> {
23372        let folded = self.is_line_folded(buffer_row);
23373        if let Crease::Inline { render_trailer, .. } = self
23374            .crease_snapshot
23375            .query_row(buffer_row, &self.buffer_snapshot)?
23376        {
23377            let render_trailer = render_trailer.as_ref()?;
23378            Some(render_trailer(buffer_row, folded, window, cx))
23379        } else {
23380            None
23381        }
23382    }
23383}
23384
23385impl Deref for EditorSnapshot {
23386    type Target = DisplaySnapshot;
23387
23388    fn deref(&self) -> &Self::Target {
23389        &self.display_snapshot
23390    }
23391}
23392
23393#[derive(Clone, Debug, PartialEq, Eq)]
23394pub enum EditorEvent {
23395    InputIgnored {
23396        text: Arc<str>,
23397    },
23398    InputHandled {
23399        utf16_range_to_replace: Option<Range<isize>>,
23400        text: Arc<str>,
23401    },
23402    ExcerptsAdded {
23403        buffer: Entity<Buffer>,
23404        predecessor: ExcerptId,
23405        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23406    },
23407    ExcerptsRemoved {
23408        ids: Vec<ExcerptId>,
23409        removed_buffer_ids: Vec<BufferId>,
23410    },
23411    BufferFoldToggled {
23412        ids: Vec<ExcerptId>,
23413        folded: bool,
23414    },
23415    ExcerptsEdited {
23416        ids: Vec<ExcerptId>,
23417    },
23418    ExcerptsExpanded {
23419        ids: Vec<ExcerptId>,
23420    },
23421    BufferEdited,
23422    Edited {
23423        transaction_id: clock::Lamport,
23424    },
23425    Reparsed(BufferId),
23426    Focused,
23427    FocusedIn,
23428    Blurred,
23429    DirtyChanged,
23430    Saved,
23431    TitleChanged,
23432    SelectionsChanged {
23433        local: bool,
23434    },
23435    ScrollPositionChanged {
23436        local: bool,
23437        autoscroll: bool,
23438    },
23439    TransactionUndone {
23440        transaction_id: clock::Lamport,
23441    },
23442    TransactionBegun {
23443        transaction_id: clock::Lamport,
23444    },
23445    CursorShapeChanged,
23446    BreadcrumbsChanged,
23447    PushedToNavHistory {
23448        anchor: Anchor,
23449        is_deactivate: bool,
23450    },
23451}
23452
23453impl EventEmitter<EditorEvent> for Editor {}
23454
23455impl Focusable for Editor {
23456    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23457        self.focus_handle.clone()
23458    }
23459}
23460
23461impl Render for Editor {
23462    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23463        let settings = ThemeSettings::get_global(cx);
23464
23465        let mut text_style = match self.mode {
23466            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23467                color: cx.theme().colors().editor_foreground,
23468                font_family: settings.ui_font.family.clone(),
23469                font_features: settings.ui_font.features.clone(),
23470                font_fallbacks: settings.ui_font.fallbacks.clone(),
23471                font_size: rems(0.875).into(),
23472                font_weight: settings.ui_font.weight,
23473                line_height: relative(settings.buffer_line_height.value()),
23474                ..Default::default()
23475            },
23476            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23477                color: cx.theme().colors().editor_foreground,
23478                font_family: settings.buffer_font.family.clone(),
23479                font_features: settings.buffer_font.features.clone(),
23480                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23481                font_size: settings.buffer_font_size(cx).into(),
23482                font_weight: settings.buffer_font.weight,
23483                line_height: relative(settings.buffer_line_height.value()),
23484                ..Default::default()
23485            },
23486        };
23487        if let Some(text_style_refinement) = &self.text_style_refinement {
23488            text_style.refine(text_style_refinement)
23489        }
23490
23491        let background = match self.mode {
23492            EditorMode::SingleLine => cx.theme().system().transparent,
23493            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23494            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23495            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23496        };
23497
23498        EditorElement::new(
23499            &cx.entity(),
23500            EditorStyle {
23501                background,
23502                border: cx.theme().colors().border,
23503                local_player: cx.theme().players().local(),
23504                text: text_style,
23505                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23506                syntax: cx.theme().syntax().clone(),
23507                status: cx.theme().status().clone(),
23508                inlay_hints_style: make_inlay_hints_style(cx),
23509                edit_prediction_styles: make_suggestion_styles(cx),
23510                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23511                show_underlines: self.diagnostics_enabled(),
23512            },
23513        )
23514    }
23515}
23516
23517impl EntityInputHandler for Editor {
23518    fn text_for_range(
23519        &mut self,
23520        range_utf16: Range<usize>,
23521        adjusted_range: &mut Option<Range<usize>>,
23522        _: &mut Window,
23523        cx: &mut Context<Self>,
23524    ) -> Option<String> {
23525        let snapshot = self.buffer.read(cx).read(cx);
23526        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23527        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23528        if (start.0..end.0) != range_utf16 {
23529            adjusted_range.replace(start.0..end.0);
23530        }
23531        Some(snapshot.text_for_range(start..end).collect())
23532    }
23533
23534    fn selected_text_range(
23535        &mut self,
23536        ignore_disabled_input: bool,
23537        _: &mut Window,
23538        cx: &mut Context<Self>,
23539    ) -> Option<UTF16Selection> {
23540        // Prevent the IME menu from appearing when holding down an alphabetic key
23541        // while input is disabled.
23542        if !ignore_disabled_input && !self.input_enabled {
23543            return None;
23544        }
23545
23546        let selection = self.selections.newest::<OffsetUtf16>(cx);
23547        let range = selection.range();
23548
23549        Some(UTF16Selection {
23550            range: range.start.0..range.end.0,
23551            reversed: selection.reversed,
23552        })
23553    }
23554
23555    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23556        let snapshot = self.buffer.read(cx).read(cx);
23557        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23558        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23559    }
23560
23561    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23562        self.clear_highlights::<InputComposition>(cx);
23563        self.ime_transaction.take();
23564    }
23565
23566    fn replace_text_in_range(
23567        &mut self,
23568        range_utf16: Option<Range<usize>>,
23569        text: &str,
23570        window: &mut Window,
23571        cx: &mut Context<Self>,
23572    ) {
23573        if !self.input_enabled {
23574            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23575            return;
23576        }
23577
23578        self.transact(window, cx, |this, window, cx| {
23579            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23580                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23581                Some(this.selection_replacement_ranges(range_utf16, cx))
23582            } else {
23583                this.marked_text_ranges(cx)
23584            };
23585
23586            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23587                let newest_selection_id = this.selections.newest_anchor().id;
23588                this.selections
23589                    .all::<OffsetUtf16>(cx)
23590                    .iter()
23591                    .zip(ranges_to_replace.iter())
23592                    .find_map(|(selection, range)| {
23593                        if selection.id == newest_selection_id {
23594                            Some(
23595                                (range.start.0 as isize - selection.head().0 as isize)
23596                                    ..(range.end.0 as isize - selection.head().0 as isize),
23597                            )
23598                        } else {
23599                            None
23600                        }
23601                    })
23602            });
23603
23604            cx.emit(EditorEvent::InputHandled {
23605                utf16_range_to_replace: range_to_replace,
23606                text: text.into(),
23607            });
23608
23609            if let Some(new_selected_ranges) = new_selected_ranges {
23610                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23611                    selections.select_ranges(new_selected_ranges)
23612                });
23613                this.backspace(&Default::default(), window, cx);
23614            }
23615
23616            this.handle_input(text, window, cx);
23617        });
23618
23619        if let Some(transaction) = self.ime_transaction {
23620            self.buffer.update(cx, |buffer, cx| {
23621                buffer.group_until_transaction(transaction, cx);
23622            });
23623        }
23624
23625        self.unmark_text(window, cx);
23626    }
23627
23628    fn replace_and_mark_text_in_range(
23629        &mut self,
23630        range_utf16: Option<Range<usize>>,
23631        text: &str,
23632        new_selected_range_utf16: Option<Range<usize>>,
23633        window: &mut Window,
23634        cx: &mut Context<Self>,
23635    ) {
23636        if !self.input_enabled {
23637            return;
23638        }
23639
23640        let transaction = self.transact(window, cx, |this, window, cx| {
23641            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23642                let snapshot = this.buffer.read(cx).read(cx);
23643                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23644                    for marked_range in &mut marked_ranges {
23645                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23646                        marked_range.start.0 += relative_range_utf16.start;
23647                        marked_range.start =
23648                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23649                        marked_range.end =
23650                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23651                    }
23652                }
23653                Some(marked_ranges)
23654            } else if let Some(range_utf16) = range_utf16 {
23655                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23656                Some(this.selection_replacement_ranges(range_utf16, cx))
23657            } else {
23658                None
23659            };
23660
23661            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23662                let newest_selection_id = this.selections.newest_anchor().id;
23663                this.selections
23664                    .all::<OffsetUtf16>(cx)
23665                    .iter()
23666                    .zip(ranges_to_replace.iter())
23667                    .find_map(|(selection, range)| {
23668                        if selection.id == newest_selection_id {
23669                            Some(
23670                                (range.start.0 as isize - selection.head().0 as isize)
23671                                    ..(range.end.0 as isize - selection.head().0 as isize),
23672                            )
23673                        } else {
23674                            None
23675                        }
23676                    })
23677            });
23678
23679            cx.emit(EditorEvent::InputHandled {
23680                utf16_range_to_replace: range_to_replace,
23681                text: text.into(),
23682            });
23683
23684            if let Some(ranges) = ranges_to_replace {
23685                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23686                    s.select_ranges(ranges)
23687                });
23688            }
23689
23690            let marked_ranges = {
23691                let snapshot = this.buffer.read(cx).read(cx);
23692                this.selections
23693                    .disjoint_anchors_arc()
23694                    .iter()
23695                    .map(|selection| {
23696                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23697                    })
23698                    .collect::<Vec<_>>()
23699            };
23700
23701            if text.is_empty() {
23702                this.unmark_text(window, cx);
23703            } else {
23704                this.highlight_text::<InputComposition>(
23705                    marked_ranges.clone(),
23706                    HighlightStyle {
23707                        underline: Some(UnderlineStyle {
23708                            thickness: px(1.),
23709                            color: None,
23710                            wavy: false,
23711                        }),
23712                        ..Default::default()
23713                    },
23714                    cx,
23715                );
23716            }
23717
23718            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23719            let use_autoclose = this.use_autoclose;
23720            let use_auto_surround = this.use_auto_surround;
23721            this.set_use_autoclose(false);
23722            this.set_use_auto_surround(false);
23723            this.handle_input(text, window, cx);
23724            this.set_use_autoclose(use_autoclose);
23725            this.set_use_auto_surround(use_auto_surround);
23726
23727            if let Some(new_selected_range) = new_selected_range_utf16 {
23728                let snapshot = this.buffer.read(cx).read(cx);
23729                let new_selected_ranges = marked_ranges
23730                    .into_iter()
23731                    .map(|marked_range| {
23732                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23733                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23734                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23735                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23736                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23737                    })
23738                    .collect::<Vec<_>>();
23739
23740                drop(snapshot);
23741                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23742                    selections.select_ranges(new_selected_ranges)
23743                });
23744            }
23745        });
23746
23747        self.ime_transaction = self.ime_transaction.or(transaction);
23748        if let Some(transaction) = self.ime_transaction {
23749            self.buffer.update(cx, |buffer, cx| {
23750                buffer.group_until_transaction(transaction, cx);
23751            });
23752        }
23753
23754        if self.text_highlights::<InputComposition>(cx).is_none() {
23755            self.ime_transaction.take();
23756        }
23757    }
23758
23759    fn bounds_for_range(
23760        &mut self,
23761        range_utf16: Range<usize>,
23762        element_bounds: gpui::Bounds<Pixels>,
23763        window: &mut Window,
23764        cx: &mut Context<Self>,
23765    ) -> Option<gpui::Bounds<Pixels>> {
23766        let text_layout_details = self.text_layout_details(window);
23767        let CharacterDimensions {
23768            em_width,
23769            em_advance,
23770            line_height,
23771        } = self.character_dimensions(window);
23772
23773        let snapshot = self.snapshot(window, cx);
23774        let scroll_position = snapshot.scroll_position();
23775        let scroll_left = scroll_position.x * em_advance;
23776
23777        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23778        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23779            + self.gutter_dimensions.full_width();
23780        let y = line_height * (start.row().as_f32() - scroll_position.y);
23781
23782        Some(Bounds {
23783            origin: element_bounds.origin + point(x, y),
23784            size: size(em_width, line_height),
23785        })
23786    }
23787
23788    fn character_index_for_point(
23789        &mut self,
23790        point: gpui::Point<Pixels>,
23791        _window: &mut Window,
23792        _cx: &mut Context<Self>,
23793    ) -> Option<usize> {
23794        let position_map = self.last_position_map.as_ref()?;
23795        if !position_map.text_hitbox.contains(&point) {
23796            return None;
23797        }
23798        let display_point = position_map.point_for_position(point).previous_valid;
23799        let anchor = position_map
23800            .snapshot
23801            .display_point_to_anchor(display_point, Bias::Left);
23802        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23803        Some(utf16_offset.0)
23804    }
23805}
23806
23807trait SelectionExt {
23808    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23809    fn spanned_rows(
23810        &self,
23811        include_end_if_at_line_start: bool,
23812        map: &DisplaySnapshot,
23813    ) -> Range<MultiBufferRow>;
23814}
23815
23816impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23817    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23818        let start = self
23819            .start
23820            .to_point(&map.buffer_snapshot)
23821            .to_display_point(map);
23822        let end = self
23823            .end
23824            .to_point(&map.buffer_snapshot)
23825            .to_display_point(map);
23826        if self.reversed {
23827            end..start
23828        } else {
23829            start..end
23830        }
23831    }
23832
23833    fn spanned_rows(
23834        &self,
23835        include_end_if_at_line_start: bool,
23836        map: &DisplaySnapshot,
23837    ) -> Range<MultiBufferRow> {
23838        let start = self.start.to_point(&map.buffer_snapshot);
23839        let mut end = self.end.to_point(&map.buffer_snapshot);
23840        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23841            end.row -= 1;
23842        }
23843
23844        let buffer_start = map.prev_line_boundary(start).0;
23845        let buffer_end = map.next_line_boundary(end).0;
23846        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23847    }
23848}
23849
23850impl<T: InvalidationRegion> InvalidationStack<T> {
23851    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23852    where
23853        S: Clone + ToOffset,
23854    {
23855        while let Some(region) = self.last() {
23856            let all_selections_inside_invalidation_ranges =
23857                if selections.len() == region.ranges().len() {
23858                    selections
23859                        .iter()
23860                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23861                        .all(|(selection, invalidation_range)| {
23862                            let head = selection.head().to_offset(buffer);
23863                            invalidation_range.start <= head && invalidation_range.end >= head
23864                        })
23865                } else {
23866                    false
23867                };
23868
23869            if all_selections_inside_invalidation_ranges {
23870                break;
23871            } else {
23872                self.pop();
23873            }
23874        }
23875    }
23876}
23877
23878impl<T> Default for InvalidationStack<T> {
23879    fn default() -> Self {
23880        Self(Default::default())
23881    }
23882}
23883
23884impl<T> Deref for InvalidationStack<T> {
23885    type Target = Vec<T>;
23886
23887    fn deref(&self) -> &Self::Target {
23888        &self.0
23889    }
23890}
23891
23892impl<T> DerefMut for InvalidationStack<T> {
23893    fn deref_mut(&mut self) -> &mut Self::Target {
23894        &mut self.0
23895    }
23896}
23897
23898impl InvalidationRegion for SnippetState {
23899    fn ranges(&self) -> &[Range<Anchor>] {
23900        &self.ranges[self.active_index]
23901    }
23902}
23903
23904fn edit_prediction_edit_text(
23905    current_snapshot: &BufferSnapshot,
23906    edits: &[(Range<Anchor>, String)],
23907    edit_preview: &EditPreview,
23908    include_deletions: bool,
23909    cx: &App,
23910) -> HighlightedText {
23911    let edits = edits
23912        .iter()
23913        .map(|(anchor, text)| {
23914            (
23915                anchor.start.text_anchor..anchor.end.text_anchor,
23916                text.clone(),
23917            )
23918        })
23919        .collect::<Vec<_>>();
23920
23921    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23922}
23923
23924fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23925    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23926    // Just show the raw edit text with basic styling
23927    let mut text = String::new();
23928    let mut highlights = Vec::new();
23929
23930    let insertion_highlight_style = HighlightStyle {
23931        color: Some(cx.theme().colors().text),
23932        ..Default::default()
23933    };
23934
23935    for (_, edit_text) in edits {
23936        let start_offset = text.len();
23937        text.push_str(edit_text);
23938        let end_offset = text.len();
23939
23940        if start_offset < end_offset {
23941            highlights.push((start_offset..end_offset, insertion_highlight_style));
23942        }
23943    }
23944
23945    HighlightedText {
23946        text: text.into(),
23947        highlights,
23948    }
23949}
23950
23951pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23952    match severity {
23953        lsp::DiagnosticSeverity::ERROR => colors.error,
23954        lsp::DiagnosticSeverity::WARNING => colors.warning,
23955        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23956        lsp::DiagnosticSeverity::HINT => colors.info,
23957        _ => colors.ignored,
23958    }
23959}
23960
23961pub fn styled_runs_for_code_label<'a>(
23962    label: &'a CodeLabel,
23963    syntax_theme: &'a theme::SyntaxTheme,
23964) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23965    let fade_out = HighlightStyle {
23966        fade_out: Some(0.35),
23967        ..Default::default()
23968    };
23969
23970    let mut prev_end = label.filter_range.end;
23971    label
23972        .runs
23973        .iter()
23974        .enumerate()
23975        .flat_map(move |(ix, (range, highlight_id))| {
23976            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23977                style
23978            } else {
23979                return Default::default();
23980            };
23981            let muted_style = style.highlight(fade_out);
23982
23983            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23984            if range.start >= label.filter_range.end {
23985                if range.start > prev_end {
23986                    runs.push((prev_end..range.start, fade_out));
23987                }
23988                runs.push((range.clone(), muted_style));
23989            } else if range.end <= label.filter_range.end {
23990                runs.push((range.clone(), style));
23991            } else {
23992                runs.push((range.start..label.filter_range.end, style));
23993                runs.push((label.filter_range.end..range.end, muted_style));
23994            }
23995            prev_end = cmp::max(prev_end, range.end);
23996
23997            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23998                runs.push((prev_end..label.text.len(), fade_out));
23999            }
24000
24001            runs
24002        })
24003}
24004
24005pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24006    let mut prev_index = 0;
24007    let mut prev_codepoint: Option<char> = None;
24008    text.char_indices()
24009        .chain([(text.len(), '\0')])
24010        .filter_map(move |(index, codepoint)| {
24011            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24012            let is_boundary = index == text.len()
24013                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24014                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24015            if is_boundary {
24016                let chunk = &text[prev_index..index];
24017                prev_index = index;
24018                Some(chunk)
24019            } else {
24020                None
24021            }
24022        })
24023}
24024
24025pub trait RangeToAnchorExt: Sized {
24026    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24027
24028    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24029        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24030        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24031    }
24032}
24033
24034impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24035    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24036        let start_offset = self.start.to_offset(snapshot);
24037        let end_offset = self.end.to_offset(snapshot);
24038        if start_offset == end_offset {
24039            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24040        } else {
24041            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24042        }
24043    }
24044}
24045
24046pub trait RowExt {
24047    fn as_f32(&self) -> f32;
24048
24049    fn next_row(&self) -> Self;
24050
24051    fn previous_row(&self) -> Self;
24052
24053    fn minus(&self, other: Self) -> u32;
24054}
24055
24056impl RowExt for DisplayRow {
24057    fn as_f32(&self) -> f32 {
24058        self.0 as f32
24059    }
24060
24061    fn next_row(&self) -> Self {
24062        Self(self.0 + 1)
24063    }
24064
24065    fn previous_row(&self) -> Self {
24066        Self(self.0.saturating_sub(1))
24067    }
24068
24069    fn minus(&self, other: Self) -> u32 {
24070        self.0 - other.0
24071    }
24072}
24073
24074impl RowExt for MultiBufferRow {
24075    fn as_f32(&self) -> f32 {
24076        self.0 as f32
24077    }
24078
24079    fn next_row(&self) -> Self {
24080        Self(self.0 + 1)
24081    }
24082
24083    fn previous_row(&self) -> Self {
24084        Self(self.0.saturating_sub(1))
24085    }
24086
24087    fn minus(&self, other: Self) -> u32 {
24088        self.0 - other.0
24089    }
24090}
24091
24092trait RowRangeExt {
24093    type Row;
24094
24095    fn len(&self) -> usize;
24096
24097    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24098}
24099
24100impl RowRangeExt for Range<MultiBufferRow> {
24101    type Row = MultiBufferRow;
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 = MultiBufferRow> {
24108        (self.start.0..self.end.0).map(MultiBufferRow)
24109    }
24110}
24111
24112impl RowRangeExt for Range<DisplayRow> {
24113    type Row = DisplayRow;
24114
24115    fn len(&self) -> usize {
24116        (self.end.0 - self.start.0) as usize
24117    }
24118
24119    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24120        (self.start.0..self.end.0).map(DisplayRow)
24121    }
24122}
24123
24124/// If select range has more than one line, we
24125/// just point the cursor to range.start.
24126fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24127    if range.start.row == range.end.row {
24128        range
24129    } else {
24130        range.start..range.start
24131    }
24132}
24133pub struct KillRing(ClipboardItem);
24134impl Global for KillRing {}
24135
24136const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24137
24138enum BreakpointPromptEditAction {
24139    Log,
24140    Condition,
24141    HitCondition,
24142}
24143
24144struct BreakpointPromptEditor {
24145    pub(crate) prompt: Entity<Editor>,
24146    editor: WeakEntity<Editor>,
24147    breakpoint_anchor: Anchor,
24148    breakpoint: Breakpoint,
24149    edit_action: BreakpointPromptEditAction,
24150    block_ids: HashSet<CustomBlockId>,
24151    editor_margins: Arc<Mutex<EditorMargins>>,
24152    _subscriptions: Vec<Subscription>,
24153}
24154
24155impl BreakpointPromptEditor {
24156    const MAX_LINES: u8 = 4;
24157
24158    fn new(
24159        editor: WeakEntity<Editor>,
24160        breakpoint_anchor: Anchor,
24161        breakpoint: Breakpoint,
24162        edit_action: BreakpointPromptEditAction,
24163        window: &mut Window,
24164        cx: &mut Context<Self>,
24165    ) -> Self {
24166        let base_text = match edit_action {
24167            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24168            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24169            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24170        }
24171        .map(|msg| msg.to_string())
24172        .unwrap_or_default();
24173
24174        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24175        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24176
24177        let prompt = cx.new(|cx| {
24178            let mut prompt = Editor::new(
24179                EditorMode::AutoHeight {
24180                    min_lines: 1,
24181                    max_lines: Some(Self::MAX_LINES as usize),
24182                },
24183                buffer,
24184                None,
24185                window,
24186                cx,
24187            );
24188            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24189            prompt.set_show_cursor_when_unfocused(false, cx);
24190            prompt.set_placeholder_text(
24191                match edit_action {
24192                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24193                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24194                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24195                },
24196                window,
24197                cx,
24198            );
24199
24200            prompt
24201        });
24202
24203        Self {
24204            prompt,
24205            editor,
24206            breakpoint_anchor,
24207            breakpoint,
24208            edit_action,
24209            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24210            block_ids: Default::default(),
24211            _subscriptions: vec![],
24212        }
24213    }
24214
24215    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24216        self.block_ids.extend(block_ids)
24217    }
24218
24219    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24220        if let Some(editor) = self.editor.upgrade() {
24221            let message = self
24222                .prompt
24223                .read(cx)
24224                .buffer
24225                .read(cx)
24226                .as_singleton()
24227                .expect("A multi buffer in breakpoint prompt isn't possible")
24228                .read(cx)
24229                .as_rope()
24230                .to_string();
24231
24232            editor.update(cx, |editor, cx| {
24233                editor.edit_breakpoint_at_anchor(
24234                    self.breakpoint_anchor,
24235                    self.breakpoint.clone(),
24236                    match self.edit_action {
24237                        BreakpointPromptEditAction::Log => {
24238                            BreakpointEditAction::EditLogMessage(message.into())
24239                        }
24240                        BreakpointPromptEditAction::Condition => {
24241                            BreakpointEditAction::EditCondition(message.into())
24242                        }
24243                        BreakpointPromptEditAction::HitCondition => {
24244                            BreakpointEditAction::EditHitCondition(message.into())
24245                        }
24246                    },
24247                    cx,
24248                );
24249
24250                editor.remove_blocks(self.block_ids.clone(), None, cx);
24251                cx.focus_self(window);
24252            });
24253        }
24254    }
24255
24256    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24257        self.editor
24258            .update(cx, |editor, cx| {
24259                editor.remove_blocks(self.block_ids.clone(), None, cx);
24260                window.focus(&editor.focus_handle);
24261            })
24262            .log_err();
24263    }
24264
24265    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24266        let settings = ThemeSettings::get_global(cx);
24267        let text_style = TextStyle {
24268            color: if self.prompt.read(cx).read_only(cx) {
24269                cx.theme().colors().text_disabled
24270            } else {
24271                cx.theme().colors().text
24272            },
24273            font_family: settings.buffer_font.family.clone(),
24274            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24275            font_size: settings.buffer_font_size(cx).into(),
24276            font_weight: settings.buffer_font.weight,
24277            line_height: relative(settings.buffer_line_height.value()),
24278            ..Default::default()
24279        };
24280        EditorElement::new(
24281            &self.prompt,
24282            EditorStyle {
24283                background: cx.theme().colors().editor_background,
24284                local_player: cx.theme().players().local(),
24285                text: text_style,
24286                ..Default::default()
24287            },
24288        )
24289    }
24290}
24291
24292impl Render for BreakpointPromptEditor {
24293    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24294        let editor_margins = *self.editor_margins.lock();
24295        let gutter_dimensions = editor_margins.gutter;
24296        h_flex()
24297            .key_context("Editor")
24298            .bg(cx.theme().colors().editor_background)
24299            .border_y_1()
24300            .border_color(cx.theme().status().info_border)
24301            .size_full()
24302            .py(window.line_height() / 2.5)
24303            .on_action(cx.listener(Self::confirm))
24304            .on_action(cx.listener(Self::cancel))
24305            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24306            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24307    }
24308}
24309
24310impl Focusable for BreakpointPromptEditor {
24311    fn focus_handle(&self, cx: &App) -> FocusHandle {
24312        self.prompt.focus_handle(cx)
24313    }
24314}
24315
24316fn all_edits_insertions_or_deletions(
24317    edits: &Vec<(Range<Anchor>, String)>,
24318    snapshot: &MultiBufferSnapshot,
24319) -> bool {
24320    let mut all_insertions = true;
24321    let mut all_deletions = true;
24322
24323    for (range, new_text) in edits.iter() {
24324        let range_is_empty = range.to_offset(snapshot).is_empty();
24325        let text_is_empty = new_text.is_empty();
24326
24327        if range_is_empty != text_is_empty {
24328            if range_is_empty {
24329                all_deletions = false;
24330            } else {
24331                all_insertions = false;
24332            }
24333        } else {
24334            return false;
24335        }
24336
24337        if !all_insertions && !all_deletions {
24338            return false;
24339        }
24340    }
24341    all_insertions || all_deletions
24342}
24343
24344struct MissingEditPredictionKeybindingTooltip;
24345
24346impl Render for MissingEditPredictionKeybindingTooltip {
24347    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24348        ui::tooltip_container(window, cx, |container, _, cx| {
24349            container
24350                .flex_shrink_0()
24351                .max_w_80()
24352                .min_h(rems_from_px(124.))
24353                .justify_between()
24354                .child(
24355                    v_flex()
24356                        .flex_1()
24357                        .text_ui_sm(cx)
24358                        .child(Label::new("Conflict with Accept Keybinding"))
24359                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24360                )
24361                .child(
24362                    h_flex()
24363                        .pb_1()
24364                        .gap_1()
24365                        .items_end()
24366                        .w_full()
24367                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24368                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24369                        }))
24370                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24371                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24372                        })),
24373                )
24374        })
24375    }
24376}
24377
24378#[derive(Debug, Clone, Copy, PartialEq)]
24379pub struct LineHighlight {
24380    pub background: Background,
24381    pub border: Option<gpui::Hsla>,
24382    pub include_gutter: bool,
24383    pub type_id: Option<TypeId>,
24384}
24385
24386struct LineManipulationResult {
24387    pub new_text: String,
24388    pub line_count_before: usize,
24389    pub line_count_after: usize,
24390}
24391
24392fn render_diff_hunk_controls(
24393    row: u32,
24394    status: &DiffHunkStatus,
24395    hunk_range: Range<Anchor>,
24396    is_created_file: bool,
24397    line_height: Pixels,
24398    editor: &Entity<Editor>,
24399    _window: &mut Window,
24400    cx: &mut App,
24401) -> AnyElement {
24402    h_flex()
24403        .h(line_height)
24404        .mr_1()
24405        .gap_1()
24406        .px_0p5()
24407        .pb_1()
24408        .border_x_1()
24409        .border_b_1()
24410        .border_color(cx.theme().colors().border_variant)
24411        .rounded_b_lg()
24412        .bg(cx.theme().colors().editor_background)
24413        .gap_1()
24414        .block_mouse_except_scroll()
24415        .shadow_md()
24416        .child(if status.has_secondary_hunk() {
24417            Button::new(("stage", row as u64), "Stage")
24418                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24419                .tooltip({
24420                    let focus_handle = editor.focus_handle(cx);
24421                    move |window, cx| {
24422                        Tooltip::for_action_in(
24423                            "Stage Hunk",
24424                            &::git::ToggleStaged,
24425                            &focus_handle,
24426                            window,
24427                            cx,
24428                        )
24429                    }
24430                })
24431                .on_click({
24432                    let editor = editor.clone();
24433                    move |_event, _window, cx| {
24434                        editor.update(cx, |editor, cx| {
24435                            editor.stage_or_unstage_diff_hunks(
24436                                true,
24437                                vec![hunk_range.start..hunk_range.start],
24438                                cx,
24439                            );
24440                        });
24441                    }
24442                })
24443        } else {
24444            Button::new(("unstage", row as u64), "Unstage")
24445                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24446                .tooltip({
24447                    let focus_handle = editor.focus_handle(cx);
24448                    move |window, cx| {
24449                        Tooltip::for_action_in(
24450                            "Unstage Hunk",
24451                            &::git::ToggleStaged,
24452                            &focus_handle,
24453                            window,
24454                            cx,
24455                        )
24456                    }
24457                })
24458                .on_click({
24459                    let editor = editor.clone();
24460                    move |_event, _window, cx| {
24461                        editor.update(cx, |editor, cx| {
24462                            editor.stage_or_unstage_diff_hunks(
24463                                false,
24464                                vec![hunk_range.start..hunk_range.start],
24465                                cx,
24466                            );
24467                        });
24468                    }
24469                })
24470        })
24471        .child(
24472            Button::new(("restore", row as u64), "Restore")
24473                .tooltip({
24474                    let focus_handle = editor.focus_handle(cx);
24475                    move |window, cx| {
24476                        Tooltip::for_action_in(
24477                            "Restore Hunk",
24478                            &::git::Restore,
24479                            &focus_handle,
24480                            window,
24481                            cx,
24482                        )
24483                    }
24484                })
24485                .on_click({
24486                    let editor = editor.clone();
24487                    move |_event, window, cx| {
24488                        editor.update(cx, |editor, cx| {
24489                            let snapshot = editor.snapshot(window, cx);
24490                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24491                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24492                        });
24493                    }
24494                })
24495                .disabled(is_created_file),
24496        )
24497        .when(
24498            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24499            |el| {
24500                el.child(
24501                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24502                        .shape(IconButtonShape::Square)
24503                        .icon_size(IconSize::Small)
24504                        // .disabled(!has_multiple_hunks)
24505                        .tooltip({
24506                            let focus_handle = editor.focus_handle(cx);
24507                            move |window, cx| {
24508                                Tooltip::for_action_in(
24509                                    "Next Hunk",
24510                                    &GoToHunk,
24511                                    &focus_handle,
24512                                    window,
24513                                    cx,
24514                                )
24515                            }
24516                        })
24517                        .on_click({
24518                            let editor = editor.clone();
24519                            move |_event, window, cx| {
24520                                editor.update(cx, |editor, cx| {
24521                                    let snapshot = editor.snapshot(window, cx);
24522                                    let position =
24523                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24524                                    editor.go_to_hunk_before_or_after_position(
24525                                        &snapshot,
24526                                        position,
24527                                        Direction::Next,
24528                                        window,
24529                                        cx,
24530                                    );
24531                                    editor.expand_selected_diff_hunks(cx);
24532                                });
24533                            }
24534                        }),
24535                )
24536                .child(
24537                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24538                        .shape(IconButtonShape::Square)
24539                        .icon_size(IconSize::Small)
24540                        // .disabled(!has_multiple_hunks)
24541                        .tooltip({
24542                            let focus_handle = editor.focus_handle(cx);
24543                            move |window, cx| {
24544                                Tooltip::for_action_in(
24545                                    "Previous Hunk",
24546                                    &GoToPreviousHunk,
24547                                    &focus_handle,
24548                                    window,
24549                                    cx,
24550                                )
24551                            }
24552                        })
24553                        .on_click({
24554                            let editor = editor.clone();
24555                            move |_event, window, cx| {
24556                                editor.update(cx, |editor, cx| {
24557                                    let snapshot = editor.snapshot(window, cx);
24558                                    let point =
24559                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24560                                    editor.go_to_hunk_before_or_after_position(
24561                                        &snapshot,
24562                                        point,
24563                                        Direction::Prev,
24564                                        window,
24565                                        cx,
24566                                    );
24567                                    editor.expand_selected_diff_hunks(cx);
24568                                });
24569                            }
24570                        }),
24571                )
24572            },
24573        )
24574        .into_any_element()
24575}
24576
24577pub fn multibuffer_context_lines(cx: &App) -> u32 {
24578    EditorSettings::try_get(cx)
24579        .map(|settings| settings.excerpt_context_lines)
24580        .unwrap_or(2)
24581        .min(32)
24582}