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//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, Render,
  111    ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle,
  112    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
  113    WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,
  114};
  115use hover_links::{HoverLink, HoveredLinkState, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  125    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143};
  144use parking_lot::Mutex;
  145use persistence::DB;
  146use project::{
  147    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  148    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  149    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  150    ProjectPath, ProjectTransaction, TaskSourceKind,
  151    debugger::{
  152        breakpoint_store::{
  153            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  154            BreakpointStore, BreakpointStoreEvent,
  155        },
  156        session::{Session, SessionEvent},
  157    },
  158    git_store::GitStoreEvent,
  159    lsp_store::{
  160        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  161        OpenLspBufferHandle,
  162    },
  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::{MutableSelectionsCollection, SelectionsCollection};
  169use serde::{Deserialize, Serialize};
  170use settings::{
  171    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  172    update_settings_file,
  173};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::{Any, TypeId},
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    collections::hash_map,
  182    iter::{self, Peekable},
  183    mem,
  184    num::NonZeroU32,
  185    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  193use theme::{
  194    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    inlays::{
  216        InlineValueCache,
  217        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  218    },
  219    scroll::{ScrollOffset, ScrollPixelOffset},
  220    selections_collection::resolve_selections_wrapping_blocks,
  221    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  222};
  223
  224pub const FILE_HEADER_HEIGHT: u32 = 2;
  225pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  226const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  227const MAX_LINE_LEN: usize = 1024;
  228const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  229const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  230pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  231#[doc(hidden)]
  232pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  233pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  234
  235pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  236pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  238pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  239
  240pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  241pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  242pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  243
  244pub type RenderDiffHunkControlsFn = Arc<
  245    dyn Fn(
  246        u32,
  247        &DiffHunkStatus,
  248        Range<Anchor>,
  249        bool,
  250        Pixels,
  251        &Entity<Editor>,
  252        &mut Window,
  253        &mut App,
  254    ) -> AnyElement,
  255>;
  256
  257enum ReportEditorEvent {
  258    Saved { auto_saved: bool },
  259    EditorOpened,
  260    Closed,
  261}
  262
  263impl ReportEditorEvent {
  264    pub fn event_type(&self) -> &'static str {
  265        match self {
  266            Self::Saved { .. } => "Editor Saved",
  267            Self::EditorOpened => "Editor Opened",
  268            Self::Closed => "Editor Closed",
  269        }
  270    }
  271}
  272
  273pub enum ActiveDebugLine {}
  274pub enum DebugStackFrameLine {}
  275enum DocumentHighlightRead {}
  276enum DocumentHighlightWrite {}
  277enum InputComposition {}
  278pub enum PendingInput {}
  279enum SelectedTextHighlight {}
  280
  281pub enum ConflictsOuter {}
  282pub enum ConflictsOurs {}
  283pub enum ConflictsTheirs {}
  284pub enum ConflictsOursMarker {}
  285pub enum ConflictsTheirsMarker {}
  286
  287#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  288pub enum Navigated {
  289    Yes,
  290    No,
  291}
  292
  293impl Navigated {
  294    pub fn from_bool(yes: bool) -> Navigated {
  295        if yes { Navigated::Yes } else { Navigated::No }
  296    }
  297}
  298
  299#[derive(Debug, Clone, PartialEq, Eq)]
  300enum DisplayDiffHunk {
  301    Folded {
  302        display_row: DisplayRow,
  303    },
  304    Unfolded {
  305        is_created_file: bool,
  306        diff_base_byte_range: Range<usize>,
  307        display_row_range: Range<DisplayRow>,
  308        multi_buffer_range: Range<Anchor>,
  309        status: DiffHunkStatus,
  310    },
  311}
  312
  313pub enum HideMouseCursorOrigin {
  314    TypingAction,
  315    MovementAction,
  316}
  317
  318pub fn init(cx: &mut App) {
  319    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  320
  321    workspace::register_project_item::<Editor>(cx);
  322    workspace::FollowableViewRegistry::register::<Editor>(cx);
  323    workspace::register_serializable_item::<Editor>(cx);
  324
  325    cx.observe_new(
  326        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  327            workspace.register_action(Editor::new_file);
  328            workspace.register_action(Editor::new_file_split);
  329            workspace.register_action(Editor::new_file_vertical);
  330            workspace.register_action(Editor::new_file_horizontal);
  331            workspace.register_action(Editor::cancel_language_server_work);
  332            workspace.register_action(Editor::toggle_focus);
  333        },
  334    )
  335    .detach();
  336
  337    cx.on_action(move |_: &workspace::NewFile, cx| {
  338        let app_state = workspace::AppState::global(cx);
  339        if let Some(app_state) = app_state.upgrade() {
  340            workspace::open_new(
  341                Default::default(),
  342                app_state,
  343                cx,
  344                |workspace, window, cx| {
  345                    Editor::new_file(workspace, &Default::default(), window, cx)
  346                },
  347            )
  348            .detach();
  349        }
  350    });
  351    cx.on_action(move |_: &workspace::NewWindow, cx| {
  352        let app_state = workspace::AppState::global(cx);
  353        if let Some(app_state) = app_state.upgrade() {
  354            workspace::open_new(
  355                Default::default(),
  356                app_state,
  357                cx,
  358                |workspace, window, cx| {
  359                    cx.activate(true);
  360                    Editor::new_file(workspace, &Default::default(), window, cx)
  361                },
  362            )
  363            .detach();
  364        }
  365    });
  366}
  367
  368pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  369    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  370}
  371
  372pub trait DiagnosticRenderer {
  373    fn render_group(
  374        &self,
  375        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  376        buffer_id: BufferId,
  377        snapshot: EditorSnapshot,
  378        editor: WeakEntity<Editor>,
  379        language_registry: Option<Arc<LanguageRegistry>>,
  380        cx: &mut App,
  381    ) -> Vec<BlockProperties<Anchor>>;
  382
  383    fn render_hover(
  384        &self,
  385        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  386        range: Range<Point>,
  387        buffer_id: BufferId,
  388        language_registry: Option<Arc<LanguageRegistry>>,
  389        cx: &mut App,
  390    ) -> Option<Entity<markdown::Markdown>>;
  391
  392    fn open_link(
  393        &self,
  394        editor: &mut Editor,
  395        link: SharedString,
  396        window: &mut Window,
  397        cx: &mut Context<Editor>,
  398    );
  399}
  400
  401pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  402
  403impl GlobalDiagnosticRenderer {
  404    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  405        cx.try_global::<Self>().map(|g| g.0.clone())
  406    }
  407}
  408
  409impl gpui::Global for GlobalDiagnosticRenderer {}
  410pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  411    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  412}
  413
  414pub struct SearchWithinRange;
  415
  416trait InvalidationRegion {
  417    fn ranges(&self) -> &[Range<Anchor>];
  418}
  419
  420#[derive(Clone, Debug, PartialEq)]
  421pub enum SelectPhase {
  422    Begin {
  423        position: DisplayPoint,
  424        add: bool,
  425        click_count: usize,
  426    },
  427    BeginColumnar {
  428        position: DisplayPoint,
  429        reset: bool,
  430        mode: ColumnarMode,
  431        goal_column: u32,
  432    },
  433    Extend {
  434        position: DisplayPoint,
  435        click_count: usize,
  436    },
  437    Update {
  438        position: DisplayPoint,
  439        goal_column: u32,
  440        scroll_delta: gpui::Point<f32>,
  441    },
  442    End,
  443}
  444
  445#[derive(Clone, Debug, PartialEq)]
  446pub enum ColumnarMode {
  447    FromMouse,
  448    FromSelection,
  449}
  450
  451#[derive(Clone, Debug)]
  452pub enum SelectMode {
  453    Character,
  454    Word(Range<Anchor>),
  455    Line(Range<Anchor>),
  456    All,
  457}
  458
  459#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  460pub enum SizingBehavior {
  461    /// The editor will layout itself using `size_full` and will include the vertical
  462    /// scroll margin as requested by user settings.
  463    #[default]
  464    Default,
  465    /// The editor will layout itself using `size_full`, but will not have any
  466    /// vertical overscroll.
  467    ExcludeOverscrollMargin,
  468    /// The editor will request a vertical size according to its content and will be
  469    /// layouted without a vertical scroll margin.
  470    SizeByContent,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine,
  476    AutoHeight {
  477        min_lines: usize,
  478        max_lines: Option<usize>,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// Determines the sizing behavior for this editor
  486        sizing_behavior: SizingBehavior,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sizing_behavior: SizingBehavior::Default,
  499        }
  500    }
  501
  502    #[inline]
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    #[inline]
  508    pub fn is_single_line(&self) -> bool {
  509        matches!(self, Self::SingleLine { .. })
  510    }
  511
  512    #[inline]
  513    fn is_minimap(&self) -> bool {
  514        matches!(self, Self::Minimap { .. })
  515    }
  516}
  517
  518#[derive(Copy, Clone, Debug)]
  519pub enum SoftWrap {
  520    /// Prefer not to wrap at all.
  521    ///
  522    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  523    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  524    GitDiff,
  525    /// Prefer a single line generally, unless an overly long line is encountered.
  526    None,
  527    /// Soft wrap lines that exceed the editor width.
  528    EditorWidth,
  529    /// Soft wrap lines at the preferred line length.
  530    Column(u32),
  531    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  532    Bounded(u32),
  533}
  534
  535#[derive(Clone)]
  536pub struct EditorStyle {
  537    pub background: Hsla,
  538    pub border: Hsla,
  539    pub local_player: PlayerColor,
  540    pub text: TextStyle,
  541    pub scrollbar_width: Pixels,
  542    pub syntax: Arc<SyntaxTheme>,
  543    pub status: StatusColors,
  544    pub inlay_hints_style: HighlightStyle,
  545    pub edit_prediction_styles: EditPredictionStyles,
  546    pub unnecessary_code_fade: f32,
  547    pub show_underlines: bool,
  548}
  549
  550impl Default for EditorStyle {
  551    fn default() -> Self {
  552        Self {
  553            background: Hsla::default(),
  554            border: Hsla::default(),
  555            local_player: PlayerColor::default(),
  556            text: TextStyle::default(),
  557            scrollbar_width: Pixels::default(),
  558            syntax: Default::default(),
  559            // HACK: Status colors don't have a real default.
  560            // We should look into removing the status colors from the editor
  561            // style and retrieve them directly from the theme.
  562            status: StatusColors::dark(),
  563            inlay_hints_style: HighlightStyle::default(),
  564            edit_prediction_styles: EditPredictionStyles {
  565                insertion: HighlightStyle::default(),
  566                whitespace: HighlightStyle::default(),
  567            },
  568            unnecessary_code_fade: Default::default(),
  569            show_underlines: true,
  570        }
  571    }
  572}
  573
  574pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  575    let show_background = language_settings::language_settings(None, None, cx)
  576        .inlay_hints
  577        .show_background;
  578
  579    let mut style = cx.theme().syntax().get("hint");
  580
  581    if style.color.is_none() {
  582        style.color = Some(cx.theme().status().hint);
  583    }
  584
  585    if !show_background {
  586        style.background_color = None;
  587        return style;
  588    }
  589
  590    if style.background_color.is_none() {
  591        style.background_color = Some(cx.theme().status().hint_background);
  592    }
  593
  594    style
  595}
  596
  597pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  598    EditPredictionStyles {
  599        insertion: HighlightStyle {
  600            color: Some(cx.theme().status().predictive),
  601            ..HighlightStyle::default()
  602        },
  603        whitespace: HighlightStyle {
  604            background_color: Some(cx.theme().status().created_background),
  605            ..HighlightStyle::default()
  606        },
  607    }
  608}
  609
  610type CompletionId = usize;
  611
  612pub(crate) enum EditDisplayMode {
  613    TabAccept,
  614    DiffPopover,
  615    Inline,
  616}
  617
  618enum EditPrediction {
  619    Edit {
  620        edits: Vec<(Range<Anchor>, Arc<str>)>,
  621        edit_preview: Option<EditPreview>,
  622        display_mode: EditDisplayMode,
  623        snapshot: BufferSnapshot,
  624    },
  625    /// Move to a specific location in the active editor
  626    MoveWithin {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630    /// Move to a specific location in a different editor (not the active one)
  631    MoveOutside {
  632        target: language::Anchor,
  633        snapshot: BufferSnapshot,
  634    },
  635}
  636
  637struct EditPredictionState {
  638    inlay_ids: Vec<InlayId>,
  639    completion: EditPrediction,
  640    completion_id: Option<SharedString>,
  641    invalidation_range: Option<Range<Anchor>>,
  642}
  643
  644enum EditPredictionSettings {
  645    Disabled,
  646    Enabled {
  647        show_in_menu: bool,
  648        preview_requires_modifier: bool,
  649    },
  650}
  651
  652enum EditPredictionHighlight {}
  653
  654#[derive(Debug, Clone)]
  655struct InlineDiagnostic {
  656    message: SharedString,
  657    group_id: usize,
  658    is_primary: bool,
  659    start: Point,
  660    severity: lsp::DiagnosticSeverity,
  661}
  662
  663pub enum MenuEditPredictionsPolicy {
  664    Never,
  665    ByProvider,
  666}
  667
  668pub enum EditPredictionPreview {
  669    /// Modifier is not pressed
  670    Inactive { released_too_fast: bool },
  671    /// Modifier pressed
  672    Active {
  673        since: Instant,
  674        previous_scroll_position: Option<ScrollAnchor>,
  675    },
  676}
  677
  678impl EditPredictionPreview {
  679    pub fn released_too_fast(&self) -> bool {
  680        match self {
  681            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  682            EditPredictionPreview::Active { .. } => false,
  683        }
  684    }
  685
  686    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  687        if let EditPredictionPreview::Active {
  688            previous_scroll_position,
  689            ..
  690        } = self
  691        {
  692            *previous_scroll_position = scroll_position;
  693        }
  694    }
  695}
  696
  697pub struct ContextMenuOptions {
  698    pub min_entries_visible: usize,
  699    pub max_entries_visible: usize,
  700    pub placement: Option<ContextMenuPlacement>,
  701}
  702
  703#[derive(Debug, Clone, PartialEq, Eq)]
  704pub enum ContextMenuPlacement {
  705    Above,
  706    Below,
  707}
  708
  709#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  710struct EditorActionId(usize);
  711
  712impl EditorActionId {
  713    pub fn post_inc(&mut self) -> Self {
  714        let answer = self.0;
  715
  716        *self = Self(answer + 1);
  717
  718        Self(answer)
  719    }
  720}
  721
  722// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  723// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  724
  725type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  726type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  727
  728#[derive(Default)]
  729struct ScrollbarMarkerState {
  730    scrollbar_size: Size<Pixels>,
  731    dirty: bool,
  732    markers: Arc<[PaintQuad]>,
  733    pending_refresh: Option<Task<Result<()>>>,
  734}
  735
  736impl ScrollbarMarkerState {
  737    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  738        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  739    }
  740}
  741
  742#[derive(Clone, Copy, PartialEq, Eq)]
  743pub enum MinimapVisibility {
  744    Disabled,
  745    Enabled {
  746        /// The configuration currently present in the users settings.
  747        setting_configuration: bool,
  748        /// Whether to override the currently set visibility from the users setting.
  749        toggle_override: bool,
  750    },
  751}
  752
  753impl MinimapVisibility {
  754    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  755        if mode.is_full() {
  756            Self::Enabled {
  757                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  758                toggle_override: false,
  759            }
  760        } else {
  761            Self::Disabled
  762        }
  763    }
  764
  765    fn hidden(&self) -> Self {
  766        match *self {
  767            Self::Enabled {
  768                setting_configuration,
  769                ..
  770            } => Self::Enabled {
  771                setting_configuration,
  772                toggle_override: setting_configuration,
  773            },
  774            Self::Disabled => Self::Disabled,
  775        }
  776    }
  777
  778    fn disabled(&self) -> bool {
  779        matches!(*self, Self::Disabled)
  780    }
  781
  782    fn settings_visibility(&self) -> bool {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                ..
  787            } => setting_configuration,
  788            _ => false,
  789        }
  790    }
  791
  792    fn visible(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                toggle_override,
  797            } => setting_configuration ^ toggle_override,
  798            _ => false,
  799        }
  800    }
  801
  802    fn toggle_visibility(&self) -> Self {
  803        match *self {
  804            Self::Enabled {
  805                toggle_override,
  806                setting_configuration,
  807            } => Self::Enabled {
  808                setting_configuration,
  809                toggle_override: !toggle_override,
  810            },
  811            Self::Disabled => Self::Disabled,
  812        }
  813    }
  814}
  815
  816#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  817pub enum BufferSerialization {
  818    All,
  819    NonDirtyBuffers,
  820}
  821
  822impl BufferSerialization {
  823    fn new(restore_unsaved_buffers: bool) -> Self {
  824        if restore_unsaved_buffers {
  825            Self::All
  826        } else {
  827            Self::NonDirtyBuffers
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863/// Addons allow storing per-editor state in other crates (e.g. Vim)
  864pub trait Addon: 'static {
  865    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  866
  867    fn render_buffer_header_controls(
  868        &self,
  869        _: &ExcerptInfo,
  870        _: &Window,
  871        _: &App,
  872    ) -> Option<AnyElement> {
  873        None
  874    }
  875
  876    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  877        None
  878    }
  879
  880    fn to_any(&self) -> &dyn std::any::Any;
  881
  882    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  883        None
  884    }
  885}
  886
  887struct ChangeLocation {
  888    current: Option<Vec<Anchor>>,
  889    original: Vec<Anchor>,
  890}
  891impl ChangeLocation {
  892    fn locations(&self) -> &[Anchor] {
  893        self.current.as_ref().unwrap_or(&self.original)
  894    }
  895}
  896
  897/// A set of caret positions, registered when the editor was edited.
  898pub struct ChangeList {
  899    changes: Vec<ChangeLocation>,
  900    /// Currently "selected" change.
  901    position: Option<usize>,
  902}
  903
  904impl ChangeList {
  905    pub fn new() -> Self {
  906        Self {
  907            changes: Vec::new(),
  908            position: None,
  909        }
  910    }
  911
  912    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  913    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  914    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  915        if self.changes.is_empty() {
  916            return None;
  917        }
  918
  919        let prev = self.position.unwrap_or(self.changes.len());
  920        let next = if direction == Direction::Prev {
  921            prev.saturating_sub(count)
  922        } else {
  923            (prev + count).min(self.changes.len() - 1)
  924        };
  925        self.position = Some(next);
  926        self.changes.get(next).map(|change| change.locations())
  927    }
  928
  929    /// Adds a new change to the list, resetting the change list position.
  930    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  931        self.position.take();
  932        if let Some(last) = self.changes.last_mut()
  933            && group
  934        {
  935            last.current = Some(new_positions)
  936        } else {
  937            self.changes.push(ChangeLocation {
  938                original: new_positions,
  939                current: None,
  940            });
  941        }
  942    }
  943
  944    pub fn last(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.locations())
  946    }
  947
  948    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.original.as_slice())
  950    }
  951
  952    pub fn invert_last_group(&mut self) {
  953        if let Some(last) = self.changes.last_mut()
  954            && let Some(current) = last.current.as_mut()
  955        {
  956            mem::swap(&mut last.original, current);
  957        }
  958    }
  959}
  960
  961#[derive(Clone)]
  962struct InlineBlamePopoverState {
  963    scroll_handle: ScrollHandle,
  964    commit_message: Option<ParsedCommitMessage>,
  965    markdown: Entity<Markdown>,
  966}
  967
  968struct InlineBlamePopover {
  969    position: gpui::Point<Pixels>,
  970    hide_task: Option<Task<()>>,
  971    popover_bounds: Option<Bounds<Pixels>>,
  972    popover_state: InlineBlamePopoverState,
  973    keyboard_grace: bool,
  974}
  975
  976enum SelectionDragState {
  977    /// State when no drag related activity is detected.
  978    None,
  979    /// State when the mouse is down on a selection that is about to be dragged.
  980    ReadyToDrag {
  981        selection: Selection<Anchor>,
  982        click_position: gpui::Point<Pixels>,
  983        mouse_down_time: Instant,
  984    },
  985    /// State when the mouse is dragging the selection in the editor.
  986    Dragging {
  987        selection: Selection<Anchor>,
  988        drop_cursor: Selection<Anchor>,
  989        hide_drop_cursor: bool,
  990    },
  991}
  992
  993enum ColumnarSelectionState {
  994    FromMouse {
  995        selection_tail: Anchor,
  996        display_point: Option<DisplayPoint>,
  997    },
  998    FromSelection {
  999        selection_tail: Anchor,
 1000    },
 1001}
 1002
 1003/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1004/// a breakpoint on them.
 1005#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1006struct PhantomBreakpointIndicator {
 1007    display_row: DisplayRow,
 1008    /// There's a small debounce between hovering over the line and showing the indicator.
 1009    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1010    is_active: bool,
 1011    collides_with_existing_breakpoint: bool,
 1012}
 1013
 1014/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1015///
 1016/// See the [module level documentation](self) for more information.
 1017pub struct Editor {
 1018    focus_handle: FocusHandle,
 1019    last_focused_descendant: Option<WeakFocusHandle>,
 1020    /// The text buffer being edited
 1021    buffer: Entity<MultiBuffer>,
 1022    /// Map of how text in the buffer should be displayed.
 1023    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1024    pub display_map: Entity<DisplayMap>,
 1025    placeholder_display_map: Option<Entity<DisplayMap>>,
 1026    pub selections: SelectionsCollection,
 1027    pub scroll_manager: ScrollManager,
 1028    /// When inline assist editors are linked, they all render cursors because
 1029    /// typing enters text into each of them, even the ones that aren't focused.
 1030    pub(crate) show_cursor_when_unfocused: bool,
 1031    columnar_selection_state: Option<ColumnarSelectionState>,
 1032    add_selections_state: Option<AddSelectionsState>,
 1033    select_next_state: Option<SelectNextState>,
 1034    select_prev_state: Option<SelectNextState>,
 1035    selection_history: SelectionHistory,
 1036    defer_selection_effects: bool,
 1037    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1038    autoclose_regions: Vec<AutocloseRegion>,
 1039    snippet_stack: InvalidationStack<SnippetState>,
 1040    select_syntax_node_history: SelectSyntaxNodeHistory,
 1041    ime_transaction: Option<TransactionId>,
 1042    pub diagnostics_max_severity: DiagnosticSeverity,
 1043    active_diagnostics: ActiveDiagnostic,
 1044    show_inline_diagnostics: bool,
 1045    inline_diagnostics_update: Task<()>,
 1046    inline_diagnostics_enabled: bool,
 1047    diagnostics_enabled: bool,
 1048    word_completions_enabled: bool,
 1049    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1050    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1051    hard_wrap: Option<usize>,
 1052    project: Option<Entity<Project>>,
 1053    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1054    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1055    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1056    blink_manager: Entity<BlinkManager>,
 1057    show_cursor_names: bool,
 1058    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1059    pub show_local_selections: bool,
 1060    mode: EditorMode,
 1061    show_breadcrumbs: bool,
 1062    show_gutter: bool,
 1063    show_scrollbars: ScrollbarAxes,
 1064    minimap_visibility: MinimapVisibility,
 1065    offset_content: bool,
 1066    disable_expand_excerpt_buttons: bool,
 1067    show_line_numbers: Option<bool>,
 1068    use_relative_line_numbers: Option<bool>,
 1069    show_git_diff_gutter: Option<bool>,
 1070    show_code_actions: Option<bool>,
 1071    show_runnables: Option<bool>,
 1072    show_breakpoints: Option<bool>,
 1073    show_wrap_guides: Option<bool>,
 1074    show_indent_guides: Option<bool>,
 1075    highlight_order: usize,
 1076    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1077    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1078    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1079    scrollbar_marker_state: ScrollbarMarkerState,
 1080    active_indent_guides_state: ActiveIndentGuidesState,
 1081    nav_history: Option<ItemNavHistory>,
 1082    context_menu: RefCell<Option<CodeContextMenu>>,
 1083    context_menu_options: Option<ContextMenuOptions>,
 1084    mouse_context_menu: Option<MouseContextMenu>,
 1085    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1086    inline_blame_popover: Option<InlineBlamePopover>,
 1087    inline_blame_popover_show_task: Option<Task<()>>,
 1088    signature_help_state: SignatureHelpState,
 1089    auto_signature_help: Option<bool>,
 1090    find_all_references_task_sources: Vec<Anchor>,
 1091    next_completion_id: CompletionId,
 1092    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1093    code_actions_task: Option<Task<Result<()>>>,
 1094    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1096    document_highlights_task: Option<Task<()>>,
 1097    linked_editing_range_task: Option<Task<Option<()>>>,
 1098    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1099    pending_rename: Option<RenameState>,
 1100    searchable: bool,
 1101    cursor_shape: CursorShape,
 1102    current_line_highlight: Option<CurrentLineHighlight>,
 1103    pub collapse_matches: bool,
 1104    autoindent_mode: Option<AutoindentMode>,
 1105    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1106    input_enabled: bool,
 1107    use_modal_editing: bool,
 1108    read_only: bool,
 1109    leader_id: Option<CollaboratorId>,
 1110    remote_id: Option<ViewId>,
 1111    pub hover_state: HoverState,
 1112    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1113    gutter_hovered: bool,
 1114    hovered_link_state: Option<HoveredLinkState>,
 1115    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1116    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1117    active_edit_prediction: Option<EditPredictionState>,
 1118    /// Used to prevent flickering as the user types while the menu is open
 1119    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1120    edit_prediction_settings: EditPredictionSettings,
 1121    edit_predictions_hidden_for_vim_mode: bool,
 1122    show_edit_predictions_override: Option<bool>,
 1123    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1124    edit_prediction_preview: EditPredictionPreview,
 1125    edit_prediction_indent_conflict: bool,
 1126    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1127    next_inlay_id: usize,
 1128    next_color_inlay_id: usize,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    buffer_serialization: Option<BufferSerialization>,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191
 1192    selection_drag_state: SelectionDragState,
 1193    colors: Option<LspColorData>,
 1194    post_scroll_update: Task<()>,
 1195    refresh_colors_task: Task<()>,
 1196    inlay_hints: Option<LspInlayHintData>,
 1197    folding_newlines: Task<()>,
 1198    select_next_is_case_sensitive: Option<bool>,
 1199    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1200    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1201    accent_overrides: Vec<SharedString>,
 1202    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1203    use_base_text_line_numbers: bool,
 1204}
 1205
 1206fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1207    if debounce_ms > 0 {
 1208        Some(Duration::from_millis(debounce_ms))
 1209    } else {
 1210        None
 1211    }
 1212}
 1213
 1214#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1215enum NextScrollCursorCenterTopBottom {
 1216    #[default]
 1217    Center,
 1218    Top,
 1219    Bottom,
 1220}
 1221
 1222impl NextScrollCursorCenterTopBottom {
 1223    fn next(&self) -> Self {
 1224        match self {
 1225            Self::Center => Self::Top,
 1226            Self::Top => Self::Bottom,
 1227            Self::Bottom => Self::Center,
 1228        }
 1229    }
 1230}
 1231
 1232#[derive(Clone)]
 1233pub struct EditorSnapshot {
 1234    pub mode: EditorMode,
 1235    show_gutter: bool,
 1236    show_line_numbers: Option<bool>,
 1237    show_git_diff_gutter: Option<bool>,
 1238    show_code_actions: Option<bool>,
 1239    show_runnables: Option<bool>,
 1240    show_breakpoints: Option<bool>,
 1241    git_blame_gutter_max_author_length: Option<usize>,
 1242    pub display_snapshot: DisplaySnapshot,
 1243    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1244    is_focused: bool,
 1245    scroll_anchor: ScrollAnchor,
 1246    ongoing_scroll: OngoingScroll,
 1247    current_line_highlight: CurrentLineHighlight,
 1248    gutter_hovered: bool,
 1249}
 1250
 1251#[derive(Default, Debug, Clone, Copy)]
 1252pub struct GutterDimensions {
 1253    pub left_padding: Pixels,
 1254    pub right_padding: Pixels,
 1255    pub width: Pixels,
 1256    pub margin: Pixels,
 1257    pub git_blame_entries_width: Option<Pixels>,
 1258}
 1259
 1260impl GutterDimensions {
 1261    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1262        Self {
 1263            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1264            ..Default::default()
 1265        }
 1266    }
 1267
 1268    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1269        -cx.text_system().descent(font_id, font_size)
 1270    }
 1271    /// The full width of the space taken up by the gutter.
 1272    pub fn full_width(&self) -> Pixels {
 1273        self.margin + self.width
 1274    }
 1275
 1276    /// The width of the space reserved for the fold indicators,
 1277    /// use alongside 'justify_end' and `gutter_width` to
 1278    /// right align content with the line numbers
 1279    pub fn fold_area_width(&self) -> Pixels {
 1280        self.margin + self.right_padding
 1281    }
 1282}
 1283
 1284struct CharacterDimensions {
 1285    em_width: Pixels,
 1286    em_advance: Pixels,
 1287    line_height: Pixels,
 1288}
 1289
 1290#[derive(Debug)]
 1291pub struct RemoteSelection {
 1292    pub replica_id: ReplicaId,
 1293    pub selection: Selection<Anchor>,
 1294    pub cursor_shape: CursorShape,
 1295    pub collaborator_id: CollaboratorId,
 1296    pub line_mode: bool,
 1297    pub user_name: Option<SharedString>,
 1298    pub color: PlayerColor,
 1299}
 1300
 1301#[derive(Clone, Debug)]
 1302struct SelectionHistoryEntry {
 1303    selections: Arc<[Selection<Anchor>]>,
 1304    select_next_state: Option<SelectNextState>,
 1305    select_prev_state: Option<SelectNextState>,
 1306    add_selections_state: Option<AddSelectionsState>,
 1307}
 1308
 1309#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1310enum SelectionHistoryMode {
 1311    #[default]
 1312    Normal,
 1313    Undoing,
 1314    Redoing,
 1315    Skipping,
 1316}
 1317
 1318#[derive(Clone, PartialEq, Eq, Hash)]
 1319struct HoveredCursor {
 1320    replica_id: ReplicaId,
 1321    selection_id: usize,
 1322}
 1323
 1324#[derive(Debug)]
 1325/// SelectionEffects controls the side-effects of updating the selection.
 1326///
 1327/// The default behaviour does "what you mostly want":
 1328/// - it pushes to the nav history if the cursor moved by >10 lines
 1329/// - it re-triggers completion requests
 1330/// - it scrolls to fit
 1331///
 1332/// You might want to modify these behaviours. For example when doing a "jump"
 1333/// like go to definition, we always want to add to nav history; but when scrolling
 1334/// in vim mode we never do.
 1335///
 1336/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1337/// move.
 1338#[derive(Clone)]
 1339pub struct SelectionEffects {
 1340    nav_history: Option<bool>,
 1341    completions: bool,
 1342    scroll: Option<Autoscroll>,
 1343}
 1344
 1345impl Default for SelectionEffects {
 1346    fn default() -> Self {
 1347        Self {
 1348            nav_history: None,
 1349            completions: true,
 1350            scroll: Some(Autoscroll::fit()),
 1351        }
 1352    }
 1353}
 1354impl SelectionEffects {
 1355    pub fn scroll(scroll: Autoscroll) -> Self {
 1356        Self {
 1357            scroll: Some(scroll),
 1358            ..Default::default()
 1359        }
 1360    }
 1361
 1362    pub fn no_scroll() -> Self {
 1363        Self {
 1364            scroll: None,
 1365            ..Default::default()
 1366        }
 1367    }
 1368
 1369    pub fn completions(self, completions: bool) -> Self {
 1370        Self {
 1371            completions,
 1372            ..self
 1373        }
 1374    }
 1375
 1376    pub fn nav_history(self, nav_history: bool) -> Self {
 1377        Self {
 1378            nav_history: Some(nav_history),
 1379            ..self
 1380        }
 1381    }
 1382}
 1383
 1384struct DeferredSelectionEffectsState {
 1385    changed: bool,
 1386    effects: SelectionEffects,
 1387    old_cursor_position: Anchor,
 1388    history_entry: SelectionHistoryEntry,
 1389}
 1390
 1391#[derive(Default)]
 1392struct SelectionHistory {
 1393    #[allow(clippy::type_complexity)]
 1394    selections_by_transaction:
 1395        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1396    mode: SelectionHistoryMode,
 1397    undo_stack: VecDeque<SelectionHistoryEntry>,
 1398    redo_stack: VecDeque<SelectionHistoryEntry>,
 1399}
 1400
 1401impl SelectionHistory {
 1402    #[track_caller]
 1403    fn insert_transaction(
 1404        &mut self,
 1405        transaction_id: TransactionId,
 1406        selections: Arc<[Selection<Anchor>]>,
 1407    ) {
 1408        if selections.is_empty() {
 1409            log::error!(
 1410                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1411                std::panic::Location::caller()
 1412            );
 1413            return;
 1414        }
 1415        self.selections_by_transaction
 1416            .insert(transaction_id, (selections, None));
 1417    }
 1418
 1419    #[allow(clippy::type_complexity)]
 1420    fn transaction(
 1421        &self,
 1422        transaction_id: TransactionId,
 1423    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1424        self.selections_by_transaction.get(&transaction_id)
 1425    }
 1426
 1427    #[allow(clippy::type_complexity)]
 1428    fn transaction_mut(
 1429        &mut self,
 1430        transaction_id: TransactionId,
 1431    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1432        self.selections_by_transaction.get_mut(&transaction_id)
 1433    }
 1434
 1435    fn push(&mut self, entry: SelectionHistoryEntry) {
 1436        if !entry.selections.is_empty() {
 1437            match self.mode {
 1438                SelectionHistoryMode::Normal => {
 1439                    self.push_undo(entry);
 1440                    self.redo_stack.clear();
 1441                }
 1442                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1443                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1444                SelectionHistoryMode::Skipping => {}
 1445            }
 1446        }
 1447    }
 1448
 1449    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1450        if self
 1451            .undo_stack
 1452            .back()
 1453            .is_none_or(|e| e.selections != entry.selections)
 1454        {
 1455            self.undo_stack.push_back(entry);
 1456            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1457                self.undo_stack.pop_front();
 1458            }
 1459        }
 1460    }
 1461
 1462    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1463        if self
 1464            .redo_stack
 1465            .back()
 1466            .is_none_or(|e| e.selections != entry.selections)
 1467        {
 1468            self.redo_stack.push_back(entry);
 1469            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1470                self.redo_stack.pop_front();
 1471            }
 1472        }
 1473    }
 1474}
 1475
 1476#[derive(Clone, Copy)]
 1477pub struct RowHighlightOptions {
 1478    pub autoscroll: bool,
 1479    pub include_gutter: bool,
 1480}
 1481
 1482impl Default for RowHighlightOptions {
 1483    fn default() -> Self {
 1484        Self {
 1485            autoscroll: Default::default(),
 1486            include_gutter: true,
 1487        }
 1488    }
 1489}
 1490
 1491struct RowHighlight {
 1492    index: usize,
 1493    range: Range<Anchor>,
 1494    color: Hsla,
 1495    options: RowHighlightOptions,
 1496    type_id: TypeId,
 1497}
 1498
 1499#[derive(Clone, Debug)]
 1500struct AddSelectionsState {
 1501    groups: Vec<AddSelectionsGroup>,
 1502}
 1503
 1504#[derive(Clone, Debug)]
 1505struct AddSelectionsGroup {
 1506    above: bool,
 1507    stack: Vec<usize>,
 1508}
 1509
 1510#[derive(Clone)]
 1511struct SelectNextState {
 1512    query: AhoCorasick,
 1513    wordwise: bool,
 1514    done: bool,
 1515}
 1516
 1517impl std::fmt::Debug for SelectNextState {
 1518    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1519        f.debug_struct(std::any::type_name::<Self>())
 1520            .field("wordwise", &self.wordwise)
 1521            .field("done", &self.done)
 1522            .finish()
 1523    }
 1524}
 1525
 1526#[derive(Debug)]
 1527struct AutocloseRegion {
 1528    selection_id: usize,
 1529    range: Range<Anchor>,
 1530    pair: BracketPair,
 1531}
 1532
 1533#[derive(Debug)]
 1534struct SnippetState {
 1535    ranges: Vec<Vec<Range<Anchor>>>,
 1536    active_index: usize,
 1537    choices: Vec<Option<Vec<String>>>,
 1538}
 1539
 1540#[doc(hidden)]
 1541pub struct RenameState {
 1542    pub range: Range<Anchor>,
 1543    pub old_name: Arc<str>,
 1544    pub editor: Entity<Editor>,
 1545    block_id: CustomBlockId,
 1546}
 1547
 1548struct InvalidationStack<T>(Vec<T>);
 1549
 1550struct RegisteredEditPredictionProvider {
 1551    provider: Arc<dyn EditPredictionProviderHandle>,
 1552    _subscription: Subscription,
 1553}
 1554
 1555#[derive(Debug, PartialEq, Eq)]
 1556pub struct ActiveDiagnosticGroup {
 1557    pub active_range: Range<Anchor>,
 1558    pub active_message: String,
 1559    pub group_id: usize,
 1560    pub blocks: HashSet<CustomBlockId>,
 1561}
 1562
 1563#[derive(Debug, PartialEq, Eq)]
 1564
 1565pub(crate) enum ActiveDiagnostic {
 1566    None,
 1567    All,
 1568    Group(ActiveDiagnosticGroup),
 1569}
 1570
 1571#[derive(Serialize, Deserialize, Clone, Debug)]
 1572pub struct ClipboardSelection {
 1573    /// The number of bytes in this selection.
 1574    pub len: usize,
 1575    /// Whether this was a full-line selection.
 1576    pub is_entire_line: bool,
 1577    /// The indentation of the first line when this content was originally copied.
 1578    pub first_line_indent: u32,
 1579}
 1580
 1581// selections, scroll behavior, was newest selection reversed
 1582type SelectSyntaxNodeHistoryState = (
 1583    Box<[Selection<MultiBufferOffset>]>,
 1584    SelectSyntaxNodeScrollBehavior,
 1585    bool,
 1586);
 1587
 1588#[derive(Default)]
 1589struct SelectSyntaxNodeHistory {
 1590    stack: Vec<SelectSyntaxNodeHistoryState>,
 1591    // disable temporarily to allow changing selections without losing the stack
 1592    pub disable_clearing: bool,
 1593}
 1594
 1595impl SelectSyntaxNodeHistory {
 1596    pub fn try_clear(&mut self) {
 1597        if !self.disable_clearing {
 1598            self.stack.clear();
 1599        }
 1600    }
 1601
 1602    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1603        self.stack.push(selection);
 1604    }
 1605
 1606    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1607        self.stack.pop()
 1608    }
 1609}
 1610
 1611enum SelectSyntaxNodeScrollBehavior {
 1612    CursorTop,
 1613    FitSelection,
 1614    CursorBottom,
 1615}
 1616
 1617#[derive(Debug)]
 1618pub(crate) struct NavigationData {
 1619    cursor_anchor: Anchor,
 1620    cursor_position: Point,
 1621    scroll_anchor: ScrollAnchor,
 1622    scroll_top_row: u32,
 1623}
 1624
 1625#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1626pub enum GotoDefinitionKind {
 1627    Symbol,
 1628    Declaration,
 1629    Type,
 1630    Implementation,
 1631}
 1632
 1633pub enum FormatTarget {
 1634    Buffers(HashSet<Entity<Buffer>>),
 1635    Ranges(Vec<Range<MultiBufferPoint>>),
 1636}
 1637
 1638pub(crate) struct FocusedBlock {
 1639    id: BlockId,
 1640    focus_handle: WeakFocusHandle,
 1641}
 1642
 1643#[derive(Clone, Debug)]
 1644enum JumpData {
 1645    MultiBufferRow {
 1646        row: MultiBufferRow,
 1647        line_offset_from_top: u32,
 1648    },
 1649    MultiBufferPoint {
 1650        excerpt_id: ExcerptId,
 1651        position: Point,
 1652        anchor: text::Anchor,
 1653        line_offset_from_top: u32,
 1654    },
 1655}
 1656
 1657pub enum MultibufferSelectionMode {
 1658    First,
 1659    All,
 1660}
 1661
 1662#[derive(Clone, Copy, Debug, Default)]
 1663pub struct RewrapOptions {
 1664    pub override_language_settings: bool,
 1665    pub preserve_existing_whitespace: bool,
 1666}
 1667
 1668impl Editor {
 1669    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(EditorMode::full(), buffer, None, window, cx)
 1679    }
 1680
 1681    pub fn auto_height(
 1682        min_lines: usize,
 1683        max_lines: usize,
 1684        window: &mut Window,
 1685        cx: &mut Context<Self>,
 1686    ) -> Self {
 1687        let buffer = cx.new(|cx| Buffer::local("", cx));
 1688        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1689        Self::new(
 1690            EditorMode::AutoHeight {
 1691                min_lines,
 1692                max_lines: Some(max_lines),
 1693            },
 1694            buffer,
 1695            None,
 1696            window,
 1697            cx,
 1698        )
 1699    }
 1700
 1701    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1702    /// The editor grows as tall as needed to fit its content.
 1703    pub fn auto_height_unbounded(
 1704        min_lines: usize,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        let buffer = cx.new(|cx| Buffer::local("", cx));
 1709        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1710        Self::new(
 1711            EditorMode::AutoHeight {
 1712                min_lines,
 1713                max_lines: None,
 1714            },
 1715            buffer,
 1716            None,
 1717            window,
 1718            cx,
 1719        )
 1720    }
 1721
 1722    pub fn for_buffer(
 1723        buffer: Entity<Buffer>,
 1724        project: Option<Entity<Project>>,
 1725        window: &mut Window,
 1726        cx: &mut Context<Self>,
 1727    ) -> Self {
 1728        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1729        Self::new(EditorMode::full(), buffer, project, window, cx)
 1730    }
 1731
 1732    pub fn for_multibuffer(
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Self::new(EditorMode::full(), buffer, project, window, cx)
 1739    }
 1740
 1741    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1742        let mut clone = Self::new(
 1743            self.mode.clone(),
 1744            self.buffer.clone(),
 1745            self.project.clone(),
 1746            window,
 1747            cx,
 1748        );
 1749        self.display_map.update(cx, |display_map, cx| {
 1750            let snapshot = display_map.snapshot(cx);
 1751            clone.display_map.update(cx, |display_map, cx| {
 1752                display_map.set_state(&snapshot, cx);
 1753            });
 1754        });
 1755        clone.folds_did_change(cx);
 1756        clone.selections.clone_state(&self.selections);
 1757        clone.scroll_manager.clone_state(&self.scroll_manager);
 1758        clone.searchable = self.searchable;
 1759        clone.read_only = self.read_only;
 1760        clone
 1761    }
 1762
 1763    pub fn new(
 1764        mode: EditorMode,
 1765        buffer: Entity<MultiBuffer>,
 1766        project: Option<Entity<Project>>,
 1767        window: &mut Window,
 1768        cx: &mut Context<Self>,
 1769    ) -> Self {
 1770        Editor::new_internal(mode, buffer, project, None, window, cx)
 1771    }
 1772
 1773    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1774        let multi_buffer = self.buffer().read(cx);
 1775        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1776        let multi_buffer_visible_start = self
 1777            .scroll_manager
 1778            .anchor()
 1779            .anchor
 1780            .to_point(&multi_buffer_snapshot);
 1781        let max_row = multi_buffer_snapshot.max_point().row;
 1782
 1783        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1784        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1785
 1786        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1787            let outline_items = buffer
 1788                .outline_items_containing(
 1789                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1790                    true,
 1791                    self.style().map(|style| style.syntax.as_ref()),
 1792                )
 1793                .into_iter()
 1794                .map(|outline_item| OutlineItem {
 1795                    depth: outline_item.depth,
 1796                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1797                    source_range_for_text: Anchor::range_in_buffer(
 1798                        *excerpt_id,
 1799                        outline_item.source_range_for_text,
 1800                    ),
 1801                    text: outline_item.text,
 1802                    highlight_ranges: outline_item.highlight_ranges,
 1803                    name_ranges: outline_item.name_ranges,
 1804                    body_range: outline_item
 1805                        .body_range
 1806                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1807                    annotation_range: outline_item
 1808                        .annotation_range
 1809                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1810                });
 1811            return Some(outline_items.collect());
 1812        }
 1813
 1814        None
 1815    }
 1816
 1817    fn new_internal(
 1818        mode: EditorMode,
 1819        multi_buffer: Entity<MultiBuffer>,
 1820        project: Option<Entity<Project>>,
 1821        display_map: Option<Entity<DisplayMap>>,
 1822        window: &mut Window,
 1823        cx: &mut Context<Self>,
 1824    ) -> Self {
 1825        debug_assert!(
 1826            display_map.is_none() || mode.is_minimap(),
 1827            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1828        );
 1829
 1830        let full_mode = mode.is_full();
 1831        let is_minimap = mode.is_minimap();
 1832        let diagnostics_max_severity = if full_mode {
 1833            EditorSettings::get_global(cx)
 1834                .diagnostics_max_severity
 1835                .unwrap_or(DiagnosticSeverity::Hint)
 1836        } else {
 1837            DiagnosticSeverity::Off
 1838        };
 1839        let style = window.text_style();
 1840        let font_size = style.font_size.to_pixels(window.rem_size());
 1841        let editor = cx.entity().downgrade();
 1842        let fold_placeholder = FoldPlaceholder {
 1843            constrain_width: false,
 1844            render: Arc::new(move |fold_id, fold_range, cx| {
 1845                let editor = editor.clone();
 1846                div()
 1847                    .id(fold_id)
 1848                    .bg(cx.theme().colors().ghost_element_background)
 1849                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1850                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1851                    .rounded_xs()
 1852                    .size_full()
 1853                    .cursor_pointer()
 1854                    .child("")
 1855                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1856                    .on_click(move |_, _window, cx| {
 1857                        editor
 1858                            .update(cx, |editor, cx| {
 1859                                editor.unfold_ranges(
 1860                                    &[fold_range.start..fold_range.end],
 1861                                    true,
 1862                                    false,
 1863                                    cx,
 1864                                );
 1865                                cx.stop_propagation();
 1866                            })
 1867                            .ok();
 1868                    })
 1869                    .into_any()
 1870            }),
 1871            merge_adjacent: true,
 1872            ..FoldPlaceholder::default()
 1873        };
 1874        let display_map = display_map.unwrap_or_else(|| {
 1875            cx.new(|cx| {
 1876                DisplayMap::new(
 1877                    multi_buffer.clone(),
 1878                    style.font(),
 1879                    font_size,
 1880                    None,
 1881                    FILE_HEADER_HEIGHT,
 1882                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1883                    fold_placeholder,
 1884                    diagnostics_max_severity,
 1885                    cx,
 1886                )
 1887            })
 1888        });
 1889
 1890        let selections = SelectionsCollection::new();
 1891
 1892        let blink_manager = cx.new(|cx| {
 1893            let mut blink_manager = BlinkManager::new(
 1894                CURSOR_BLINK_INTERVAL,
 1895                |cx| EditorSettings::get_global(cx).cursor_blink,
 1896                cx,
 1897            );
 1898            if is_minimap {
 1899                blink_manager.disable(cx);
 1900            }
 1901            blink_manager
 1902        });
 1903
 1904        let soft_wrap_mode_override =
 1905            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1906
 1907        let mut project_subscriptions = Vec::new();
 1908        if full_mode && let Some(project) = project.as_ref() {
 1909            project_subscriptions.push(cx.subscribe_in(
 1910                project,
 1911                window,
 1912                |editor, _, event, window, cx| match event {
 1913                    project::Event::RefreshCodeLens => {
 1914                        // we always query lens with actions, without storing them, always refreshing them
 1915                    }
 1916                    project::Event::RefreshInlayHints {
 1917                        server_id,
 1918                        request_id,
 1919                    } => {
 1920                        editor.refresh_inlay_hints(
 1921                            InlayHintRefreshReason::RefreshRequested {
 1922                                server_id: *server_id,
 1923                                request_id: *request_id,
 1924                            },
 1925                            cx,
 1926                        );
 1927                    }
 1928                    project::Event::LanguageServerRemoved(..) => {
 1929                        if editor.tasks_update_task.is_none() {
 1930                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1931                        }
 1932                        editor.registered_buffers.clear();
 1933                        editor.register_visible_buffers(cx);
 1934                    }
 1935                    project::Event::LanguageServerAdded(..) => {
 1936                        if editor.tasks_update_task.is_none() {
 1937                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1938                        }
 1939                    }
 1940                    project::Event::SnippetEdit(id, snippet_edits) => {
 1941                        // todo(lw): Non singletons
 1942                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1943                            let snapshot = buffer.read(cx).snapshot();
 1944                            let focus_handle = editor.focus_handle(cx);
 1945                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1946                                for (range, snippet) in snippet_edits {
 1947                                    let buffer_range =
 1948                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1949                                    editor
 1950                                        .insert_snippet(
 1951                                            &[MultiBufferOffset(buffer_range.start)
 1952                                                ..MultiBufferOffset(buffer_range.end)],
 1953                                            snippet.clone(),
 1954                                            window,
 1955                                            cx,
 1956                                        )
 1957                                        .ok();
 1958                                }
 1959                            }
 1960                        }
 1961                    }
 1962                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1963                        let buffer_id = *buffer_id;
 1964                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1965                            editor.register_buffer(buffer_id, cx);
 1966                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1967                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1968                            refresh_linked_ranges(editor, window, cx);
 1969                            editor.refresh_code_actions(window, cx);
 1970                            editor.refresh_document_highlights(cx);
 1971                        }
 1972                    }
 1973
 1974                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1975                        let Some(workspace) = editor.workspace() else {
 1976                            return;
 1977                        };
 1978                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1979                        else {
 1980                            return;
 1981                        };
 1982
 1983                        if active_editor.entity_id() == cx.entity_id() {
 1984                            let entity_id = cx.entity_id();
 1985                            workspace.update(cx, |this, cx| {
 1986                                this.panes_mut()
 1987                                    .iter_mut()
 1988                                    .filter(|pane| pane.entity_id() != entity_id)
 1989                                    .for_each(|p| {
 1990                                        p.update(cx, |pane, _| {
 1991                                            pane.nav_history_mut().rename_item(
 1992                                                entity_id,
 1993                                                project_path.clone(),
 1994                                                abs_path.clone().into(),
 1995                                            );
 1996                                        })
 1997                                    });
 1998                            });
 1999                            let edited_buffers_already_open = {
 2000                                let other_editors: Vec<Entity<Editor>> = workspace
 2001                                    .read(cx)
 2002                                    .panes()
 2003                                    .iter()
 2004                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2005                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2006                                    .collect();
 2007
 2008                                transaction.0.keys().all(|buffer| {
 2009                                    other_editors.iter().any(|editor| {
 2010                                        let multi_buffer = editor.read(cx).buffer();
 2011                                        multi_buffer.read(cx).is_singleton()
 2012                                            && multi_buffer.read(cx).as_singleton().map_or(
 2013                                                false,
 2014                                                |singleton| {
 2015                                                    singleton.entity_id() == buffer.entity_id()
 2016                                                },
 2017                                            )
 2018                                    })
 2019                                })
 2020                            };
 2021                            if !edited_buffers_already_open {
 2022                                let workspace = workspace.downgrade();
 2023                                let transaction = transaction.clone();
 2024                                cx.defer_in(window, move |_, window, cx| {
 2025                                    cx.spawn_in(window, async move |editor, cx| {
 2026                                        Self::open_project_transaction(
 2027                                            &editor,
 2028                                            workspace,
 2029                                            transaction,
 2030                                            "Rename".to_string(),
 2031                                            cx,
 2032                                        )
 2033                                        .await
 2034                                        .ok()
 2035                                    })
 2036                                    .detach();
 2037                                });
 2038                            }
 2039                        }
 2040                    }
 2041
 2042                    _ => {}
 2043                },
 2044            ));
 2045            if let Some(task_inventory) = project
 2046                .read(cx)
 2047                .task_store()
 2048                .read(cx)
 2049                .task_inventory()
 2050                .cloned()
 2051            {
 2052                project_subscriptions.push(cx.observe_in(
 2053                    &task_inventory,
 2054                    window,
 2055                    |editor, _, window, cx| {
 2056                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2057                    },
 2058                ));
 2059            };
 2060
 2061            project_subscriptions.push(cx.subscribe_in(
 2062                &project.read(cx).breakpoint_store(),
 2063                window,
 2064                |editor, _, event, window, cx| match event {
 2065                    BreakpointStoreEvent::ClearDebugLines => {
 2066                        editor.clear_row_highlights::<ActiveDebugLine>();
 2067                        editor.refresh_inline_values(cx);
 2068                    }
 2069                    BreakpointStoreEvent::SetDebugLine => {
 2070                        if editor.go_to_active_debug_line(window, cx) {
 2071                            cx.stop_propagation();
 2072                        }
 2073
 2074                        editor.refresh_inline_values(cx);
 2075                    }
 2076                    _ => {}
 2077                },
 2078            ));
 2079            let git_store = project.read(cx).git_store().clone();
 2080            let project = project.clone();
 2081            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2082                if let GitStoreEvent::RepositoryAdded = event {
 2083                    this.load_diff_task = Some(
 2084                        update_uncommitted_diff_for_buffer(
 2085                            cx.entity(),
 2086                            &project,
 2087                            this.buffer.read(cx).all_buffers(),
 2088                            this.buffer.clone(),
 2089                            cx,
 2090                        )
 2091                        .shared(),
 2092                    );
 2093                }
 2094            }));
 2095        }
 2096
 2097        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2098
 2099        let inlay_hint_settings =
 2100            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2101        let focus_handle = cx.focus_handle();
 2102        if !is_minimap {
 2103            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2104                .detach();
 2105            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2106                .detach();
 2107            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2108                .detach();
 2109            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2110                .detach();
 2111            cx.observe_pending_input(window, Self::observe_pending_input)
 2112                .detach();
 2113        }
 2114
 2115        let show_indent_guides =
 2116            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2117                Some(false)
 2118            } else {
 2119                None
 2120            };
 2121
 2122        let breakpoint_store = match (&mode, project.as_ref()) {
 2123            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2124            _ => None,
 2125        };
 2126
 2127        let mut code_action_providers = Vec::new();
 2128        let mut load_uncommitted_diff = None;
 2129        if let Some(project) = project.clone() {
 2130            load_uncommitted_diff = Some(
 2131                update_uncommitted_diff_for_buffer(
 2132                    cx.entity(),
 2133                    &project,
 2134                    multi_buffer.read(cx).all_buffers(),
 2135                    multi_buffer.clone(),
 2136                    cx,
 2137                )
 2138                .shared(),
 2139            );
 2140            code_action_providers.push(Rc::new(project) as Rc<_>);
 2141        }
 2142
 2143        let mut editor = Self {
 2144            focus_handle,
 2145            show_cursor_when_unfocused: false,
 2146            last_focused_descendant: None,
 2147            buffer: multi_buffer.clone(),
 2148            display_map: display_map.clone(),
 2149            placeholder_display_map: None,
 2150            selections,
 2151            scroll_manager: ScrollManager::new(cx),
 2152            columnar_selection_state: None,
 2153            add_selections_state: None,
 2154            select_next_state: None,
 2155            select_prev_state: None,
 2156            selection_history: SelectionHistory::default(),
 2157            defer_selection_effects: false,
 2158            deferred_selection_effects_state: None,
 2159            autoclose_regions: Vec::new(),
 2160            snippet_stack: InvalidationStack::default(),
 2161            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2162            ime_transaction: None,
 2163            active_diagnostics: ActiveDiagnostic::None,
 2164            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2165            inline_diagnostics_update: Task::ready(()),
 2166            inline_diagnostics: Vec::new(),
 2167            soft_wrap_mode_override,
 2168            diagnostics_max_severity,
 2169            hard_wrap: None,
 2170            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2171            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2172            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2173            project,
 2174            blink_manager: blink_manager.clone(),
 2175            show_local_selections: true,
 2176            show_scrollbars: ScrollbarAxes {
 2177                horizontal: full_mode,
 2178                vertical: full_mode,
 2179            },
 2180            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2181            offset_content: !matches!(mode, EditorMode::SingleLine),
 2182            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2183            show_gutter: full_mode,
 2184            show_line_numbers: (!full_mode).then_some(false),
 2185            use_relative_line_numbers: None,
 2186            disable_expand_excerpt_buttons: !full_mode,
 2187            show_git_diff_gutter: None,
 2188            show_code_actions: None,
 2189            show_runnables: None,
 2190            show_breakpoints: None,
 2191            show_wrap_guides: None,
 2192            show_indent_guides,
 2193            highlight_order: 0,
 2194            highlighted_rows: HashMap::default(),
 2195            background_highlights: HashMap::default(),
 2196            gutter_highlights: HashMap::default(),
 2197            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2198            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2199            nav_history: None,
 2200            context_menu: RefCell::new(None),
 2201            context_menu_options: None,
 2202            mouse_context_menu: None,
 2203            completion_tasks: Vec::new(),
 2204            inline_blame_popover: None,
 2205            inline_blame_popover_show_task: None,
 2206            signature_help_state: SignatureHelpState::default(),
 2207            auto_signature_help: None,
 2208            find_all_references_task_sources: Vec::new(),
 2209            next_completion_id: 0,
 2210            next_inlay_id: 0,
 2211            code_action_providers,
 2212            available_code_actions: None,
 2213            code_actions_task: None,
 2214            quick_selection_highlight_task: None,
 2215            debounced_selection_highlight_task: None,
 2216            document_highlights_task: None,
 2217            linked_editing_range_task: None,
 2218            pending_rename: None,
 2219            searchable: !is_minimap,
 2220            cursor_shape: EditorSettings::get_global(cx)
 2221                .cursor_shape
 2222                .unwrap_or_default(),
 2223            current_line_highlight: None,
 2224            autoindent_mode: Some(AutoindentMode::EachLine),
 2225            collapse_matches: false,
 2226            workspace: None,
 2227            input_enabled: !is_minimap,
 2228            use_modal_editing: full_mode,
 2229            read_only: is_minimap,
 2230            use_autoclose: true,
 2231            use_auto_surround: true,
 2232            auto_replace_emoji_shortcode: false,
 2233            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2234            leader_id: None,
 2235            remote_id: None,
 2236            hover_state: HoverState::default(),
 2237            pending_mouse_down: None,
 2238            hovered_link_state: None,
 2239            edit_prediction_provider: None,
 2240            active_edit_prediction: None,
 2241            stale_edit_prediction_in_menu: None,
 2242            edit_prediction_preview: EditPredictionPreview::Inactive {
 2243                released_too_fast: false,
 2244            },
 2245            inline_diagnostics_enabled: full_mode,
 2246            diagnostics_enabled: full_mode,
 2247            word_completions_enabled: full_mode,
 2248            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2249            gutter_hovered: false,
 2250            pixel_position_of_newest_cursor: None,
 2251            last_bounds: None,
 2252            last_position_map: None,
 2253            expect_bounds_change: None,
 2254            gutter_dimensions: GutterDimensions::default(),
 2255            style: None,
 2256            show_cursor_names: false,
 2257            hovered_cursors: HashMap::default(),
 2258            next_editor_action_id: EditorActionId::default(),
 2259            editor_actions: Rc::default(),
 2260            edit_predictions_hidden_for_vim_mode: false,
 2261            show_edit_predictions_override: None,
 2262            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2263            edit_prediction_settings: EditPredictionSettings::Disabled,
 2264            edit_prediction_indent_conflict: false,
 2265            edit_prediction_requires_modifier_in_indent_conflict: true,
 2266            custom_context_menu: None,
 2267            show_git_blame_gutter: false,
 2268            show_git_blame_inline: false,
 2269            show_selection_menu: None,
 2270            show_git_blame_inline_delay_task: None,
 2271            git_blame_inline_enabled: full_mode
 2272                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2273            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2274            buffer_serialization: is_minimap.not().then(|| {
 2275                BufferSerialization::new(
 2276                    ProjectSettings::get_global(cx)
 2277                        .session
 2278                        .restore_unsaved_buffers,
 2279                )
 2280            }),
 2281            blame: None,
 2282            blame_subscription: None,
 2283            tasks: BTreeMap::default(),
 2284
 2285            breakpoint_store,
 2286            gutter_breakpoint_indicator: (None, None),
 2287            hovered_diff_hunk_row: None,
 2288            _subscriptions: (!is_minimap)
 2289                .then(|| {
 2290                    vec![
 2291                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2292                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2293                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2294                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2295                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2296                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2297                        cx.observe_window_activation(window, |editor, window, cx| {
 2298                            let active = window.is_window_active();
 2299                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2300                                if active {
 2301                                    blink_manager.enable(cx);
 2302                                } else {
 2303                                    blink_manager.disable(cx);
 2304                                }
 2305                            });
 2306                            if active {
 2307                                editor.show_mouse_cursor(cx);
 2308                            }
 2309                        }),
 2310                    ]
 2311                })
 2312                .unwrap_or_default(),
 2313            tasks_update_task: None,
 2314            pull_diagnostics_task: Task::ready(()),
 2315            colors: None,
 2316            refresh_colors_task: Task::ready(()),
 2317            inlay_hints: None,
 2318            next_color_inlay_id: 0,
 2319            post_scroll_update: Task::ready(()),
 2320            linked_edit_ranges: Default::default(),
 2321            in_project_search: false,
 2322            previous_search_ranges: None,
 2323            breadcrumb_header: None,
 2324            focused_block: None,
 2325            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2326            addons: HashMap::default(),
 2327            registered_buffers: HashMap::default(),
 2328            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2329            selection_mark_mode: false,
 2330            toggle_fold_multiple_buffers: Task::ready(()),
 2331            serialize_selections: Task::ready(()),
 2332            serialize_folds: Task::ready(()),
 2333            text_style_refinement: None,
 2334            load_diff_task: load_uncommitted_diff,
 2335            temporary_diff_override: false,
 2336            mouse_cursor_hidden: false,
 2337            minimap: None,
 2338            hide_mouse_mode: EditorSettings::get_global(cx)
 2339                .hide_mouse
 2340                .unwrap_or_default(),
 2341            change_list: ChangeList::new(),
 2342            mode,
 2343            selection_drag_state: SelectionDragState::None,
 2344            folding_newlines: Task::ready(()),
 2345            lookup_key: None,
 2346            select_next_is_case_sensitive: None,
 2347            applicable_language_settings: HashMap::default(),
 2348            accent_overrides: Vec::new(),
 2349            fetched_tree_sitter_chunks: HashMap::default(),
 2350            use_base_text_line_numbers: false,
 2351        };
 2352
 2353        if is_minimap {
 2354            return editor;
 2355        }
 2356
 2357        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2358        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2359
 2360        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2361            editor
 2362                ._subscriptions
 2363                .push(cx.observe(breakpoints, |_, _, cx| {
 2364                    cx.notify();
 2365                }));
 2366        }
 2367        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2368        editor._subscriptions.extend(project_subscriptions);
 2369
 2370        editor._subscriptions.push(cx.subscribe_in(
 2371            &cx.entity(),
 2372            window,
 2373            |editor, _, e: &EditorEvent, window, cx| match e {
 2374                EditorEvent::ScrollPositionChanged { local, .. } => {
 2375                    if *local {
 2376                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2377                        editor.inline_blame_popover.take();
 2378                        let new_anchor = editor.scroll_manager.anchor();
 2379                        let snapshot = editor.snapshot(window, cx);
 2380                        editor.update_restoration_data(cx, move |data| {
 2381                            data.scroll_position = (
 2382                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2383                                new_anchor.offset,
 2384                            );
 2385                        });
 2386
 2387                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2388                            cx.background_executor()
 2389                                .timer(Duration::from_millis(50))
 2390                                .await;
 2391                            editor
 2392                                .update_in(cx, |editor, window, cx| {
 2393                                    editor.register_visible_buffers(cx);
 2394                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2395                                    editor.refresh_inlay_hints(
 2396                                        InlayHintRefreshReason::NewLinesShown,
 2397                                        cx,
 2398                                    );
 2399                                    editor.colorize_brackets(false, cx);
 2400                                })
 2401                                .ok();
 2402                        });
 2403                    }
 2404                }
 2405                EditorEvent::Edited { .. } => {
 2406                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2407                        .map(|vim_mode| vim_mode.0)
 2408                        .unwrap_or(false);
 2409                    if !vim_mode {
 2410                        let display_map = editor.display_snapshot(cx);
 2411                        let selections = editor.selections.all_adjusted_display(&display_map);
 2412                        let pop_state = editor
 2413                            .change_list
 2414                            .last()
 2415                            .map(|previous| {
 2416                                previous.len() == selections.len()
 2417                                    && previous.iter().enumerate().all(|(ix, p)| {
 2418                                        p.to_display_point(&display_map).row()
 2419                                            == selections[ix].head().row()
 2420                                    })
 2421                            })
 2422                            .unwrap_or(false);
 2423                        let new_positions = selections
 2424                            .into_iter()
 2425                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2426                            .collect();
 2427                        editor
 2428                            .change_list
 2429                            .push_to_change_list(pop_state, new_positions);
 2430                    }
 2431                }
 2432                _ => (),
 2433            },
 2434        ));
 2435
 2436        if let Some(dap_store) = editor
 2437            .project
 2438            .as_ref()
 2439            .map(|project| project.read(cx).dap_store())
 2440        {
 2441            let weak_editor = cx.weak_entity();
 2442
 2443            editor
 2444                ._subscriptions
 2445                .push(
 2446                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2447                        let session_entity = cx.entity();
 2448                        weak_editor
 2449                            .update(cx, |editor, cx| {
 2450                                editor._subscriptions.push(
 2451                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2452                                );
 2453                            })
 2454                            .ok();
 2455                    }),
 2456                );
 2457
 2458            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2459                editor
 2460                    ._subscriptions
 2461                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2462            }
 2463        }
 2464
 2465        // skip adding the initial selection to selection history
 2466        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2467        editor.end_selection(window, cx);
 2468        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2469
 2470        editor.scroll_manager.show_scrollbars(window, cx);
 2471        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2472
 2473        if full_mode {
 2474            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2475            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2476
 2477            if editor.git_blame_inline_enabled {
 2478                editor.start_git_blame_inline(false, window, cx);
 2479            }
 2480
 2481            editor.go_to_active_debug_line(window, cx);
 2482
 2483            editor.minimap =
 2484                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2485            editor.colors = Some(LspColorData::new(cx));
 2486            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2487
 2488            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2489                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2490            }
 2491            editor.update_lsp_data(None, window, cx);
 2492            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2493        }
 2494
 2495        editor
 2496    }
 2497
 2498    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2499        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2500    }
 2501
 2502    pub fn deploy_mouse_context_menu(
 2503        &mut self,
 2504        position: gpui::Point<Pixels>,
 2505        context_menu: Entity<ContextMenu>,
 2506        window: &mut Window,
 2507        cx: &mut Context<Self>,
 2508    ) {
 2509        self.mouse_context_menu = Some(MouseContextMenu::new(
 2510            self,
 2511            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2512            context_menu,
 2513            window,
 2514            cx,
 2515        ));
 2516    }
 2517
 2518    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2519        self.mouse_context_menu
 2520            .as_ref()
 2521            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2522    }
 2523
 2524    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2525        if self
 2526            .selections
 2527            .pending_anchor()
 2528            .is_some_and(|pending_selection| {
 2529                let snapshot = self.buffer().read(cx).snapshot(cx);
 2530                pending_selection.range().includes(range, &snapshot)
 2531            })
 2532        {
 2533            return true;
 2534        }
 2535
 2536        self.selections
 2537            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2538            .into_iter()
 2539            .any(|selection| {
 2540                // This is needed to cover a corner case, if we just check for an existing
 2541                // selection in the fold range, having a cursor at the start of the fold
 2542                // marks it as selected. Non-empty selections don't cause this.
 2543                let length = selection.end - selection.start;
 2544                length > 0
 2545            })
 2546    }
 2547
 2548    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2549        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2550    }
 2551
 2552    fn key_context_internal(
 2553        &self,
 2554        has_active_edit_prediction: bool,
 2555        window: &mut Window,
 2556        cx: &mut App,
 2557    ) -> KeyContext {
 2558        let mut key_context = KeyContext::new_with_defaults();
 2559        key_context.add("Editor");
 2560        let mode = match self.mode {
 2561            EditorMode::SingleLine => "single_line",
 2562            EditorMode::AutoHeight { .. } => "auto_height",
 2563            EditorMode::Minimap { .. } => "minimap",
 2564            EditorMode::Full { .. } => "full",
 2565        };
 2566
 2567        if EditorSettings::jupyter_enabled(cx) {
 2568            key_context.add("jupyter");
 2569        }
 2570
 2571        key_context.set("mode", mode);
 2572        if self.pending_rename.is_some() {
 2573            key_context.add("renaming");
 2574        }
 2575
 2576        if let Some(snippet_stack) = self.snippet_stack.last() {
 2577            key_context.add("in_snippet");
 2578
 2579            if snippet_stack.active_index > 0 {
 2580                key_context.add("has_previous_tabstop");
 2581            }
 2582
 2583            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2584                key_context.add("has_next_tabstop");
 2585            }
 2586        }
 2587
 2588        match self.context_menu.borrow().as_ref() {
 2589            Some(CodeContextMenu::Completions(menu)) => {
 2590                if menu.visible() {
 2591                    key_context.add("menu");
 2592                    key_context.add("showing_completions");
 2593                }
 2594            }
 2595            Some(CodeContextMenu::CodeActions(menu)) => {
 2596                if menu.visible() {
 2597                    key_context.add("menu");
 2598                    key_context.add("showing_code_actions")
 2599                }
 2600            }
 2601            None => {}
 2602        }
 2603
 2604        if self.signature_help_state.has_multiple_signatures() {
 2605            key_context.add("showing_signature_help");
 2606        }
 2607
 2608        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2609        if !self.focus_handle(cx).contains_focused(window, cx)
 2610            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2611        {
 2612            for addon in self.addons.values() {
 2613                addon.extend_key_context(&mut key_context, cx)
 2614            }
 2615        }
 2616
 2617        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2618            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2619                Some(
 2620                    file.full_path(cx)
 2621                        .extension()?
 2622                        .to_string_lossy()
 2623                        .into_owned(),
 2624                )
 2625            }) {
 2626                key_context.set("extension", extension);
 2627            }
 2628        } else {
 2629            key_context.add("multibuffer");
 2630        }
 2631
 2632        if has_active_edit_prediction {
 2633            if self.edit_prediction_in_conflict() {
 2634                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2635            } else {
 2636                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2637                key_context.add("copilot_suggestion");
 2638            }
 2639        }
 2640
 2641        if self.selection_mark_mode {
 2642            key_context.add("selection_mode");
 2643        }
 2644
 2645        let disjoint = self.selections.disjoint_anchors();
 2646        let snapshot = self.snapshot(window, cx);
 2647        let snapshot = snapshot.buffer_snapshot();
 2648        if self.mode == EditorMode::SingleLine
 2649            && let [selection] = disjoint
 2650            && selection.start == selection.end
 2651            && selection.end.to_offset(snapshot) == snapshot.len()
 2652        {
 2653            key_context.add("end_of_input");
 2654        }
 2655
 2656        if self.has_any_expanded_diff_hunks(cx) {
 2657            key_context.add("diffs_expanded");
 2658        }
 2659
 2660        key_context
 2661    }
 2662
 2663    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2664        self.last_bounds.as_ref()
 2665    }
 2666
 2667    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2668        if self.mouse_cursor_hidden {
 2669            self.mouse_cursor_hidden = false;
 2670            cx.notify();
 2671        }
 2672    }
 2673
 2674    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2675        let hide_mouse_cursor = match origin {
 2676            HideMouseCursorOrigin::TypingAction => {
 2677                matches!(
 2678                    self.hide_mouse_mode,
 2679                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2680                )
 2681            }
 2682            HideMouseCursorOrigin::MovementAction => {
 2683                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2684            }
 2685        };
 2686        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2687            self.mouse_cursor_hidden = hide_mouse_cursor;
 2688            cx.notify();
 2689        }
 2690    }
 2691
 2692    pub fn edit_prediction_in_conflict(&self) -> bool {
 2693        if !self.show_edit_predictions_in_menu() {
 2694            return false;
 2695        }
 2696
 2697        let showing_completions = self
 2698            .context_menu
 2699            .borrow()
 2700            .as_ref()
 2701            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2702
 2703        showing_completions
 2704            || self.edit_prediction_requires_modifier()
 2705            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2706            // bindings to insert tab characters.
 2707            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2708    }
 2709
 2710    pub fn accept_edit_prediction_keybind(
 2711        &self,
 2712        accept_partial: bool,
 2713        window: &mut Window,
 2714        cx: &mut App,
 2715    ) -> AcceptEditPredictionBinding {
 2716        let key_context = self.key_context_internal(true, window, cx);
 2717        let in_conflict = self.edit_prediction_in_conflict();
 2718
 2719        let bindings = if accept_partial {
 2720            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2721        } else {
 2722            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2723        };
 2724
 2725        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2726        // just the first one.
 2727        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2728            !in_conflict
 2729                || binding
 2730                    .keystrokes()
 2731                    .first()
 2732                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2733        }))
 2734    }
 2735
 2736    pub fn new_file(
 2737        workspace: &mut Workspace,
 2738        _: &workspace::NewFile,
 2739        window: &mut Window,
 2740        cx: &mut Context<Workspace>,
 2741    ) {
 2742        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2743            "Failed to create buffer",
 2744            window,
 2745            cx,
 2746            |e, _, _| match e.error_code() {
 2747                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2748                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2749                e.error_tag("required").unwrap_or("the latest version")
 2750            )),
 2751                _ => None,
 2752            },
 2753        );
 2754    }
 2755
 2756    pub fn new_in_workspace(
 2757        workspace: &mut Workspace,
 2758        window: &mut Window,
 2759        cx: &mut Context<Workspace>,
 2760    ) -> Task<Result<Entity<Editor>>> {
 2761        let project = workspace.project().clone();
 2762        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2763
 2764        cx.spawn_in(window, async move |workspace, cx| {
 2765            let buffer = create.await?;
 2766            workspace.update_in(cx, |workspace, window, cx| {
 2767                let editor =
 2768                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2769                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2770                editor
 2771            })
 2772        })
 2773    }
 2774
 2775    fn new_file_vertical(
 2776        workspace: &mut Workspace,
 2777        _: &workspace::NewFileSplitVertical,
 2778        window: &mut Window,
 2779        cx: &mut Context<Workspace>,
 2780    ) {
 2781        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2782    }
 2783
 2784    fn new_file_horizontal(
 2785        workspace: &mut Workspace,
 2786        _: &workspace::NewFileSplitHorizontal,
 2787        window: &mut Window,
 2788        cx: &mut Context<Workspace>,
 2789    ) {
 2790        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2791    }
 2792
 2793    fn new_file_split(
 2794        workspace: &mut Workspace,
 2795        action: &workspace::NewFileSplit,
 2796        window: &mut Window,
 2797        cx: &mut Context<Workspace>,
 2798    ) {
 2799        Self::new_file_in_direction(workspace, action.0, window, cx)
 2800    }
 2801
 2802    fn new_file_in_direction(
 2803        workspace: &mut Workspace,
 2804        direction: SplitDirection,
 2805        window: &mut Window,
 2806        cx: &mut Context<Workspace>,
 2807    ) {
 2808        let project = workspace.project().clone();
 2809        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2810
 2811        cx.spawn_in(window, async move |workspace, cx| {
 2812            let buffer = create.await?;
 2813            workspace.update_in(cx, move |workspace, window, cx| {
 2814                workspace.split_item(
 2815                    direction,
 2816                    Box::new(
 2817                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2818                    ),
 2819                    window,
 2820                    cx,
 2821                )
 2822            })?;
 2823            anyhow::Ok(())
 2824        })
 2825        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2826            match e.error_code() {
 2827                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2828                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2829                e.error_tag("required").unwrap_or("the latest version")
 2830            )),
 2831                _ => None,
 2832            }
 2833        });
 2834    }
 2835
 2836    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2837        self.leader_id
 2838    }
 2839
 2840    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2841        &self.buffer
 2842    }
 2843
 2844    pub fn project(&self) -> Option<&Entity<Project>> {
 2845        self.project.as_ref()
 2846    }
 2847
 2848    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2849        self.workspace.as_ref()?.0.upgrade()
 2850    }
 2851
 2852    /// Returns the workspace serialization ID if this editor should be serialized.
 2853    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2854        self.workspace
 2855            .as_ref()
 2856            .filter(|_| self.should_serialize_buffer())
 2857            .and_then(|workspace| workspace.1)
 2858    }
 2859
 2860    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2861        self.buffer().read(cx).title(cx)
 2862    }
 2863
 2864    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2865        let git_blame_gutter_max_author_length = self
 2866            .render_git_blame_gutter(cx)
 2867            .then(|| {
 2868                if let Some(blame) = self.blame.as_ref() {
 2869                    let max_author_length =
 2870                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2871                    Some(max_author_length)
 2872                } else {
 2873                    None
 2874                }
 2875            })
 2876            .flatten();
 2877
 2878        EditorSnapshot {
 2879            mode: self.mode.clone(),
 2880            show_gutter: self.show_gutter,
 2881            show_line_numbers: self.show_line_numbers,
 2882            show_git_diff_gutter: self.show_git_diff_gutter,
 2883            show_code_actions: self.show_code_actions,
 2884            show_runnables: self.show_runnables,
 2885            show_breakpoints: self.show_breakpoints,
 2886            git_blame_gutter_max_author_length,
 2887            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2888            placeholder_display_snapshot: self
 2889                .placeholder_display_map
 2890                .as_ref()
 2891                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2892            scroll_anchor: self.scroll_manager.anchor(),
 2893            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2894            is_focused: self.focus_handle.is_focused(window),
 2895            current_line_highlight: self
 2896                .current_line_highlight
 2897                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2898            gutter_hovered: self.gutter_hovered,
 2899        }
 2900    }
 2901
 2902    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2903        self.buffer.read(cx).language_at(point, cx)
 2904    }
 2905
 2906    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2907        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2908    }
 2909
 2910    pub fn active_excerpt(
 2911        &self,
 2912        cx: &App,
 2913    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2914        self.buffer
 2915            .read(cx)
 2916            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2917    }
 2918
 2919    pub fn mode(&self) -> &EditorMode {
 2920        &self.mode
 2921    }
 2922
 2923    pub fn set_mode(&mut self, mode: EditorMode) {
 2924        self.mode = mode;
 2925    }
 2926
 2927    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2928        self.collaboration_hub.as_deref()
 2929    }
 2930
 2931    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2932        self.collaboration_hub = Some(hub);
 2933    }
 2934
 2935    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2936        self.in_project_search = in_project_search;
 2937    }
 2938
 2939    pub fn set_custom_context_menu(
 2940        &mut self,
 2941        f: impl 'static
 2942        + Fn(
 2943            &mut Self,
 2944            DisplayPoint,
 2945            &mut Window,
 2946            &mut Context<Self>,
 2947        ) -> Option<Entity<ui::ContextMenu>>,
 2948    ) {
 2949        self.custom_context_menu = Some(Box::new(f))
 2950    }
 2951
 2952    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2953        self.completion_provider = provider;
 2954    }
 2955
 2956    #[cfg(any(test, feature = "test-support"))]
 2957    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2958        self.completion_provider.clone()
 2959    }
 2960
 2961    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2962        self.semantics_provider.clone()
 2963    }
 2964
 2965    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2966        self.semantics_provider = provider;
 2967    }
 2968
 2969    pub fn set_edit_prediction_provider<T>(
 2970        &mut self,
 2971        provider: Option<Entity<T>>,
 2972        window: &mut Window,
 2973        cx: &mut Context<Self>,
 2974    ) where
 2975        T: EditPredictionProvider,
 2976    {
 2977        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2978            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2979                if this.focus_handle.is_focused(window) {
 2980                    this.update_visible_edit_prediction(window, cx);
 2981                }
 2982            }),
 2983            provider: Arc::new(provider),
 2984        });
 2985        self.update_edit_prediction_settings(cx);
 2986        self.refresh_edit_prediction(false, false, window, cx);
 2987    }
 2988
 2989    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2990        self.placeholder_display_map
 2991            .as_ref()
 2992            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2993    }
 2994
 2995    pub fn set_placeholder_text(
 2996        &mut self,
 2997        placeholder_text: &str,
 2998        window: &mut Window,
 2999        cx: &mut Context<Self>,
 3000    ) {
 3001        let multibuffer = cx
 3002            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3003
 3004        let style = window.text_style();
 3005
 3006        self.placeholder_display_map = Some(cx.new(|cx| {
 3007            DisplayMap::new(
 3008                multibuffer,
 3009                style.font(),
 3010                style.font_size.to_pixels(window.rem_size()),
 3011                None,
 3012                FILE_HEADER_HEIGHT,
 3013                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3014                Default::default(),
 3015                DiagnosticSeverity::Off,
 3016                cx,
 3017            )
 3018        }));
 3019        cx.notify();
 3020    }
 3021
 3022    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3023        self.cursor_shape = cursor_shape;
 3024
 3025        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3026        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3027
 3028        cx.notify();
 3029    }
 3030
 3031    pub fn cursor_shape(&self) -> CursorShape {
 3032        self.cursor_shape
 3033    }
 3034
 3035    pub fn set_current_line_highlight(
 3036        &mut self,
 3037        current_line_highlight: Option<CurrentLineHighlight>,
 3038    ) {
 3039        self.current_line_highlight = current_line_highlight;
 3040    }
 3041
 3042    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3043        self.collapse_matches = collapse_matches;
 3044    }
 3045
 3046    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3047        if self.collapse_matches {
 3048            return range.start..range.start;
 3049        }
 3050        range.clone()
 3051    }
 3052
 3053    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3054        self.display_map.read(cx).clip_at_line_ends
 3055    }
 3056
 3057    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3058        if self.display_map.read(cx).clip_at_line_ends != clip {
 3059            self.display_map
 3060                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3061        }
 3062    }
 3063
 3064    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3065        self.input_enabled = input_enabled;
 3066    }
 3067
 3068    pub fn set_edit_predictions_hidden_for_vim_mode(
 3069        &mut self,
 3070        hidden: bool,
 3071        window: &mut Window,
 3072        cx: &mut Context<Self>,
 3073    ) {
 3074        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3075            self.edit_predictions_hidden_for_vim_mode = hidden;
 3076            if hidden {
 3077                self.update_visible_edit_prediction(window, cx);
 3078            } else {
 3079                self.refresh_edit_prediction(true, false, window, cx);
 3080            }
 3081        }
 3082    }
 3083
 3084    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3085        self.menu_edit_predictions_policy = value;
 3086    }
 3087
 3088    pub fn set_autoindent(&mut self, autoindent: bool) {
 3089        if autoindent {
 3090            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3091        } else {
 3092            self.autoindent_mode = None;
 3093        }
 3094    }
 3095
 3096    pub fn read_only(&self, cx: &App) -> bool {
 3097        self.read_only || self.buffer.read(cx).read_only()
 3098    }
 3099
 3100    pub fn set_read_only(&mut self, read_only: bool) {
 3101        self.read_only = read_only;
 3102    }
 3103
 3104    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3105        self.use_autoclose = autoclose;
 3106    }
 3107
 3108    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3109        self.use_auto_surround = auto_surround;
 3110    }
 3111
 3112    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3113        self.auto_replace_emoji_shortcode = auto_replace;
 3114    }
 3115
 3116    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3117        self.buffer_serialization = should_serialize.then(|| {
 3118            BufferSerialization::new(
 3119                ProjectSettings::get_global(cx)
 3120                    .session
 3121                    .restore_unsaved_buffers,
 3122            )
 3123        })
 3124    }
 3125
 3126    fn should_serialize_buffer(&self) -> bool {
 3127        self.buffer_serialization.is_some()
 3128    }
 3129
 3130    pub fn toggle_edit_predictions(
 3131        &mut self,
 3132        _: &ToggleEditPrediction,
 3133        window: &mut Window,
 3134        cx: &mut Context<Self>,
 3135    ) {
 3136        if self.show_edit_predictions_override.is_some() {
 3137            self.set_show_edit_predictions(None, window, cx);
 3138        } else {
 3139            let show_edit_predictions = !self.edit_predictions_enabled();
 3140            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3141        }
 3142    }
 3143
 3144    pub fn set_show_edit_predictions(
 3145        &mut self,
 3146        show_edit_predictions: Option<bool>,
 3147        window: &mut Window,
 3148        cx: &mut Context<Self>,
 3149    ) {
 3150        self.show_edit_predictions_override = show_edit_predictions;
 3151        self.update_edit_prediction_settings(cx);
 3152
 3153        if let Some(false) = show_edit_predictions {
 3154            self.discard_edit_prediction(false, cx);
 3155        } else {
 3156            self.refresh_edit_prediction(false, true, window, cx);
 3157        }
 3158    }
 3159
 3160    fn edit_predictions_disabled_in_scope(
 3161        &self,
 3162        buffer: &Entity<Buffer>,
 3163        buffer_position: language::Anchor,
 3164        cx: &App,
 3165    ) -> bool {
 3166        let snapshot = buffer.read(cx).snapshot();
 3167        let settings = snapshot.settings_at(buffer_position, cx);
 3168
 3169        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3170            return false;
 3171        };
 3172
 3173        scope.override_name().is_some_and(|scope_name| {
 3174            settings
 3175                .edit_predictions_disabled_in
 3176                .iter()
 3177                .any(|s| s == scope_name)
 3178        })
 3179    }
 3180
 3181    pub fn set_use_modal_editing(&mut self, to: bool) {
 3182        self.use_modal_editing = to;
 3183    }
 3184
 3185    pub fn use_modal_editing(&self) -> bool {
 3186        self.use_modal_editing
 3187    }
 3188
 3189    fn selections_did_change(
 3190        &mut self,
 3191        local: bool,
 3192        old_cursor_position: &Anchor,
 3193        effects: SelectionEffects,
 3194        window: &mut Window,
 3195        cx: &mut Context<Self>,
 3196    ) {
 3197        window.invalidate_character_coordinates();
 3198
 3199        // Copy selections to primary selection buffer
 3200        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3201        if local {
 3202            let selections = self
 3203                .selections
 3204                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3205            let buffer_handle = self.buffer.read(cx).read(cx);
 3206
 3207            let mut text = String::new();
 3208            for (index, selection) in selections.iter().enumerate() {
 3209                let text_for_selection = buffer_handle
 3210                    .text_for_range(selection.start..selection.end)
 3211                    .collect::<String>();
 3212
 3213                text.push_str(&text_for_selection);
 3214                if index != selections.len() - 1 {
 3215                    text.push('\n');
 3216                }
 3217            }
 3218
 3219            if !text.is_empty() {
 3220                cx.write_to_primary(ClipboardItem::new_string(text));
 3221            }
 3222        }
 3223
 3224        let selection_anchors = self.selections.disjoint_anchors_arc();
 3225
 3226        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3227            self.buffer.update(cx, |buffer, cx| {
 3228                buffer.set_active_selections(
 3229                    &selection_anchors,
 3230                    self.selections.line_mode(),
 3231                    self.cursor_shape,
 3232                    cx,
 3233                )
 3234            });
 3235        }
 3236        let display_map = self
 3237            .display_map
 3238            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3239        let buffer = display_map.buffer_snapshot();
 3240        if self.selections.count() == 1 {
 3241            self.add_selections_state = None;
 3242        }
 3243        self.select_next_state = None;
 3244        self.select_prev_state = None;
 3245        self.select_syntax_node_history.try_clear();
 3246        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3247        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3248        self.take_rename(false, window, cx);
 3249
 3250        let newest_selection = self.selections.newest_anchor();
 3251        let new_cursor_position = newest_selection.head();
 3252        let selection_start = newest_selection.start;
 3253
 3254        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3255            self.push_to_nav_history(
 3256                *old_cursor_position,
 3257                Some(new_cursor_position.to_point(buffer)),
 3258                false,
 3259                effects.nav_history == Some(true),
 3260                cx,
 3261            );
 3262        }
 3263
 3264        if local {
 3265            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3266                self.register_buffer(buffer_id, cx);
 3267            }
 3268
 3269            let mut context_menu = self.context_menu.borrow_mut();
 3270            let completion_menu = match context_menu.as_ref() {
 3271                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3272                Some(CodeContextMenu::CodeActions(_)) => {
 3273                    *context_menu = None;
 3274                    None
 3275                }
 3276                None => None,
 3277            };
 3278            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3279            drop(context_menu);
 3280
 3281            if effects.completions
 3282                && let Some(completion_position) = completion_position
 3283            {
 3284                let start_offset = selection_start.to_offset(buffer);
 3285                let position_matches = start_offset == completion_position.to_offset(buffer);
 3286                let continue_showing = if position_matches {
 3287                    if self.snippet_stack.is_empty() {
 3288                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3289                            == Some(CharKind::Word)
 3290                    } else {
 3291                        // Snippet choices can be shown even when the cursor is in whitespace.
 3292                        // Dismissing the menu with actions like backspace is handled by
 3293                        // invalidation regions.
 3294                        true
 3295                    }
 3296                } else {
 3297                    false
 3298                };
 3299
 3300                if continue_showing {
 3301                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3302                } else {
 3303                    self.hide_context_menu(window, cx);
 3304                }
 3305            }
 3306
 3307            hide_hover(self, cx);
 3308
 3309            if old_cursor_position.to_display_point(&display_map).row()
 3310                != new_cursor_position.to_display_point(&display_map).row()
 3311            {
 3312                self.available_code_actions.take();
 3313            }
 3314            self.refresh_code_actions(window, cx);
 3315            self.refresh_document_highlights(cx);
 3316            refresh_linked_ranges(self, window, cx);
 3317
 3318            self.refresh_selected_text_highlights(false, window, cx);
 3319            self.refresh_matching_bracket_highlights(window, cx);
 3320            self.update_visible_edit_prediction(window, cx);
 3321            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3322            self.inline_blame_popover.take();
 3323            if self.git_blame_inline_enabled {
 3324                self.start_inline_blame_timer(window, cx);
 3325            }
 3326        }
 3327
 3328        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3329        cx.emit(EditorEvent::SelectionsChanged { local });
 3330
 3331        let selections = &self.selections.disjoint_anchors_arc();
 3332        if selections.len() == 1 {
 3333            cx.emit(SearchEvent::ActiveMatchChanged)
 3334        }
 3335        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3336            let inmemory_selections = selections
 3337                .iter()
 3338                .map(|s| {
 3339                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3340                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3341                })
 3342                .collect();
 3343            self.update_restoration_data(cx, |data| {
 3344                data.selections = inmemory_selections;
 3345            });
 3346
 3347            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3348                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3349            {
 3350                let snapshot = self.buffer().read(cx).snapshot(cx);
 3351                let selections = selections.clone();
 3352                let background_executor = cx.background_executor().clone();
 3353                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3354                self.serialize_selections = cx.background_spawn(async move {
 3355                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3356                    let db_selections = selections
 3357                        .iter()
 3358                        .map(|selection| {
 3359                            (
 3360                                selection.start.to_offset(&snapshot).0,
 3361                                selection.end.to_offset(&snapshot).0,
 3362                            )
 3363                        })
 3364                        .collect();
 3365
 3366                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3367                        .await
 3368                        .with_context(|| {
 3369                            format!(
 3370                                "persisting editor selections for editor {editor_id}, \
 3371                                workspace {workspace_id:?}"
 3372                            )
 3373                        })
 3374                        .log_err();
 3375                });
 3376            }
 3377        }
 3378
 3379        cx.notify();
 3380    }
 3381
 3382    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3383        use text::ToOffset as _;
 3384        use text::ToPoint as _;
 3385
 3386        if self.mode.is_minimap()
 3387            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3388        {
 3389            return;
 3390        }
 3391
 3392        if !self.buffer().read(cx).is_singleton() {
 3393            return;
 3394        }
 3395
 3396        let display_snapshot = self
 3397            .display_map
 3398            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3399        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3400            return;
 3401        };
 3402        let inmemory_folds = display_snapshot
 3403            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3404            .map(|fold| {
 3405                fold.range.start.text_anchor.to_point(&snapshot)
 3406                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3407            })
 3408            .collect();
 3409        self.update_restoration_data(cx, |data| {
 3410            data.folds = inmemory_folds;
 3411        });
 3412
 3413        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3414            return;
 3415        };
 3416        let background_executor = cx.background_executor().clone();
 3417        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3418        let db_folds = display_snapshot
 3419            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3420            .map(|fold| {
 3421                (
 3422                    fold.range.start.text_anchor.to_offset(&snapshot),
 3423                    fold.range.end.text_anchor.to_offset(&snapshot),
 3424                )
 3425            })
 3426            .collect();
 3427        self.serialize_folds = cx.background_spawn(async move {
 3428            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3429            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3430                .await
 3431                .with_context(|| {
 3432                    format!(
 3433                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3434                    )
 3435                })
 3436                .log_err();
 3437        });
 3438    }
 3439
 3440    pub fn sync_selections(
 3441        &mut self,
 3442        other: Entity<Editor>,
 3443        cx: &mut Context<Self>,
 3444    ) -> gpui::Subscription {
 3445        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3446        if !other_selections.is_empty() {
 3447            self.selections
 3448                .change_with(&self.display_snapshot(cx), |selections| {
 3449                    selections.select_anchors(other_selections);
 3450                });
 3451        }
 3452
 3453        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3454            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3455                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3456                if other_selections.is_empty() {
 3457                    return;
 3458                }
 3459                let snapshot = this.display_snapshot(cx);
 3460                this.selections.change_with(&snapshot, |selections| {
 3461                    selections.select_anchors(other_selections);
 3462                });
 3463            }
 3464        });
 3465
 3466        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3467            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3468                let these_selections = this.selections.disjoint_anchors().to_vec();
 3469                if these_selections.is_empty() {
 3470                    return;
 3471                }
 3472                other.update(cx, |other_editor, cx| {
 3473                    let snapshot = other_editor.display_snapshot(cx);
 3474                    other_editor
 3475                        .selections
 3476                        .change_with(&snapshot, |selections| {
 3477                            selections.select_anchors(these_selections);
 3478                        })
 3479                });
 3480            }
 3481        });
 3482
 3483        Subscription::join(other_subscription, this_subscription)
 3484    }
 3485
 3486    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3487        if self.buffer().read(cx).is_singleton() {
 3488            return;
 3489        }
 3490        let snapshot = self.buffer.read(cx).snapshot(cx);
 3491        let buffer_ids: HashSet<BufferId> = self
 3492            .selections
 3493            .disjoint_anchor_ranges()
 3494            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3495            .collect();
 3496        for buffer_id in buffer_ids {
 3497            self.unfold_buffer(buffer_id, cx);
 3498        }
 3499    }
 3500
 3501    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3502    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3503    /// effects of selection change occur at the end of the transaction.
 3504    pub fn change_selections<R>(
 3505        &mut self,
 3506        effects: SelectionEffects,
 3507        window: &mut Window,
 3508        cx: &mut Context<Self>,
 3509        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3510    ) -> R {
 3511        let snapshot = self.display_snapshot(cx);
 3512        if let Some(state) = &mut self.deferred_selection_effects_state {
 3513            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3514            state.effects.completions = effects.completions;
 3515            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3516            let (changed, result) = self.selections.change_with(&snapshot, change);
 3517            state.changed |= changed;
 3518            return result;
 3519        }
 3520        let mut state = DeferredSelectionEffectsState {
 3521            changed: false,
 3522            effects,
 3523            old_cursor_position: self.selections.newest_anchor().head(),
 3524            history_entry: SelectionHistoryEntry {
 3525                selections: self.selections.disjoint_anchors_arc(),
 3526                select_next_state: self.select_next_state.clone(),
 3527                select_prev_state: self.select_prev_state.clone(),
 3528                add_selections_state: self.add_selections_state.clone(),
 3529            },
 3530        };
 3531        let (changed, result) = self.selections.change_with(&snapshot, change);
 3532        state.changed = state.changed || changed;
 3533        if self.defer_selection_effects {
 3534            self.deferred_selection_effects_state = Some(state);
 3535        } else {
 3536            self.apply_selection_effects(state, window, cx);
 3537        }
 3538        result
 3539    }
 3540
 3541    /// Defers the effects of selection change, so that the effects of multiple calls to
 3542    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3543    /// to selection history and the state of popovers based on selection position aren't
 3544    /// erroneously updated.
 3545    pub fn with_selection_effects_deferred<R>(
 3546        &mut self,
 3547        window: &mut Window,
 3548        cx: &mut Context<Self>,
 3549        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3550    ) -> R {
 3551        let already_deferred = self.defer_selection_effects;
 3552        self.defer_selection_effects = true;
 3553        let result = update(self, window, cx);
 3554        if !already_deferred {
 3555            self.defer_selection_effects = false;
 3556            if let Some(state) = self.deferred_selection_effects_state.take() {
 3557                self.apply_selection_effects(state, window, cx);
 3558            }
 3559        }
 3560        result
 3561    }
 3562
 3563    fn apply_selection_effects(
 3564        &mut self,
 3565        state: DeferredSelectionEffectsState,
 3566        window: &mut Window,
 3567        cx: &mut Context<Self>,
 3568    ) {
 3569        if state.changed {
 3570            self.selection_history.push(state.history_entry);
 3571
 3572            if let Some(autoscroll) = state.effects.scroll {
 3573                self.request_autoscroll(autoscroll, cx);
 3574            }
 3575
 3576            let old_cursor_position = &state.old_cursor_position;
 3577
 3578            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3579
 3580            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3581                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3582            }
 3583        }
 3584    }
 3585
 3586    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3587    where
 3588        I: IntoIterator<Item = (Range<S>, T)>,
 3589        S: ToOffset,
 3590        T: Into<Arc<str>>,
 3591    {
 3592        if self.read_only(cx) {
 3593            return;
 3594        }
 3595
 3596        self.buffer
 3597            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3598    }
 3599
 3600    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3601    where
 3602        I: IntoIterator<Item = (Range<S>, T)>,
 3603        S: ToOffset,
 3604        T: Into<Arc<str>>,
 3605    {
 3606        if self.read_only(cx) {
 3607            return;
 3608        }
 3609
 3610        self.buffer.update(cx, |buffer, cx| {
 3611            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3612        });
 3613    }
 3614
 3615    pub fn edit_with_block_indent<I, S, T>(
 3616        &mut self,
 3617        edits: I,
 3618        original_indent_columns: Vec<Option<u32>>,
 3619        cx: &mut Context<Self>,
 3620    ) where
 3621        I: IntoIterator<Item = (Range<S>, T)>,
 3622        S: ToOffset,
 3623        T: Into<Arc<str>>,
 3624    {
 3625        if self.read_only(cx) {
 3626            return;
 3627        }
 3628
 3629        self.buffer.update(cx, |buffer, cx| {
 3630            buffer.edit(
 3631                edits,
 3632                Some(AutoindentMode::Block {
 3633                    original_indent_columns,
 3634                }),
 3635                cx,
 3636            )
 3637        });
 3638    }
 3639
 3640    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3641        self.hide_context_menu(window, cx);
 3642
 3643        match phase {
 3644            SelectPhase::Begin {
 3645                position,
 3646                add,
 3647                click_count,
 3648            } => self.begin_selection(position, add, click_count, window, cx),
 3649            SelectPhase::BeginColumnar {
 3650                position,
 3651                goal_column,
 3652                reset,
 3653                mode,
 3654            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3655            SelectPhase::Extend {
 3656                position,
 3657                click_count,
 3658            } => self.extend_selection(position, click_count, window, cx),
 3659            SelectPhase::Update {
 3660                position,
 3661                goal_column,
 3662                scroll_delta,
 3663            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3664            SelectPhase::End => self.end_selection(window, cx),
 3665        }
 3666    }
 3667
 3668    fn extend_selection(
 3669        &mut self,
 3670        position: DisplayPoint,
 3671        click_count: usize,
 3672        window: &mut Window,
 3673        cx: &mut Context<Self>,
 3674    ) {
 3675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3676        let tail = self
 3677            .selections
 3678            .newest::<MultiBufferOffset>(&display_map)
 3679            .tail();
 3680        let click_count = click_count.max(match self.selections.select_mode() {
 3681            SelectMode::Character => 1,
 3682            SelectMode::Word(_) => 2,
 3683            SelectMode::Line(_) => 3,
 3684            SelectMode::All => 4,
 3685        });
 3686        self.begin_selection(position, false, click_count, window, cx);
 3687
 3688        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3689
 3690        let current_selection = match self.selections.select_mode() {
 3691            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3692            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3693        };
 3694
 3695        let mut pending_selection = self
 3696            .selections
 3697            .pending_anchor()
 3698            .cloned()
 3699            .expect("extend_selection not called with pending selection");
 3700
 3701        if pending_selection
 3702            .start
 3703            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3704            == Ordering::Greater
 3705        {
 3706            pending_selection.start = current_selection.start;
 3707        }
 3708        if pending_selection
 3709            .end
 3710            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3711            == Ordering::Less
 3712        {
 3713            pending_selection.end = current_selection.end;
 3714            pending_selection.reversed = true;
 3715        }
 3716
 3717        let mut pending_mode = self.selections.pending_mode().unwrap();
 3718        match &mut pending_mode {
 3719            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3720            _ => {}
 3721        }
 3722
 3723        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3724            SelectionEffects::scroll(Autoscroll::fit())
 3725        } else {
 3726            SelectionEffects::no_scroll()
 3727        };
 3728
 3729        self.change_selections(effects, window, cx, |s| {
 3730            s.set_pending(pending_selection.clone(), pending_mode);
 3731            s.set_is_extending(true);
 3732        });
 3733    }
 3734
 3735    fn begin_selection(
 3736        &mut self,
 3737        position: DisplayPoint,
 3738        add: bool,
 3739        click_count: usize,
 3740        window: &mut Window,
 3741        cx: &mut Context<Self>,
 3742    ) {
 3743        if !self.focus_handle.is_focused(window) {
 3744            self.last_focused_descendant = None;
 3745            window.focus(&self.focus_handle);
 3746        }
 3747
 3748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3749        let buffer = display_map.buffer_snapshot();
 3750        let position = display_map.clip_point(position, Bias::Left);
 3751
 3752        let start;
 3753        let end;
 3754        let mode;
 3755        let mut auto_scroll;
 3756        match click_count {
 3757            1 => {
 3758                start = buffer.anchor_before(position.to_point(&display_map));
 3759                end = start;
 3760                mode = SelectMode::Character;
 3761                auto_scroll = true;
 3762            }
 3763            2 => {
 3764                let position = display_map
 3765                    .clip_point(position, Bias::Left)
 3766                    .to_offset(&display_map, Bias::Left);
 3767                let (range, _) = buffer.surrounding_word(position, None);
 3768                start = buffer.anchor_before(range.start);
 3769                end = buffer.anchor_before(range.end);
 3770                mode = SelectMode::Word(start..end);
 3771                auto_scroll = true;
 3772            }
 3773            3 => {
 3774                let position = display_map
 3775                    .clip_point(position, Bias::Left)
 3776                    .to_point(&display_map);
 3777                let line_start = display_map.prev_line_boundary(position).0;
 3778                let next_line_start = buffer.clip_point(
 3779                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3780                    Bias::Left,
 3781                );
 3782                start = buffer.anchor_before(line_start);
 3783                end = buffer.anchor_before(next_line_start);
 3784                mode = SelectMode::Line(start..end);
 3785                auto_scroll = true;
 3786            }
 3787            _ => {
 3788                start = buffer.anchor_before(MultiBufferOffset(0));
 3789                end = buffer.anchor_before(buffer.len());
 3790                mode = SelectMode::All;
 3791                auto_scroll = false;
 3792            }
 3793        }
 3794        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3795
 3796        let point_to_delete: Option<usize> = {
 3797            let selected_points: Vec<Selection<Point>> =
 3798                self.selections.disjoint_in_range(start..end, &display_map);
 3799
 3800            if !add || click_count > 1 {
 3801                None
 3802            } else if !selected_points.is_empty() {
 3803                Some(selected_points[0].id)
 3804            } else {
 3805                let clicked_point_already_selected =
 3806                    self.selections.disjoint_anchors().iter().find(|selection| {
 3807                        selection.start.to_point(buffer) == start.to_point(buffer)
 3808                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3809                    });
 3810
 3811                clicked_point_already_selected.map(|selection| selection.id)
 3812            }
 3813        };
 3814
 3815        let selections_count = self.selections.count();
 3816        let effects = if auto_scroll {
 3817            SelectionEffects::default()
 3818        } else {
 3819            SelectionEffects::no_scroll()
 3820        };
 3821
 3822        self.change_selections(effects, window, cx, |s| {
 3823            if let Some(point_to_delete) = point_to_delete {
 3824                s.delete(point_to_delete);
 3825
 3826                if selections_count == 1 {
 3827                    s.set_pending_anchor_range(start..end, mode);
 3828                }
 3829            } else {
 3830                if !add {
 3831                    s.clear_disjoint();
 3832                }
 3833
 3834                s.set_pending_anchor_range(start..end, mode);
 3835            }
 3836        });
 3837    }
 3838
 3839    fn begin_columnar_selection(
 3840        &mut self,
 3841        position: DisplayPoint,
 3842        goal_column: u32,
 3843        reset: bool,
 3844        mode: ColumnarMode,
 3845        window: &mut Window,
 3846        cx: &mut Context<Self>,
 3847    ) {
 3848        if !self.focus_handle.is_focused(window) {
 3849            self.last_focused_descendant = None;
 3850            window.focus(&self.focus_handle);
 3851        }
 3852
 3853        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3854
 3855        if reset {
 3856            let pointer_position = display_map
 3857                .buffer_snapshot()
 3858                .anchor_before(position.to_point(&display_map));
 3859
 3860            self.change_selections(
 3861                SelectionEffects::scroll(Autoscroll::newest()),
 3862                window,
 3863                cx,
 3864                |s| {
 3865                    s.clear_disjoint();
 3866                    s.set_pending_anchor_range(
 3867                        pointer_position..pointer_position,
 3868                        SelectMode::Character,
 3869                    );
 3870                },
 3871            );
 3872        };
 3873
 3874        let tail = self.selections.newest::<Point>(&display_map).tail();
 3875        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3876        self.columnar_selection_state = match mode {
 3877            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3878                selection_tail: selection_anchor,
 3879                display_point: if reset {
 3880                    if position.column() != goal_column {
 3881                        Some(DisplayPoint::new(position.row(), goal_column))
 3882                    } else {
 3883                        None
 3884                    }
 3885                } else {
 3886                    None
 3887                },
 3888            }),
 3889            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3890                selection_tail: selection_anchor,
 3891            }),
 3892        };
 3893
 3894        if !reset {
 3895            self.select_columns(position, goal_column, &display_map, window, cx);
 3896        }
 3897    }
 3898
 3899    fn update_selection(
 3900        &mut self,
 3901        position: DisplayPoint,
 3902        goal_column: u32,
 3903        scroll_delta: gpui::Point<f32>,
 3904        window: &mut Window,
 3905        cx: &mut Context<Self>,
 3906    ) {
 3907        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3908
 3909        if self.columnar_selection_state.is_some() {
 3910            self.select_columns(position, goal_column, &display_map, window, cx);
 3911        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3912            let buffer = display_map.buffer_snapshot();
 3913            let head;
 3914            let tail;
 3915            let mode = self.selections.pending_mode().unwrap();
 3916            match &mode {
 3917                SelectMode::Character => {
 3918                    head = position.to_point(&display_map);
 3919                    tail = pending.tail().to_point(buffer);
 3920                }
 3921                SelectMode::Word(original_range) => {
 3922                    let offset = display_map
 3923                        .clip_point(position, Bias::Left)
 3924                        .to_offset(&display_map, Bias::Left);
 3925                    let original_range = original_range.to_offset(buffer);
 3926
 3927                    let head_offset = if buffer.is_inside_word(offset, None)
 3928                        || original_range.contains(&offset)
 3929                    {
 3930                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3931                        if word_range.start < original_range.start {
 3932                            word_range.start
 3933                        } else {
 3934                            word_range.end
 3935                        }
 3936                    } else {
 3937                        offset
 3938                    };
 3939
 3940                    head = head_offset.to_point(buffer);
 3941                    if head_offset <= original_range.start {
 3942                        tail = original_range.end.to_point(buffer);
 3943                    } else {
 3944                        tail = original_range.start.to_point(buffer);
 3945                    }
 3946                }
 3947                SelectMode::Line(original_range) => {
 3948                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3949
 3950                    let position = display_map
 3951                        .clip_point(position, Bias::Left)
 3952                        .to_point(&display_map);
 3953                    let line_start = display_map.prev_line_boundary(position).0;
 3954                    let next_line_start = buffer.clip_point(
 3955                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3956                        Bias::Left,
 3957                    );
 3958
 3959                    if line_start < original_range.start {
 3960                        head = line_start
 3961                    } else {
 3962                        head = next_line_start
 3963                    }
 3964
 3965                    if head <= original_range.start {
 3966                        tail = original_range.end;
 3967                    } else {
 3968                        tail = original_range.start;
 3969                    }
 3970                }
 3971                SelectMode::All => {
 3972                    return;
 3973                }
 3974            };
 3975
 3976            if head < tail {
 3977                pending.start = buffer.anchor_before(head);
 3978                pending.end = buffer.anchor_before(tail);
 3979                pending.reversed = true;
 3980            } else {
 3981                pending.start = buffer.anchor_before(tail);
 3982                pending.end = buffer.anchor_before(head);
 3983                pending.reversed = false;
 3984            }
 3985
 3986            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3987                s.set_pending(pending.clone(), mode);
 3988            });
 3989        } else {
 3990            log::error!("update_selection dispatched with no pending selection");
 3991            return;
 3992        }
 3993
 3994        self.apply_scroll_delta(scroll_delta, window, cx);
 3995        cx.notify();
 3996    }
 3997
 3998    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3999        self.columnar_selection_state.take();
 4000        if let Some(pending_mode) = self.selections.pending_mode() {
 4001            let selections = self
 4002                .selections
 4003                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4004            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4005                s.select(selections);
 4006                s.clear_pending();
 4007                if s.is_extending() {
 4008                    s.set_is_extending(false);
 4009                } else {
 4010                    s.set_select_mode(pending_mode);
 4011                }
 4012            });
 4013        }
 4014    }
 4015
 4016    fn select_columns(
 4017        &mut self,
 4018        head: DisplayPoint,
 4019        goal_column: u32,
 4020        display_map: &DisplaySnapshot,
 4021        window: &mut Window,
 4022        cx: &mut Context<Self>,
 4023    ) {
 4024        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4025            return;
 4026        };
 4027
 4028        let tail = match columnar_state {
 4029            ColumnarSelectionState::FromMouse {
 4030                selection_tail,
 4031                display_point,
 4032            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4033            ColumnarSelectionState::FromSelection { selection_tail } => {
 4034                selection_tail.to_display_point(display_map)
 4035            }
 4036        };
 4037
 4038        let start_row = cmp::min(tail.row(), head.row());
 4039        let end_row = cmp::max(tail.row(), head.row());
 4040        let start_column = cmp::min(tail.column(), goal_column);
 4041        let end_column = cmp::max(tail.column(), goal_column);
 4042        let reversed = start_column < tail.column();
 4043
 4044        let selection_ranges = (start_row.0..=end_row.0)
 4045            .map(DisplayRow)
 4046            .filter_map(|row| {
 4047                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4048                    || start_column <= display_map.line_len(row))
 4049                    && !display_map.is_block_line(row)
 4050                {
 4051                    let start = display_map
 4052                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4053                        .to_point(display_map);
 4054                    let end = display_map
 4055                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4056                        .to_point(display_map);
 4057                    if reversed {
 4058                        Some(end..start)
 4059                    } else {
 4060                        Some(start..end)
 4061                    }
 4062                } else {
 4063                    None
 4064                }
 4065            })
 4066            .collect::<Vec<_>>();
 4067        if selection_ranges.is_empty() {
 4068            return;
 4069        }
 4070
 4071        let ranges = match columnar_state {
 4072            ColumnarSelectionState::FromMouse { .. } => {
 4073                let mut non_empty_ranges = selection_ranges
 4074                    .iter()
 4075                    .filter(|selection_range| selection_range.start != selection_range.end)
 4076                    .peekable();
 4077                if non_empty_ranges.peek().is_some() {
 4078                    non_empty_ranges.cloned().collect()
 4079                } else {
 4080                    selection_ranges
 4081                }
 4082            }
 4083            _ => selection_ranges,
 4084        };
 4085
 4086        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4087            s.select_ranges(ranges);
 4088        });
 4089        cx.notify();
 4090    }
 4091
 4092    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4093        self.selections
 4094            .all_adjusted(snapshot)
 4095            .iter()
 4096            .any(|selection| !selection.is_empty())
 4097    }
 4098
 4099    pub fn has_pending_nonempty_selection(&self) -> bool {
 4100        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4101            Some(Selection { start, end, .. }) => start != end,
 4102            None => false,
 4103        };
 4104
 4105        pending_nonempty_selection
 4106            || (self.columnar_selection_state.is_some()
 4107                && self.selections.disjoint_anchors().len() > 1)
 4108    }
 4109
 4110    pub fn has_pending_selection(&self) -> bool {
 4111        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4112    }
 4113
 4114    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4115        self.selection_mark_mode = false;
 4116        self.selection_drag_state = SelectionDragState::None;
 4117
 4118        if self.dismiss_menus_and_popups(true, window, cx) {
 4119            cx.notify();
 4120            return;
 4121        }
 4122        if self.clear_expanded_diff_hunks(cx) {
 4123            cx.notify();
 4124            return;
 4125        }
 4126        if self.show_git_blame_gutter {
 4127            self.show_git_blame_gutter = false;
 4128            cx.notify();
 4129            return;
 4130        }
 4131
 4132        if self.mode.is_full()
 4133            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4134        {
 4135            cx.notify();
 4136            return;
 4137        }
 4138
 4139        cx.propagate();
 4140    }
 4141
 4142    pub fn dismiss_menus_and_popups(
 4143        &mut self,
 4144        is_user_requested: bool,
 4145        window: &mut Window,
 4146        cx: &mut Context<Self>,
 4147    ) -> bool {
 4148        let mut dismissed = false;
 4149
 4150        dismissed |= self.take_rename(false, window, cx).is_some();
 4151        dismissed |= self.hide_blame_popover(true, cx);
 4152        dismissed |= hide_hover(self, cx);
 4153        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4154        dismissed |= self.hide_context_menu(window, cx).is_some();
 4155        dismissed |= self.mouse_context_menu.take().is_some();
 4156        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4157        dismissed |= self.snippet_stack.pop().is_some();
 4158
 4159        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4160            self.dismiss_diagnostics(cx);
 4161            dismissed = true;
 4162        }
 4163
 4164        dismissed
 4165    }
 4166
 4167    fn linked_editing_ranges_for(
 4168        &self,
 4169        selection: Range<text::Anchor>,
 4170        cx: &App,
 4171    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4172        if self.linked_edit_ranges.is_empty() {
 4173            return None;
 4174        }
 4175        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4176            selection.end.buffer_id.and_then(|end_buffer_id| {
 4177                if selection.start.buffer_id != Some(end_buffer_id) {
 4178                    return None;
 4179                }
 4180                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4181                let snapshot = buffer.read(cx).snapshot();
 4182                self.linked_edit_ranges
 4183                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4184                    .map(|ranges| (ranges, snapshot, buffer))
 4185            })?;
 4186        use text::ToOffset as TO;
 4187        // find offset from the start of current range to current cursor position
 4188        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4189
 4190        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4191        let start_difference = start_offset - start_byte_offset;
 4192        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4193        let end_difference = end_offset - start_byte_offset;
 4194        // Current range has associated linked ranges.
 4195        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4196        for range in linked_ranges.iter() {
 4197            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4198            let end_offset = start_offset + end_difference;
 4199            let start_offset = start_offset + start_difference;
 4200            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4201                continue;
 4202            }
 4203            if self.selections.disjoint_anchor_ranges().any(|s| {
 4204                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4205                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4206                {
 4207                    return false;
 4208                }
 4209                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4210                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4211            }) {
 4212                continue;
 4213            }
 4214            let start = buffer_snapshot.anchor_after(start_offset);
 4215            let end = buffer_snapshot.anchor_after(end_offset);
 4216            linked_edits
 4217                .entry(buffer.clone())
 4218                .or_default()
 4219                .push(start..end);
 4220        }
 4221        Some(linked_edits)
 4222    }
 4223
 4224    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4225        let text: Arc<str> = text.into();
 4226
 4227        if self.read_only(cx) {
 4228            return;
 4229        }
 4230
 4231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4232
 4233        self.unfold_buffers_with_selections(cx);
 4234
 4235        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4236        let mut bracket_inserted = false;
 4237        let mut edits = Vec::new();
 4238        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4239        let mut new_selections = Vec::with_capacity(selections.len());
 4240        let mut new_autoclose_regions = Vec::new();
 4241        let snapshot = self.buffer.read(cx).read(cx);
 4242        let mut clear_linked_edit_ranges = false;
 4243
 4244        for (selection, autoclose_region) in
 4245            self.selections_with_autoclose_regions(selections, &snapshot)
 4246        {
 4247            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4248                // Determine if the inserted text matches the opening or closing
 4249                // bracket of any of this language's bracket pairs.
 4250                let mut bracket_pair = None;
 4251                let mut is_bracket_pair_start = false;
 4252                let mut is_bracket_pair_end = false;
 4253                if !text.is_empty() {
 4254                    let mut bracket_pair_matching_end = None;
 4255                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4256                    //  and they are removing the character that triggered IME popup.
 4257                    for (pair, enabled) in scope.brackets() {
 4258                        if !pair.close && !pair.surround {
 4259                            continue;
 4260                        }
 4261
 4262                        if enabled && pair.start.ends_with(text.as_ref()) {
 4263                            let prefix_len = pair.start.len() - text.len();
 4264                            let preceding_text_matches_prefix = prefix_len == 0
 4265                                || (selection.start.column >= (prefix_len as u32)
 4266                                    && snapshot.contains_str_at(
 4267                                        Point::new(
 4268                                            selection.start.row,
 4269                                            selection.start.column - (prefix_len as u32),
 4270                                        ),
 4271                                        &pair.start[..prefix_len],
 4272                                    ));
 4273                            if preceding_text_matches_prefix {
 4274                                bracket_pair = Some(pair.clone());
 4275                                is_bracket_pair_start = true;
 4276                                break;
 4277                            }
 4278                        }
 4279                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4280                        {
 4281                            // take first bracket pair matching end, but don't break in case a later bracket
 4282                            // pair matches start
 4283                            bracket_pair_matching_end = Some(pair.clone());
 4284                        }
 4285                    }
 4286                    if let Some(end) = bracket_pair_matching_end
 4287                        && bracket_pair.is_none()
 4288                    {
 4289                        bracket_pair = Some(end);
 4290                        is_bracket_pair_end = true;
 4291                    }
 4292                }
 4293
 4294                if let Some(bracket_pair) = bracket_pair {
 4295                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4296                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4297                    let auto_surround =
 4298                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4299                    if selection.is_empty() {
 4300                        if is_bracket_pair_start {
 4301                            // If the inserted text is a suffix of an opening bracket and the
 4302                            // selection is preceded by the rest of the opening bracket, then
 4303                            // insert the closing bracket.
 4304                            let following_text_allows_autoclose = snapshot
 4305                                .chars_at(selection.start)
 4306                                .next()
 4307                                .is_none_or(|c| scope.should_autoclose_before(c));
 4308
 4309                            let preceding_text_allows_autoclose = selection.start.column == 0
 4310                                || snapshot
 4311                                    .reversed_chars_at(selection.start)
 4312                                    .next()
 4313                                    .is_none_or(|c| {
 4314                                        bracket_pair.start != bracket_pair.end
 4315                                            || !snapshot
 4316                                                .char_classifier_at(selection.start)
 4317                                                .is_word(c)
 4318                                    });
 4319
 4320                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4321                                && bracket_pair.start.len() == 1
 4322                            {
 4323                                let target = bracket_pair.start.chars().next().unwrap();
 4324                                let current_line_count = snapshot
 4325                                    .reversed_chars_at(selection.start)
 4326                                    .take_while(|&c| c != '\n')
 4327                                    .filter(|&c| c == target)
 4328                                    .count();
 4329                                current_line_count % 2 == 1
 4330                            } else {
 4331                                false
 4332                            };
 4333
 4334                            if autoclose
 4335                                && bracket_pair.close
 4336                                && following_text_allows_autoclose
 4337                                && preceding_text_allows_autoclose
 4338                                && !is_closing_quote
 4339                            {
 4340                                let anchor = snapshot.anchor_before(selection.end);
 4341                                new_selections.push((selection.map(|_| anchor), text.len()));
 4342                                new_autoclose_regions.push((
 4343                                    anchor,
 4344                                    text.len(),
 4345                                    selection.id,
 4346                                    bracket_pair.clone(),
 4347                                ));
 4348                                edits.push((
 4349                                    selection.range(),
 4350                                    format!("{}{}", text, bracket_pair.end).into(),
 4351                                ));
 4352                                bracket_inserted = true;
 4353                                continue;
 4354                            }
 4355                        }
 4356
 4357                        if let Some(region) = autoclose_region {
 4358                            // If the selection is followed by an auto-inserted closing bracket,
 4359                            // then don't insert that closing bracket again; just move the selection
 4360                            // past the closing bracket.
 4361                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4362                                && text.as_ref() == region.pair.end.as_str()
 4363                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4364                            if should_skip {
 4365                                let anchor = snapshot.anchor_after(selection.end);
 4366                                new_selections
 4367                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4368                                continue;
 4369                            }
 4370                        }
 4371
 4372                        let always_treat_brackets_as_autoclosed = snapshot
 4373                            .language_settings_at(selection.start, cx)
 4374                            .always_treat_brackets_as_autoclosed;
 4375                        if always_treat_brackets_as_autoclosed
 4376                            && is_bracket_pair_end
 4377                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4378                        {
 4379                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4380                            // and the inserted text is a closing bracket and the selection is followed
 4381                            // by the closing bracket then move the selection past the closing bracket.
 4382                            let anchor = snapshot.anchor_after(selection.end);
 4383                            new_selections.push((selection.map(|_| anchor), text.len()));
 4384                            continue;
 4385                        }
 4386                    }
 4387                    // If an opening bracket is 1 character long and is typed while
 4388                    // text is selected, then surround that text with the bracket pair.
 4389                    else if auto_surround
 4390                        && bracket_pair.surround
 4391                        && is_bracket_pair_start
 4392                        && bracket_pair.start.chars().count() == 1
 4393                    {
 4394                        edits.push((selection.start..selection.start, text.clone()));
 4395                        edits.push((
 4396                            selection.end..selection.end,
 4397                            bracket_pair.end.as_str().into(),
 4398                        ));
 4399                        bracket_inserted = true;
 4400                        new_selections.push((
 4401                            Selection {
 4402                                id: selection.id,
 4403                                start: snapshot.anchor_after(selection.start),
 4404                                end: snapshot.anchor_before(selection.end),
 4405                                reversed: selection.reversed,
 4406                                goal: selection.goal,
 4407                            },
 4408                            0,
 4409                        ));
 4410                        continue;
 4411                    }
 4412                }
 4413            }
 4414
 4415            if self.auto_replace_emoji_shortcode
 4416                && selection.is_empty()
 4417                && text.as_ref().ends_with(':')
 4418                && let Some(possible_emoji_short_code) =
 4419                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4420                && !possible_emoji_short_code.is_empty()
 4421                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4422            {
 4423                let emoji_shortcode_start = Point::new(
 4424                    selection.start.row,
 4425                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4426                );
 4427
 4428                // Remove shortcode from buffer
 4429                edits.push((
 4430                    emoji_shortcode_start..selection.start,
 4431                    "".to_string().into(),
 4432                ));
 4433                new_selections.push((
 4434                    Selection {
 4435                        id: selection.id,
 4436                        start: snapshot.anchor_after(emoji_shortcode_start),
 4437                        end: snapshot.anchor_before(selection.start),
 4438                        reversed: selection.reversed,
 4439                        goal: selection.goal,
 4440                    },
 4441                    0,
 4442                ));
 4443
 4444                // Insert emoji
 4445                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4446                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4447                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4448
 4449                continue;
 4450            }
 4451
 4452            // If not handling any auto-close operation, then just replace the selected
 4453            // text with the given input and move the selection to the end of the
 4454            // newly inserted text.
 4455            let anchor = snapshot.anchor_after(selection.end);
 4456            if !self.linked_edit_ranges.is_empty() {
 4457                let start_anchor = snapshot.anchor_before(selection.start);
 4458
 4459                let is_word_char = text.chars().next().is_none_or(|char| {
 4460                    let classifier = snapshot
 4461                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4462                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4463                    classifier.is_word(char)
 4464                });
 4465
 4466                if is_word_char {
 4467                    if let Some(ranges) = self
 4468                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4469                    {
 4470                        for (buffer, edits) in ranges {
 4471                            linked_edits
 4472                                .entry(buffer.clone())
 4473                                .or_default()
 4474                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4475                        }
 4476                    }
 4477                } else {
 4478                    clear_linked_edit_ranges = true;
 4479                }
 4480            }
 4481
 4482            new_selections.push((selection.map(|_| anchor), 0));
 4483            edits.push((selection.start..selection.end, text.clone()));
 4484        }
 4485
 4486        drop(snapshot);
 4487
 4488        self.transact(window, cx, |this, window, cx| {
 4489            if clear_linked_edit_ranges {
 4490                this.linked_edit_ranges.clear();
 4491            }
 4492            let initial_buffer_versions =
 4493                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4494
 4495            this.buffer.update(cx, |buffer, cx| {
 4496                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4497            });
 4498            for (buffer, edits) in linked_edits {
 4499                buffer.update(cx, |buffer, cx| {
 4500                    let snapshot = buffer.snapshot();
 4501                    let edits = edits
 4502                        .into_iter()
 4503                        .map(|(range, text)| {
 4504                            use text::ToPoint as TP;
 4505                            let end_point = TP::to_point(&range.end, &snapshot);
 4506                            let start_point = TP::to_point(&range.start, &snapshot);
 4507                            (start_point..end_point, text)
 4508                        })
 4509                        .sorted_by_key(|(range, _)| range.start);
 4510                    buffer.edit(edits, None, cx);
 4511                })
 4512            }
 4513            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4514            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4515            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4516            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4517                new_anchor_selections,
 4518                &map,
 4519            )
 4520            .zip(new_selection_deltas)
 4521            .map(|(selection, delta)| Selection {
 4522                id: selection.id,
 4523                start: selection.start + delta,
 4524                end: selection.end + delta,
 4525                reversed: selection.reversed,
 4526                goal: SelectionGoal::None,
 4527            })
 4528            .collect::<Vec<_>>();
 4529
 4530            let mut i = 0;
 4531            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4532                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4533                let start = map.buffer_snapshot().anchor_before(position);
 4534                let end = map.buffer_snapshot().anchor_after(position);
 4535                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4536                    match existing_state
 4537                        .range
 4538                        .start
 4539                        .cmp(&start, map.buffer_snapshot())
 4540                    {
 4541                        Ordering::Less => i += 1,
 4542                        Ordering::Greater => break,
 4543                        Ordering::Equal => {
 4544                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4545                                Ordering::Less => i += 1,
 4546                                Ordering::Equal => break,
 4547                                Ordering::Greater => break,
 4548                            }
 4549                        }
 4550                    }
 4551                }
 4552                this.autoclose_regions.insert(
 4553                    i,
 4554                    AutocloseRegion {
 4555                        selection_id,
 4556                        range: start..end,
 4557                        pair,
 4558                    },
 4559                );
 4560            }
 4561
 4562            let had_active_edit_prediction = this.has_active_edit_prediction();
 4563            this.change_selections(
 4564                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4565                window,
 4566                cx,
 4567                |s| s.select(new_selections),
 4568            );
 4569
 4570            if !bracket_inserted
 4571                && let Some(on_type_format_task) =
 4572                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4573            {
 4574                on_type_format_task.detach_and_log_err(cx);
 4575            }
 4576
 4577            let editor_settings = EditorSettings::get_global(cx);
 4578            if bracket_inserted
 4579                && (editor_settings.auto_signature_help
 4580                    || editor_settings.show_signature_help_after_edits)
 4581            {
 4582                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4583            }
 4584
 4585            let trigger_in_words =
 4586                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4587            if this.hard_wrap.is_some() {
 4588                let latest: Range<Point> = this.selections.newest(&map).range();
 4589                if latest.is_empty()
 4590                    && this
 4591                        .buffer()
 4592                        .read(cx)
 4593                        .snapshot(cx)
 4594                        .line_len(MultiBufferRow(latest.start.row))
 4595                        == latest.start.column
 4596                {
 4597                    this.rewrap_impl(
 4598                        RewrapOptions {
 4599                            override_language_settings: true,
 4600                            preserve_existing_whitespace: true,
 4601                        },
 4602                        cx,
 4603                    )
 4604                }
 4605            }
 4606            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4607            refresh_linked_ranges(this, window, cx);
 4608            this.refresh_edit_prediction(true, false, window, cx);
 4609            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4610        });
 4611    }
 4612
 4613    fn find_possible_emoji_shortcode_at_position(
 4614        snapshot: &MultiBufferSnapshot,
 4615        position: Point,
 4616    ) -> Option<String> {
 4617        let mut chars = Vec::new();
 4618        let mut found_colon = false;
 4619        for char in snapshot.reversed_chars_at(position).take(100) {
 4620            // Found a possible emoji shortcode in the middle of the buffer
 4621            if found_colon {
 4622                if char.is_whitespace() {
 4623                    chars.reverse();
 4624                    return Some(chars.iter().collect());
 4625                }
 4626                // If the previous character is not a whitespace, we are in the middle of a word
 4627                // and we only want to complete the shortcode if the word is made up of other emojis
 4628                let mut containing_word = String::new();
 4629                for ch in snapshot
 4630                    .reversed_chars_at(position)
 4631                    .skip(chars.len() + 1)
 4632                    .take(100)
 4633                {
 4634                    if ch.is_whitespace() {
 4635                        break;
 4636                    }
 4637                    containing_word.push(ch);
 4638                }
 4639                let containing_word = containing_word.chars().rev().collect::<String>();
 4640                if util::word_consists_of_emojis(containing_word.as_str()) {
 4641                    chars.reverse();
 4642                    return Some(chars.iter().collect());
 4643                }
 4644            }
 4645
 4646            if char.is_whitespace() || !char.is_ascii() {
 4647                return None;
 4648            }
 4649            if char == ':' {
 4650                found_colon = true;
 4651            } else {
 4652                chars.push(char);
 4653            }
 4654        }
 4655        // Found a possible emoji shortcode at the beginning of the buffer
 4656        chars.reverse();
 4657        Some(chars.iter().collect())
 4658    }
 4659
 4660    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4662        self.transact(window, cx, |this, window, cx| {
 4663            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4664                let selections = this
 4665                    .selections
 4666                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4667                let multi_buffer = this.buffer.read(cx);
 4668                let buffer = multi_buffer.snapshot(cx);
 4669                selections
 4670                    .iter()
 4671                    .map(|selection| {
 4672                        let start_point = selection.start.to_point(&buffer);
 4673                        let mut existing_indent =
 4674                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4675                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4676                        let start = selection.start;
 4677                        let end = selection.end;
 4678                        let selection_is_empty = start == end;
 4679                        let language_scope = buffer.language_scope_at(start);
 4680                        let (
 4681                            comment_delimiter,
 4682                            doc_delimiter,
 4683                            insert_extra_newline,
 4684                            indent_on_newline,
 4685                            indent_on_extra_newline,
 4686                        ) = if let Some(language) = &language_scope {
 4687                            let mut insert_extra_newline =
 4688                                insert_extra_newline_brackets(&buffer, start..end, language)
 4689                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4690
 4691                            // Comment extension on newline is allowed only for cursor selections
 4692                            let comment_delimiter = maybe!({
 4693                                if !selection_is_empty {
 4694                                    return None;
 4695                                }
 4696
 4697                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4698                                    return None;
 4699                                }
 4700
 4701                                let delimiters = language.line_comment_prefixes();
 4702                                let max_len_of_delimiter =
 4703                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4704                                let (snapshot, range) =
 4705                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4706
 4707                                let num_of_whitespaces = snapshot
 4708                                    .chars_for_range(range.clone())
 4709                                    .take_while(|c| c.is_whitespace())
 4710                                    .count();
 4711                                let comment_candidate = snapshot
 4712                                    .chars_for_range(range.clone())
 4713                                    .skip(num_of_whitespaces)
 4714                                    .take(max_len_of_delimiter)
 4715                                    .collect::<String>();
 4716                                let (delimiter, trimmed_len) = delimiters
 4717                                    .iter()
 4718                                    .filter_map(|delimiter| {
 4719                                        let prefix = delimiter.trim_end();
 4720                                        if comment_candidate.starts_with(prefix) {
 4721                                            Some((delimiter, prefix.len()))
 4722                                        } else {
 4723                                            None
 4724                                        }
 4725                                    })
 4726                                    .max_by_key(|(_, len)| *len)?;
 4727
 4728                                if let Some(BlockCommentConfig {
 4729                                    start: block_start, ..
 4730                                }) = language.block_comment()
 4731                                {
 4732                                    let block_start_trimmed = block_start.trim_end();
 4733                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4734                                        let line_content = snapshot
 4735                                            .chars_for_range(range)
 4736                                            .skip(num_of_whitespaces)
 4737                                            .take(block_start_trimmed.len())
 4738                                            .collect::<String>();
 4739
 4740                                        if line_content.starts_with(block_start_trimmed) {
 4741                                            return None;
 4742                                        }
 4743                                    }
 4744                                }
 4745
 4746                                let cursor_is_placed_after_comment_marker =
 4747                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4748                                if cursor_is_placed_after_comment_marker {
 4749                                    Some(delimiter.clone())
 4750                                } else {
 4751                                    None
 4752                                }
 4753                            });
 4754
 4755                            let mut indent_on_newline = IndentSize::spaces(0);
 4756                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4757
 4758                            let doc_delimiter = maybe!({
 4759                                if !selection_is_empty {
 4760                                    return None;
 4761                                }
 4762
 4763                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4764                                    return None;
 4765                                }
 4766
 4767                                let BlockCommentConfig {
 4768                                    start: start_tag,
 4769                                    end: end_tag,
 4770                                    prefix: delimiter,
 4771                                    tab_size: len,
 4772                                } = language.documentation_comment()?;
 4773                                let is_within_block_comment = buffer
 4774                                    .language_scope_at(start_point)
 4775                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4776                                if !is_within_block_comment {
 4777                                    return None;
 4778                                }
 4779
 4780                                let (snapshot, range) =
 4781                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4782
 4783                                let num_of_whitespaces = snapshot
 4784                                    .chars_for_range(range.clone())
 4785                                    .take_while(|c| c.is_whitespace())
 4786                                    .count();
 4787
 4788                                // 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.
 4789                                let column = start_point.column;
 4790                                let cursor_is_after_start_tag = {
 4791                                    let start_tag_len = start_tag.len();
 4792                                    let start_tag_line = snapshot
 4793                                        .chars_for_range(range.clone())
 4794                                        .skip(num_of_whitespaces)
 4795                                        .take(start_tag_len)
 4796                                        .collect::<String>();
 4797                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4798                                        num_of_whitespaces + start_tag_len <= column as usize
 4799                                    } else {
 4800                                        false
 4801                                    }
 4802                                };
 4803
 4804                                let cursor_is_after_delimiter = {
 4805                                    let delimiter_trim = delimiter.trim_end();
 4806                                    let delimiter_line = snapshot
 4807                                        .chars_for_range(range.clone())
 4808                                        .skip(num_of_whitespaces)
 4809                                        .take(delimiter_trim.len())
 4810                                        .collect::<String>();
 4811                                    if delimiter_line.starts_with(delimiter_trim) {
 4812                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4813                                    } else {
 4814                                        false
 4815                                    }
 4816                                };
 4817
 4818                                let cursor_is_before_end_tag_if_exists = {
 4819                                    let mut char_position = 0u32;
 4820                                    let mut end_tag_offset = None;
 4821
 4822                                    'outer: for chunk in snapshot.text_for_range(range) {
 4823                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4824                                            let chars_before_match =
 4825                                                chunk[..byte_pos].chars().count() as u32;
 4826                                            end_tag_offset =
 4827                                                Some(char_position + chars_before_match);
 4828                                            break 'outer;
 4829                                        }
 4830                                        char_position += chunk.chars().count() as u32;
 4831                                    }
 4832
 4833                                    if let Some(end_tag_offset) = end_tag_offset {
 4834                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4835                                        if cursor_is_after_start_tag {
 4836                                            if cursor_is_before_end_tag {
 4837                                                insert_extra_newline = true;
 4838                                            }
 4839                                            let cursor_is_at_start_of_end_tag =
 4840                                                column == end_tag_offset;
 4841                                            if cursor_is_at_start_of_end_tag {
 4842                                                indent_on_extra_newline.len = *len;
 4843                                            }
 4844                                        }
 4845                                        cursor_is_before_end_tag
 4846                                    } else {
 4847                                        true
 4848                                    }
 4849                                };
 4850
 4851                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4852                                    && cursor_is_before_end_tag_if_exists
 4853                                {
 4854                                    if cursor_is_after_start_tag {
 4855                                        indent_on_newline.len = *len;
 4856                                    }
 4857                                    Some(delimiter.clone())
 4858                                } else {
 4859                                    None
 4860                                }
 4861                            });
 4862
 4863                            (
 4864                                comment_delimiter,
 4865                                doc_delimiter,
 4866                                insert_extra_newline,
 4867                                indent_on_newline,
 4868                                indent_on_extra_newline,
 4869                            )
 4870                        } else {
 4871                            (
 4872                                None,
 4873                                None,
 4874                                false,
 4875                                IndentSize::default(),
 4876                                IndentSize::default(),
 4877                            )
 4878                        };
 4879
 4880                        let prevent_auto_indent = doc_delimiter.is_some();
 4881                        let delimiter = comment_delimiter.or(doc_delimiter);
 4882
 4883                        let capacity_for_delimiter =
 4884                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4885                        let mut new_text = String::with_capacity(
 4886                            1 + capacity_for_delimiter
 4887                                + existing_indent.len as usize
 4888                                + indent_on_newline.len as usize
 4889                                + indent_on_extra_newline.len as usize,
 4890                        );
 4891                        new_text.push('\n');
 4892                        new_text.extend(existing_indent.chars());
 4893                        new_text.extend(indent_on_newline.chars());
 4894
 4895                        if let Some(delimiter) = &delimiter {
 4896                            new_text.push_str(delimiter);
 4897                        }
 4898
 4899                        if insert_extra_newline {
 4900                            new_text.push('\n');
 4901                            new_text.extend(existing_indent.chars());
 4902                            new_text.extend(indent_on_extra_newline.chars());
 4903                        }
 4904
 4905                        let anchor = buffer.anchor_after(end);
 4906                        let new_selection = selection.map(|_| anchor);
 4907                        (
 4908                            ((start..end, new_text), prevent_auto_indent),
 4909                            (insert_extra_newline, new_selection),
 4910                        )
 4911                    })
 4912                    .unzip()
 4913            };
 4914
 4915            let mut auto_indent_edits = Vec::new();
 4916            let mut edits = Vec::new();
 4917            for (edit, prevent_auto_indent) in edits_with_flags {
 4918                if prevent_auto_indent {
 4919                    edits.push(edit);
 4920                } else {
 4921                    auto_indent_edits.push(edit);
 4922                }
 4923            }
 4924            if !edits.is_empty() {
 4925                this.edit(edits, cx);
 4926            }
 4927            if !auto_indent_edits.is_empty() {
 4928                this.edit_with_autoindent(auto_indent_edits, cx);
 4929            }
 4930
 4931            let buffer = this.buffer.read(cx).snapshot(cx);
 4932            let new_selections = selection_info
 4933                .into_iter()
 4934                .map(|(extra_newline_inserted, new_selection)| {
 4935                    let mut cursor = new_selection.end.to_point(&buffer);
 4936                    if extra_newline_inserted {
 4937                        cursor.row -= 1;
 4938                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4939                    }
 4940                    new_selection.map(|_| cursor)
 4941                })
 4942                .collect();
 4943
 4944            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4945            this.refresh_edit_prediction(true, false, window, cx);
 4946        });
 4947    }
 4948
 4949    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4951
 4952        let buffer = self.buffer.read(cx);
 4953        let snapshot = buffer.snapshot(cx);
 4954
 4955        let mut edits = Vec::new();
 4956        let mut rows = Vec::new();
 4957
 4958        for (rows_inserted, selection) in self
 4959            .selections
 4960            .all_adjusted(&self.display_snapshot(cx))
 4961            .into_iter()
 4962            .enumerate()
 4963        {
 4964            let cursor = selection.head();
 4965            let row = cursor.row;
 4966
 4967            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4968
 4969            let newline = "\n".to_string();
 4970            edits.push((start_of_line..start_of_line, newline));
 4971
 4972            rows.push(row + rows_inserted as u32);
 4973        }
 4974
 4975        self.transact(window, cx, |editor, window, cx| {
 4976            editor.edit(edits, cx);
 4977
 4978            editor.change_selections(Default::default(), window, cx, |s| {
 4979                let mut index = 0;
 4980                s.move_cursors_with(|map, _, _| {
 4981                    let row = rows[index];
 4982                    index += 1;
 4983
 4984                    let point = Point::new(row, 0);
 4985                    let boundary = map.next_line_boundary(point).1;
 4986                    let clipped = map.clip_point(boundary, Bias::Left);
 4987
 4988                    (clipped, SelectionGoal::None)
 4989                });
 4990            });
 4991
 4992            let mut indent_edits = Vec::new();
 4993            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4994            for row in rows {
 4995                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4996                for (row, indent) in indents {
 4997                    if indent.len == 0 {
 4998                        continue;
 4999                    }
 5000
 5001                    let text = match indent.kind {
 5002                        IndentKind::Space => " ".repeat(indent.len as usize),
 5003                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5004                    };
 5005                    let point = Point::new(row.0, 0);
 5006                    indent_edits.push((point..point, text));
 5007                }
 5008            }
 5009            editor.edit(indent_edits, cx);
 5010        });
 5011    }
 5012
 5013    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5014        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5015
 5016        let buffer = self.buffer.read(cx);
 5017        let snapshot = buffer.snapshot(cx);
 5018
 5019        let mut edits = Vec::new();
 5020        let mut rows = Vec::new();
 5021        let mut rows_inserted = 0;
 5022
 5023        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5024            let cursor = selection.head();
 5025            let row = cursor.row;
 5026
 5027            let point = Point::new(row + 1, 0);
 5028            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5029
 5030            let newline = "\n".to_string();
 5031            edits.push((start_of_line..start_of_line, newline));
 5032
 5033            rows_inserted += 1;
 5034            rows.push(row + rows_inserted);
 5035        }
 5036
 5037        self.transact(window, cx, |editor, window, cx| {
 5038            editor.edit(edits, cx);
 5039
 5040            editor.change_selections(Default::default(), window, cx, |s| {
 5041                let mut index = 0;
 5042                s.move_cursors_with(|map, _, _| {
 5043                    let row = rows[index];
 5044                    index += 1;
 5045
 5046                    let point = Point::new(row, 0);
 5047                    let boundary = map.next_line_boundary(point).1;
 5048                    let clipped = map.clip_point(boundary, Bias::Left);
 5049
 5050                    (clipped, SelectionGoal::None)
 5051                });
 5052            });
 5053
 5054            let mut indent_edits = Vec::new();
 5055            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5056            for row in rows {
 5057                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5058                for (row, indent) in indents {
 5059                    if indent.len == 0 {
 5060                        continue;
 5061                    }
 5062
 5063                    let text = match indent.kind {
 5064                        IndentKind::Space => " ".repeat(indent.len as usize),
 5065                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5066                    };
 5067                    let point = Point::new(row.0, 0);
 5068                    indent_edits.push((point..point, text));
 5069                }
 5070            }
 5071            editor.edit(indent_edits, cx);
 5072        });
 5073    }
 5074
 5075    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5076        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5077            original_indent_columns: Vec::new(),
 5078        });
 5079        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5080    }
 5081
 5082    fn insert_with_autoindent_mode(
 5083        &mut self,
 5084        text: &str,
 5085        autoindent_mode: Option<AutoindentMode>,
 5086        window: &mut Window,
 5087        cx: &mut Context<Self>,
 5088    ) {
 5089        if self.read_only(cx) {
 5090            return;
 5091        }
 5092
 5093        let text: Arc<str> = text.into();
 5094        self.transact(window, cx, |this, window, cx| {
 5095            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5096            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5097                let anchors = {
 5098                    let snapshot = buffer.read(cx);
 5099                    old_selections
 5100                        .iter()
 5101                        .map(|s| {
 5102                            let anchor = snapshot.anchor_after(s.head());
 5103                            s.map(|_| anchor)
 5104                        })
 5105                        .collect::<Vec<_>>()
 5106                };
 5107                buffer.edit(
 5108                    old_selections
 5109                        .iter()
 5110                        .map(|s| (s.start..s.end, text.clone())),
 5111                    autoindent_mode,
 5112                    cx,
 5113                );
 5114                anchors
 5115            });
 5116
 5117            this.change_selections(Default::default(), window, cx, |s| {
 5118                s.select_anchors(selection_anchors);
 5119            });
 5120
 5121            cx.notify();
 5122        });
 5123    }
 5124
 5125    fn trigger_completion_on_input(
 5126        &mut self,
 5127        text: &str,
 5128        trigger_in_words: bool,
 5129        window: &mut Window,
 5130        cx: &mut Context<Self>,
 5131    ) {
 5132        let completions_source = self
 5133            .context_menu
 5134            .borrow()
 5135            .as_ref()
 5136            .and_then(|menu| match menu {
 5137                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5138                CodeContextMenu::CodeActions(_) => None,
 5139            });
 5140
 5141        match completions_source {
 5142            Some(CompletionsMenuSource::Words { .. }) => {
 5143                self.open_or_update_completions_menu(
 5144                    Some(CompletionsMenuSource::Words {
 5145                        ignore_threshold: false,
 5146                    }),
 5147                    None,
 5148                    trigger_in_words,
 5149                    window,
 5150                    cx,
 5151                );
 5152            }
 5153            _ => self.open_or_update_completions_menu(
 5154                None,
 5155                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5156                true,
 5157                window,
 5158                cx,
 5159            ),
 5160        }
 5161    }
 5162
 5163    /// If any empty selections is touching the start of its innermost containing autoclose
 5164    /// region, expand it to select the brackets.
 5165    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5166        let selections = self
 5167            .selections
 5168            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5169        let buffer = self.buffer.read(cx).read(cx);
 5170        let new_selections = self
 5171            .selections_with_autoclose_regions(selections, &buffer)
 5172            .map(|(mut selection, region)| {
 5173                if !selection.is_empty() {
 5174                    return selection;
 5175                }
 5176
 5177                if let Some(region) = region {
 5178                    let mut range = region.range.to_offset(&buffer);
 5179                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5180                        range.start -= region.pair.start.len();
 5181                        if buffer.contains_str_at(range.start, &region.pair.start)
 5182                            && buffer.contains_str_at(range.end, &region.pair.end)
 5183                        {
 5184                            range.end += region.pair.end.len();
 5185                            selection.start = range.start;
 5186                            selection.end = range.end;
 5187
 5188                            return selection;
 5189                        }
 5190                    }
 5191                }
 5192
 5193                let always_treat_brackets_as_autoclosed = buffer
 5194                    .language_settings_at(selection.start, cx)
 5195                    .always_treat_brackets_as_autoclosed;
 5196
 5197                if !always_treat_brackets_as_autoclosed {
 5198                    return selection;
 5199                }
 5200
 5201                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5202                    for (pair, enabled) in scope.brackets() {
 5203                        if !enabled || !pair.close {
 5204                            continue;
 5205                        }
 5206
 5207                        if buffer.contains_str_at(selection.start, &pair.end) {
 5208                            let pair_start_len = pair.start.len();
 5209                            if buffer.contains_str_at(
 5210                                selection.start.saturating_sub_usize(pair_start_len),
 5211                                &pair.start,
 5212                            ) {
 5213                                selection.start -= pair_start_len;
 5214                                selection.end += pair.end.len();
 5215
 5216                                return selection;
 5217                            }
 5218                        }
 5219                    }
 5220                }
 5221
 5222                selection
 5223            })
 5224            .collect();
 5225
 5226        drop(buffer);
 5227        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5228            selections.select(new_selections)
 5229        });
 5230    }
 5231
 5232    /// Iterate the given selections, and for each one, find the smallest surrounding
 5233    /// autoclose region. This uses the ordering of the selections and the autoclose
 5234    /// regions to avoid repeated comparisons.
 5235    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5236        &'a self,
 5237        selections: impl IntoIterator<Item = Selection<D>>,
 5238        buffer: &'a MultiBufferSnapshot,
 5239    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5240        let mut i = 0;
 5241        let mut regions = self.autoclose_regions.as_slice();
 5242        selections.into_iter().map(move |selection| {
 5243            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5244
 5245            let mut enclosing = None;
 5246            while let Some(pair_state) = regions.get(i) {
 5247                if pair_state.range.end.to_offset(buffer) < range.start {
 5248                    regions = &regions[i + 1..];
 5249                    i = 0;
 5250                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5251                    break;
 5252                } else {
 5253                    if pair_state.selection_id == selection.id {
 5254                        enclosing = Some(pair_state);
 5255                    }
 5256                    i += 1;
 5257                }
 5258            }
 5259
 5260            (selection, enclosing)
 5261        })
 5262    }
 5263
 5264    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5265    fn invalidate_autoclose_regions(
 5266        &mut self,
 5267        mut selections: &[Selection<Anchor>],
 5268        buffer: &MultiBufferSnapshot,
 5269    ) {
 5270        self.autoclose_regions.retain(|state| {
 5271            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5272                return false;
 5273            }
 5274
 5275            let mut i = 0;
 5276            while let Some(selection) = selections.get(i) {
 5277                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5278                    selections = &selections[1..];
 5279                    continue;
 5280                }
 5281                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5282                    break;
 5283                }
 5284                if selection.id == state.selection_id {
 5285                    return true;
 5286                } else {
 5287                    i += 1;
 5288                }
 5289            }
 5290            false
 5291        });
 5292    }
 5293
 5294    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5295        let offset = position.to_offset(buffer);
 5296        let (word_range, kind) =
 5297            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5298        if offset > word_range.start && kind == Some(CharKind::Word) {
 5299            Some(
 5300                buffer
 5301                    .text_for_range(word_range.start..offset)
 5302                    .collect::<String>(),
 5303            )
 5304        } else {
 5305            None
 5306        }
 5307    }
 5308
 5309    pub fn visible_excerpts(
 5310        &self,
 5311        lsp_related_only: bool,
 5312        cx: &mut Context<Editor>,
 5313    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5314        let project = self.project().cloned();
 5315        let multi_buffer = self.buffer().read(cx);
 5316        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5317        let multi_buffer_visible_start = self
 5318            .scroll_manager
 5319            .anchor()
 5320            .anchor
 5321            .to_point(&multi_buffer_snapshot);
 5322        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5323            multi_buffer_visible_start
 5324                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5325            Bias::Left,
 5326        );
 5327        multi_buffer_snapshot
 5328            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5329            .into_iter()
 5330            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5331            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5332                if !lsp_related_only {
 5333                    return Some((
 5334                        excerpt_id,
 5335                        (
 5336                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5337                            buffer.version().clone(),
 5338                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5339                        ),
 5340                    ));
 5341                }
 5342
 5343                let project = project.as_ref()?.read(cx);
 5344                let buffer_file = project::File::from_dyn(buffer.file())?;
 5345                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5346                let worktree_entry = buffer_worktree
 5347                    .read(cx)
 5348                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5349                if worktree_entry.is_ignored {
 5350                    None
 5351                } else {
 5352                    Some((
 5353                        excerpt_id,
 5354                        (
 5355                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5356                            buffer.version().clone(),
 5357                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5358                        ),
 5359                    ))
 5360                }
 5361            })
 5362            .collect()
 5363    }
 5364
 5365    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5366        TextLayoutDetails {
 5367            text_system: window.text_system().clone(),
 5368            editor_style: self.style.clone().unwrap(),
 5369            rem_size: window.rem_size(),
 5370            scroll_anchor: self.scroll_manager.anchor(),
 5371            visible_rows: self.visible_line_count(),
 5372            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5373        }
 5374    }
 5375
 5376    fn trigger_on_type_formatting(
 5377        &self,
 5378        input: String,
 5379        window: &mut Window,
 5380        cx: &mut Context<Self>,
 5381    ) -> Option<Task<Result<()>>> {
 5382        if input.len() != 1 {
 5383            return None;
 5384        }
 5385
 5386        let project = self.project()?;
 5387        let position = self.selections.newest_anchor().head();
 5388        let (buffer, buffer_position) = self
 5389            .buffer
 5390            .read(cx)
 5391            .text_anchor_for_position(position, cx)?;
 5392
 5393        let settings = language_settings::language_settings(
 5394            buffer
 5395                .read(cx)
 5396                .language_at(buffer_position)
 5397                .map(|l| l.name()),
 5398            buffer.read(cx).file(),
 5399            cx,
 5400        );
 5401        if !settings.use_on_type_format {
 5402            return None;
 5403        }
 5404
 5405        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5406        // hence we do LSP request & edit on host side only — add formats to host's history.
 5407        let push_to_lsp_host_history = true;
 5408        // If this is not the host, append its history with new edits.
 5409        let push_to_client_history = project.read(cx).is_via_collab();
 5410
 5411        let on_type_formatting = project.update(cx, |project, cx| {
 5412            project.on_type_format(
 5413                buffer.clone(),
 5414                buffer_position,
 5415                input,
 5416                push_to_lsp_host_history,
 5417                cx,
 5418            )
 5419        });
 5420        Some(cx.spawn_in(window, async move |editor, cx| {
 5421            if let Some(transaction) = on_type_formatting.await? {
 5422                if push_to_client_history {
 5423                    buffer
 5424                        .update(cx, |buffer, _| {
 5425                            buffer.push_transaction(transaction, Instant::now());
 5426                            buffer.finalize_last_transaction();
 5427                        })
 5428                        .ok();
 5429                }
 5430                editor.update(cx, |editor, cx| {
 5431                    editor.refresh_document_highlights(cx);
 5432                })?;
 5433            }
 5434            Ok(())
 5435        }))
 5436    }
 5437
 5438    pub fn show_word_completions(
 5439        &mut self,
 5440        _: &ShowWordCompletions,
 5441        window: &mut Window,
 5442        cx: &mut Context<Self>,
 5443    ) {
 5444        self.open_or_update_completions_menu(
 5445            Some(CompletionsMenuSource::Words {
 5446                ignore_threshold: true,
 5447            }),
 5448            None,
 5449            false,
 5450            window,
 5451            cx,
 5452        );
 5453    }
 5454
 5455    pub fn show_completions(
 5456        &mut self,
 5457        _: &ShowCompletions,
 5458        window: &mut Window,
 5459        cx: &mut Context<Self>,
 5460    ) {
 5461        self.open_or_update_completions_menu(None, None, false, window, cx);
 5462    }
 5463
 5464    fn open_or_update_completions_menu(
 5465        &mut self,
 5466        requested_source: Option<CompletionsMenuSource>,
 5467        trigger: Option<String>,
 5468        trigger_in_words: bool,
 5469        window: &mut Window,
 5470        cx: &mut Context<Self>,
 5471    ) {
 5472        if self.pending_rename.is_some() {
 5473            return;
 5474        }
 5475
 5476        let completions_source = self
 5477            .context_menu
 5478            .borrow()
 5479            .as_ref()
 5480            .and_then(|menu| match menu {
 5481                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5482                CodeContextMenu::CodeActions(_) => None,
 5483            });
 5484
 5485        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5486
 5487        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5488        // inserted and selected. To handle that case, the start of the selection is used so that
 5489        // the menu starts with all choices.
 5490        let position = self
 5491            .selections
 5492            .newest_anchor()
 5493            .start
 5494            .bias_right(&multibuffer_snapshot);
 5495        if position.diff_base_anchor.is_some() {
 5496            return;
 5497        }
 5498        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5499        let Some(buffer) = buffer_position
 5500            .text_anchor
 5501            .buffer_id
 5502            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5503        else {
 5504            return;
 5505        };
 5506        let buffer_snapshot = buffer.read(cx).snapshot();
 5507
 5508        let query: Option<Arc<String>> =
 5509            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5510                .map(|query| query.into());
 5511
 5512        drop(multibuffer_snapshot);
 5513
 5514        // Hide the current completions menu when query is empty. Without this, cached
 5515        // completions from before the trigger char may be reused (#32774).
 5516        if query.is_none() {
 5517            let menu_is_open = matches!(
 5518                self.context_menu.borrow().as_ref(),
 5519                Some(CodeContextMenu::Completions(_))
 5520            );
 5521            if menu_is_open {
 5522                self.hide_context_menu(window, cx);
 5523            }
 5524        }
 5525
 5526        let mut ignore_word_threshold = false;
 5527        let provider = match requested_source {
 5528            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5529            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5530                ignore_word_threshold = ignore_threshold;
 5531                None
 5532            }
 5533            Some(CompletionsMenuSource::SnippetChoices)
 5534            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5535                log::error!("bug: SnippetChoices requested_source is not handled");
 5536                None
 5537            }
 5538        };
 5539
 5540        let sort_completions = provider
 5541            .as_ref()
 5542            .is_some_and(|provider| provider.sort_completions());
 5543
 5544        let filter_completions = provider
 5545            .as_ref()
 5546            .is_none_or(|provider| provider.filter_completions());
 5547
 5548        let was_snippets_only = matches!(
 5549            completions_source,
 5550            Some(CompletionsMenuSource::SnippetsOnly)
 5551        );
 5552
 5553        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5554            if filter_completions {
 5555                menu.filter(
 5556                    query.clone().unwrap_or_default(),
 5557                    buffer_position.text_anchor,
 5558                    &buffer,
 5559                    provider.clone(),
 5560                    window,
 5561                    cx,
 5562                );
 5563            }
 5564            // When `is_incomplete` is false, no need to re-query completions when the current query
 5565            // is a suffix of the initial query.
 5566            let was_complete = !menu.is_incomplete;
 5567            if was_complete && !was_snippets_only {
 5568                // If the new query is a suffix of the old query (typing more characters) and
 5569                // the previous result was complete, the existing completions can be filtered.
 5570                //
 5571                // Note that snippet completions are always complete.
 5572                let query_matches = match (&menu.initial_query, &query) {
 5573                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5574                    (None, _) => true,
 5575                    _ => false,
 5576                };
 5577                if query_matches {
 5578                    let position_matches = if menu.initial_position == position {
 5579                        true
 5580                    } else {
 5581                        let snapshot = self.buffer.read(cx).read(cx);
 5582                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5583                    };
 5584                    if position_matches {
 5585                        return;
 5586                    }
 5587                }
 5588            }
 5589        };
 5590
 5591        let Anchor {
 5592            excerpt_id: buffer_excerpt_id,
 5593            text_anchor: buffer_position,
 5594            ..
 5595        } = buffer_position;
 5596
 5597        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5598            buffer_snapshot.surrounding_word(buffer_position, None)
 5599        {
 5600            let word_to_exclude = buffer_snapshot
 5601                .text_for_range(word_range.clone())
 5602                .collect::<String>();
 5603            (
 5604                buffer_snapshot.anchor_before(word_range.start)
 5605                    ..buffer_snapshot.anchor_after(buffer_position),
 5606                Some(word_to_exclude),
 5607            )
 5608        } else {
 5609            (buffer_position..buffer_position, None)
 5610        };
 5611
 5612        let language = buffer_snapshot
 5613            .language_at(buffer_position)
 5614            .map(|language| language.name());
 5615
 5616        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5617            .completions
 5618            .clone();
 5619
 5620        let show_completion_documentation = buffer_snapshot
 5621            .settings_at(buffer_position, cx)
 5622            .show_completion_documentation;
 5623
 5624        // The document can be large, so stay in reasonable bounds when searching for words,
 5625        // otherwise completion pop-up might be slow to appear.
 5626        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5627        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5628        let min_word_search = buffer_snapshot.clip_point(
 5629            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5630            Bias::Left,
 5631        );
 5632        let max_word_search = buffer_snapshot.clip_point(
 5633            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5634            Bias::Right,
 5635        );
 5636        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5637            ..buffer_snapshot.point_to_offset(max_word_search);
 5638
 5639        let skip_digits = query
 5640            .as_ref()
 5641            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5642
 5643        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5644            trigger.as_ref().is_none_or(|trigger| {
 5645                provider.is_completion_trigger(
 5646                    &buffer,
 5647                    position.text_anchor,
 5648                    trigger,
 5649                    trigger_in_words,
 5650                    completions_source.is_some(),
 5651                    cx,
 5652                )
 5653            })
 5654        });
 5655
 5656        let provider_responses = if let Some(provider) = &provider
 5657            && load_provider_completions
 5658        {
 5659            let trigger_character =
 5660                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5661            let completion_context = CompletionContext {
 5662                trigger_kind: match &trigger_character {
 5663                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5664                    None => CompletionTriggerKind::INVOKED,
 5665                },
 5666                trigger_character,
 5667            };
 5668
 5669            provider.completions(
 5670                buffer_excerpt_id,
 5671                &buffer,
 5672                buffer_position,
 5673                completion_context,
 5674                window,
 5675                cx,
 5676            )
 5677        } else {
 5678            Task::ready(Ok(Vec::new()))
 5679        };
 5680
 5681        let load_word_completions = if !self.word_completions_enabled {
 5682            false
 5683        } else if requested_source
 5684            == Some(CompletionsMenuSource::Words {
 5685                ignore_threshold: true,
 5686            })
 5687        {
 5688            true
 5689        } else {
 5690            load_provider_completions
 5691                && completion_settings.words != WordsCompletionMode::Disabled
 5692                && (ignore_word_threshold || {
 5693                    let words_min_length = completion_settings.words_min_length;
 5694                    // check whether word has at least `words_min_length` characters
 5695                    let query_chars = query.iter().flat_map(|q| q.chars());
 5696                    query_chars.take(words_min_length).count() == words_min_length
 5697                })
 5698        };
 5699
 5700        let mut words = if load_word_completions {
 5701            cx.background_spawn({
 5702                let buffer_snapshot = buffer_snapshot.clone();
 5703                async move {
 5704                    buffer_snapshot.words_in_range(WordsQuery {
 5705                        fuzzy_contents: None,
 5706                        range: word_search_range,
 5707                        skip_digits,
 5708                    })
 5709                }
 5710            })
 5711        } else {
 5712            Task::ready(BTreeMap::default())
 5713        };
 5714
 5715        let snippets = if let Some(provider) = &provider
 5716            && provider.show_snippets()
 5717            && let Some(project) = self.project()
 5718        {
 5719            let char_classifier = buffer_snapshot
 5720                .char_classifier_at(buffer_position)
 5721                .scope_context(Some(CharScopeContext::Completion));
 5722            project.update(cx, |project, cx| {
 5723                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5724            })
 5725        } else {
 5726            Task::ready(Ok(CompletionResponse {
 5727                completions: Vec::new(),
 5728                display_options: Default::default(),
 5729                is_incomplete: false,
 5730            }))
 5731        };
 5732
 5733        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5734
 5735        let id = post_inc(&mut self.next_completion_id);
 5736        let task = cx.spawn_in(window, async move |editor, cx| {
 5737            let Ok(()) = editor.update(cx, |this, _| {
 5738                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5739            }) else {
 5740                return;
 5741            };
 5742
 5743            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5744            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5745            let mut completions = Vec::new();
 5746            let mut is_incomplete = false;
 5747            let mut display_options: Option<CompletionDisplayOptions> = None;
 5748            if let Some(provider_responses) = provider_responses.await.log_err()
 5749                && !provider_responses.is_empty()
 5750            {
 5751                for response in provider_responses {
 5752                    completions.extend(response.completions);
 5753                    is_incomplete = is_incomplete || response.is_incomplete;
 5754                    match display_options.as_mut() {
 5755                        None => {
 5756                            display_options = Some(response.display_options);
 5757                        }
 5758                        Some(options) => options.merge(&response.display_options),
 5759                    }
 5760                }
 5761                if completion_settings.words == WordsCompletionMode::Fallback {
 5762                    words = Task::ready(BTreeMap::default());
 5763                }
 5764            }
 5765            let display_options = display_options.unwrap_or_default();
 5766
 5767            let mut words = words.await;
 5768            if let Some(word_to_exclude) = &word_to_exclude {
 5769                words.remove(word_to_exclude);
 5770            }
 5771            for lsp_completion in &completions {
 5772                words.remove(&lsp_completion.new_text);
 5773            }
 5774            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5775                replace_range: word_replace_range.clone(),
 5776                new_text: word.clone(),
 5777                label: CodeLabel::plain(word, None),
 5778                match_start: None,
 5779                snippet_deduplication_key: None,
 5780                icon_path: None,
 5781                documentation: None,
 5782                source: CompletionSource::BufferWord {
 5783                    word_range,
 5784                    resolved: false,
 5785                },
 5786                insert_text_mode: Some(InsertTextMode::AS_IS),
 5787                confirm: None,
 5788            }));
 5789
 5790            completions.extend(
 5791                snippets
 5792                    .await
 5793                    .into_iter()
 5794                    .flat_map(|response| response.completions),
 5795            );
 5796
 5797            let menu = if completions.is_empty() {
 5798                None
 5799            } else {
 5800                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5801                    let languages = editor
 5802                        .workspace
 5803                        .as_ref()
 5804                        .and_then(|(workspace, _)| workspace.upgrade())
 5805                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5806                    let menu = CompletionsMenu::new(
 5807                        id,
 5808                        requested_source.unwrap_or(if load_provider_completions {
 5809                            CompletionsMenuSource::Normal
 5810                        } else {
 5811                            CompletionsMenuSource::SnippetsOnly
 5812                        }),
 5813                        sort_completions,
 5814                        show_completion_documentation,
 5815                        position,
 5816                        query.clone(),
 5817                        is_incomplete,
 5818                        buffer.clone(),
 5819                        completions.into(),
 5820                        display_options,
 5821                        snippet_sort_order,
 5822                        languages,
 5823                        language,
 5824                        cx,
 5825                    );
 5826
 5827                    let query = if filter_completions { query } else { None };
 5828                    let matches_task = menu.do_async_filtering(
 5829                        query.unwrap_or_default(),
 5830                        buffer_position,
 5831                        &buffer,
 5832                        cx,
 5833                    );
 5834                    (menu, matches_task)
 5835                }) else {
 5836                    return;
 5837                };
 5838
 5839                let matches = matches_task.await;
 5840
 5841                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5842                    // Newer menu already set, so exit.
 5843                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5844                        editor.context_menu.borrow().as_ref()
 5845                        && prev_menu.id > id
 5846                    {
 5847                        return;
 5848                    };
 5849
 5850                    // Only valid to take prev_menu because either the new menu is immediately set
 5851                    // below, or the menu is hidden.
 5852                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5853                        editor.context_menu.borrow_mut().take()
 5854                    {
 5855                        let position_matches =
 5856                            if prev_menu.initial_position == menu.initial_position {
 5857                                true
 5858                            } else {
 5859                                let snapshot = editor.buffer.read(cx).read(cx);
 5860                                prev_menu.initial_position.to_offset(&snapshot)
 5861                                    == menu.initial_position.to_offset(&snapshot)
 5862                            };
 5863                        if position_matches {
 5864                            // Preserve markdown cache before `set_filter_results` because it will
 5865                            // try to populate the documentation cache.
 5866                            menu.preserve_markdown_cache(prev_menu);
 5867                        }
 5868                    };
 5869
 5870                    menu.set_filter_results(matches, provider, window, cx);
 5871                }) else {
 5872                    return;
 5873                };
 5874
 5875                menu.visible().then_some(menu)
 5876            };
 5877
 5878            editor
 5879                .update_in(cx, |editor, window, cx| {
 5880                    if editor.focus_handle.is_focused(window)
 5881                        && let Some(menu) = menu
 5882                    {
 5883                        *editor.context_menu.borrow_mut() =
 5884                            Some(CodeContextMenu::Completions(menu));
 5885
 5886                        crate::hover_popover::hide_hover(editor, cx);
 5887                        if editor.show_edit_predictions_in_menu() {
 5888                            editor.update_visible_edit_prediction(window, cx);
 5889                        } else {
 5890                            editor.discard_edit_prediction(false, cx);
 5891                        }
 5892
 5893                        cx.notify();
 5894                        return;
 5895                    }
 5896
 5897                    if editor.completion_tasks.len() <= 1 {
 5898                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5899                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5900                        // If it was already hidden and we don't show edit predictions in the menu,
 5901                        // we should also show the edit prediction when available.
 5902                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5903                            editor.update_visible_edit_prediction(window, cx);
 5904                        }
 5905                    }
 5906                })
 5907                .ok();
 5908        });
 5909
 5910        self.completion_tasks.push((id, task));
 5911    }
 5912
 5913    #[cfg(feature = "test-support")]
 5914    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5915        let menu = self.context_menu.borrow();
 5916        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5917            let completions = menu.completions.borrow();
 5918            Some(completions.to_vec())
 5919        } else {
 5920            None
 5921        }
 5922    }
 5923
 5924    pub fn with_completions_menu_matching_id<R>(
 5925        &self,
 5926        id: CompletionId,
 5927        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5928    ) -> R {
 5929        let mut context_menu = self.context_menu.borrow_mut();
 5930        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5931            return f(None);
 5932        };
 5933        if completions_menu.id != id {
 5934            return f(None);
 5935        }
 5936        f(Some(completions_menu))
 5937    }
 5938
 5939    pub fn confirm_completion(
 5940        &mut self,
 5941        action: &ConfirmCompletion,
 5942        window: &mut Window,
 5943        cx: &mut Context<Self>,
 5944    ) -> Option<Task<Result<()>>> {
 5945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5946        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5947    }
 5948
 5949    pub fn confirm_completion_insert(
 5950        &mut self,
 5951        _: &ConfirmCompletionInsert,
 5952        window: &mut Window,
 5953        cx: &mut Context<Self>,
 5954    ) -> Option<Task<Result<()>>> {
 5955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5956        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5957    }
 5958
 5959    pub fn confirm_completion_replace(
 5960        &mut self,
 5961        _: &ConfirmCompletionReplace,
 5962        window: &mut Window,
 5963        cx: &mut Context<Self>,
 5964    ) -> Option<Task<Result<()>>> {
 5965        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5966        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5967    }
 5968
 5969    pub fn compose_completion(
 5970        &mut self,
 5971        action: &ComposeCompletion,
 5972        window: &mut Window,
 5973        cx: &mut Context<Self>,
 5974    ) -> Option<Task<Result<()>>> {
 5975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5976        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5977    }
 5978
 5979    fn do_completion(
 5980        &mut self,
 5981        item_ix: Option<usize>,
 5982        intent: CompletionIntent,
 5983        window: &mut Window,
 5984        cx: &mut Context<Editor>,
 5985    ) -> Option<Task<Result<()>>> {
 5986        use language::ToOffset as _;
 5987
 5988        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5989        else {
 5990            return None;
 5991        };
 5992
 5993        let candidate_id = {
 5994            let entries = completions_menu.entries.borrow();
 5995            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5996            if self.show_edit_predictions_in_menu() {
 5997                self.discard_edit_prediction(true, cx);
 5998            }
 5999            mat.candidate_id
 6000        };
 6001
 6002        let completion = completions_menu
 6003            .completions
 6004            .borrow()
 6005            .get(candidate_id)?
 6006            .clone();
 6007        cx.stop_propagation();
 6008
 6009        let buffer_handle = completions_menu.buffer.clone();
 6010
 6011        let CompletionEdit {
 6012            new_text,
 6013            snippet,
 6014            replace_range,
 6015        } = process_completion_for_edit(
 6016            &completion,
 6017            intent,
 6018            &buffer_handle,
 6019            &completions_menu.initial_position.text_anchor,
 6020            cx,
 6021        );
 6022
 6023        let buffer = buffer_handle.read(cx);
 6024        let snapshot = self.buffer.read(cx).snapshot(cx);
 6025        let newest_anchor = self.selections.newest_anchor();
 6026        let replace_range_multibuffer = {
 6027            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6028            excerpt.map_range_from_buffer(replace_range.clone())
 6029        };
 6030        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6031            return None;
 6032        }
 6033
 6034        let old_text = buffer
 6035            .text_for_range(replace_range.clone())
 6036            .collect::<String>();
 6037        let lookbehind = newest_anchor
 6038            .start
 6039            .text_anchor
 6040            .to_offset(buffer)
 6041            .saturating_sub(replace_range.start.0);
 6042        let lookahead = replace_range
 6043            .end
 6044            .0
 6045            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6046        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6047        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6048
 6049        let selections = self
 6050            .selections
 6051            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6052        let mut ranges = Vec::new();
 6053        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6054
 6055        for selection in &selections {
 6056            let range = if selection.id == newest_anchor.id {
 6057                replace_range_multibuffer.clone()
 6058            } else {
 6059                let mut range = selection.range();
 6060
 6061                // if prefix is present, don't duplicate it
 6062                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6063                    range.start = range.start.saturating_sub_usize(lookbehind);
 6064
 6065                    // if suffix is also present, mimic the newest cursor and replace it
 6066                    if selection.id != newest_anchor.id
 6067                        && snapshot.contains_str_at(range.end, suffix)
 6068                    {
 6069                        range.end += lookahead;
 6070                    }
 6071                }
 6072                range
 6073            };
 6074
 6075            ranges.push(range.clone());
 6076
 6077            if !self.linked_edit_ranges.is_empty() {
 6078                let start_anchor = snapshot.anchor_before(range.start);
 6079                let end_anchor = snapshot.anchor_after(range.end);
 6080                if let Some(ranges) = self
 6081                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6082                {
 6083                    for (buffer, edits) in ranges {
 6084                        linked_edits
 6085                            .entry(buffer.clone())
 6086                            .or_default()
 6087                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6088                    }
 6089                }
 6090            }
 6091        }
 6092
 6093        let common_prefix_len = old_text
 6094            .chars()
 6095            .zip(new_text.chars())
 6096            .take_while(|(a, b)| a == b)
 6097            .map(|(a, _)| a.len_utf8())
 6098            .sum::<usize>();
 6099
 6100        cx.emit(EditorEvent::InputHandled {
 6101            utf16_range_to_replace: None,
 6102            text: new_text[common_prefix_len..].into(),
 6103        });
 6104
 6105        self.transact(window, cx, |editor, window, cx| {
 6106            if let Some(mut snippet) = snippet {
 6107                snippet.text = new_text.to_string();
 6108                editor
 6109                    .insert_snippet(&ranges, snippet, window, cx)
 6110                    .log_err();
 6111            } else {
 6112                editor.buffer.update(cx, |multi_buffer, cx| {
 6113                    let auto_indent = match completion.insert_text_mode {
 6114                        Some(InsertTextMode::AS_IS) => None,
 6115                        _ => editor.autoindent_mode.clone(),
 6116                    };
 6117                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6118                    multi_buffer.edit(edits, auto_indent, cx);
 6119                });
 6120            }
 6121            for (buffer, edits) in linked_edits {
 6122                buffer.update(cx, |buffer, cx| {
 6123                    let snapshot = buffer.snapshot();
 6124                    let edits = edits
 6125                        .into_iter()
 6126                        .map(|(range, text)| {
 6127                            use text::ToPoint as TP;
 6128                            let end_point = TP::to_point(&range.end, &snapshot);
 6129                            let start_point = TP::to_point(&range.start, &snapshot);
 6130                            (start_point..end_point, text)
 6131                        })
 6132                        .sorted_by_key(|(range, _)| range.start);
 6133                    buffer.edit(edits, None, cx);
 6134                })
 6135            }
 6136
 6137            editor.refresh_edit_prediction(true, false, window, cx);
 6138        });
 6139        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6140
 6141        let show_new_completions_on_confirm = completion
 6142            .confirm
 6143            .as_ref()
 6144            .is_some_and(|confirm| confirm(intent, window, cx));
 6145        if show_new_completions_on_confirm {
 6146            self.open_or_update_completions_menu(None, None, false, window, cx);
 6147        }
 6148
 6149        let provider = self.completion_provider.as_ref()?;
 6150        drop(completion);
 6151        let apply_edits = provider.apply_additional_edits_for_completion(
 6152            buffer_handle,
 6153            completions_menu.completions.clone(),
 6154            candidate_id,
 6155            true,
 6156            cx,
 6157        );
 6158
 6159        let editor_settings = EditorSettings::get_global(cx);
 6160        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6161            // After the code completion is finished, users often want to know what signatures are needed.
 6162            // so we should automatically call signature_help
 6163            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6164        }
 6165
 6166        Some(cx.foreground_executor().spawn(async move {
 6167            apply_edits.await?;
 6168            Ok(())
 6169        }))
 6170    }
 6171
 6172    pub fn toggle_code_actions(
 6173        &mut self,
 6174        action: &ToggleCodeActions,
 6175        window: &mut Window,
 6176        cx: &mut Context<Self>,
 6177    ) {
 6178        let quick_launch = action.quick_launch;
 6179        let mut context_menu = self.context_menu.borrow_mut();
 6180        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6181            if code_actions.deployed_from == action.deployed_from {
 6182                // Toggle if we're selecting the same one
 6183                *context_menu = None;
 6184                cx.notify();
 6185                return;
 6186            } else {
 6187                // Otherwise, clear it and start a new one
 6188                *context_menu = None;
 6189                cx.notify();
 6190            }
 6191        }
 6192        drop(context_menu);
 6193        let snapshot = self.snapshot(window, cx);
 6194        let deployed_from = action.deployed_from.clone();
 6195        let action = action.clone();
 6196        self.completion_tasks.clear();
 6197        self.discard_edit_prediction(false, cx);
 6198
 6199        let multibuffer_point = match &action.deployed_from {
 6200            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6201                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6202            }
 6203            _ => self
 6204                .selections
 6205                .newest::<Point>(&snapshot.display_snapshot)
 6206                .head(),
 6207        };
 6208        let Some((buffer, buffer_row)) = snapshot
 6209            .buffer_snapshot()
 6210            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6211            .and_then(|(buffer_snapshot, range)| {
 6212                self.buffer()
 6213                    .read(cx)
 6214                    .buffer(buffer_snapshot.remote_id())
 6215                    .map(|buffer| (buffer, range.start.row))
 6216            })
 6217        else {
 6218            return;
 6219        };
 6220        let buffer_id = buffer.read(cx).remote_id();
 6221        let tasks = self
 6222            .tasks
 6223            .get(&(buffer_id, buffer_row))
 6224            .map(|t| Arc::new(t.to_owned()));
 6225
 6226        if !self.focus_handle.is_focused(window) {
 6227            return;
 6228        }
 6229        let project = self.project.clone();
 6230
 6231        let code_actions_task = match deployed_from {
 6232            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6233            _ => self.code_actions(buffer_row, window, cx),
 6234        };
 6235
 6236        let runnable_task = match deployed_from {
 6237            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6238            _ => {
 6239                let mut task_context_task = Task::ready(None);
 6240                if let Some(tasks) = &tasks
 6241                    && let Some(project) = project
 6242                {
 6243                    task_context_task =
 6244                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6245                }
 6246
 6247                cx.spawn_in(window, {
 6248                    let buffer = buffer.clone();
 6249                    async move |editor, cx| {
 6250                        let task_context = task_context_task.await;
 6251
 6252                        let resolved_tasks =
 6253                            tasks
 6254                                .zip(task_context.clone())
 6255                                .map(|(tasks, task_context)| ResolvedTasks {
 6256                                    templates: tasks.resolve(&task_context).collect(),
 6257                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6258                                        multibuffer_point.row,
 6259                                        tasks.column,
 6260                                    )),
 6261                                });
 6262                        let debug_scenarios = editor
 6263                            .update(cx, |editor, cx| {
 6264                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6265                            })?
 6266                            .await;
 6267                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6268                    }
 6269                })
 6270            }
 6271        };
 6272
 6273        cx.spawn_in(window, async move |editor, cx| {
 6274            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6275            let code_actions = code_actions_task.await;
 6276            let spawn_straight_away = quick_launch
 6277                && resolved_tasks
 6278                    .as_ref()
 6279                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6280                && code_actions
 6281                    .as_ref()
 6282                    .is_none_or(|actions| actions.is_empty())
 6283                && debug_scenarios.is_empty();
 6284
 6285            editor.update_in(cx, |editor, window, cx| {
 6286                crate::hover_popover::hide_hover(editor, cx);
 6287                let actions = CodeActionContents::new(
 6288                    resolved_tasks,
 6289                    code_actions,
 6290                    debug_scenarios,
 6291                    task_context.unwrap_or_default(),
 6292                );
 6293
 6294                // Don't show the menu if there are no actions available
 6295                if actions.is_empty() {
 6296                    cx.notify();
 6297                    return Task::ready(Ok(()));
 6298                }
 6299
 6300                *editor.context_menu.borrow_mut() =
 6301                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6302                        buffer,
 6303                        actions,
 6304                        selected_item: Default::default(),
 6305                        scroll_handle: UniformListScrollHandle::default(),
 6306                        deployed_from,
 6307                    }));
 6308                cx.notify();
 6309                if spawn_straight_away
 6310                    && let Some(task) = editor.confirm_code_action(
 6311                        &ConfirmCodeAction { item_ix: Some(0) },
 6312                        window,
 6313                        cx,
 6314                    )
 6315                {
 6316                    return task;
 6317                }
 6318
 6319                Task::ready(Ok(()))
 6320            })
 6321        })
 6322        .detach_and_log_err(cx);
 6323    }
 6324
 6325    fn debug_scenarios(
 6326        &mut self,
 6327        resolved_tasks: &Option<ResolvedTasks>,
 6328        buffer: &Entity<Buffer>,
 6329        cx: &mut App,
 6330    ) -> Task<Vec<task::DebugScenario>> {
 6331        maybe!({
 6332            let project = self.project()?;
 6333            let dap_store = project.read(cx).dap_store();
 6334            let mut scenarios = vec![];
 6335            let resolved_tasks = resolved_tasks.as_ref()?;
 6336            let buffer = buffer.read(cx);
 6337            let language = buffer.language()?;
 6338            let file = buffer.file();
 6339            let debug_adapter = language_settings(language.name().into(), file, cx)
 6340                .debuggers
 6341                .first()
 6342                .map(SharedString::from)
 6343                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6344
 6345            dap_store.update(cx, |dap_store, cx| {
 6346                for (_, task) in &resolved_tasks.templates {
 6347                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6348                        task.original_task().clone(),
 6349                        debug_adapter.clone().into(),
 6350                        task.display_label().to_owned().into(),
 6351                        cx,
 6352                    );
 6353                    scenarios.push(maybe_scenario);
 6354                }
 6355            });
 6356            Some(cx.background_spawn(async move {
 6357                futures::future::join_all(scenarios)
 6358                    .await
 6359                    .into_iter()
 6360                    .flatten()
 6361                    .collect::<Vec<_>>()
 6362            }))
 6363        })
 6364        .unwrap_or_else(|| Task::ready(vec![]))
 6365    }
 6366
 6367    fn code_actions(
 6368        &mut self,
 6369        buffer_row: u32,
 6370        window: &mut Window,
 6371        cx: &mut Context<Self>,
 6372    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6373        let mut task = self.code_actions_task.take();
 6374        cx.spawn_in(window, async move |editor, cx| {
 6375            while let Some(prev_task) = task {
 6376                prev_task.await.log_err();
 6377                task = editor
 6378                    .update(cx, |this, _| this.code_actions_task.take())
 6379                    .ok()?;
 6380            }
 6381
 6382            editor
 6383                .update(cx, |editor, cx| {
 6384                    editor
 6385                        .available_code_actions
 6386                        .clone()
 6387                        .and_then(|(location, code_actions)| {
 6388                            let snapshot = location.buffer.read(cx).snapshot();
 6389                            let point_range = location.range.to_point(&snapshot);
 6390                            let point_range = point_range.start.row..=point_range.end.row;
 6391                            if point_range.contains(&buffer_row) {
 6392                                Some(code_actions)
 6393                            } else {
 6394                                None
 6395                            }
 6396                        })
 6397                })
 6398                .ok()
 6399                .flatten()
 6400        })
 6401    }
 6402
 6403    pub fn confirm_code_action(
 6404        &mut self,
 6405        action: &ConfirmCodeAction,
 6406        window: &mut Window,
 6407        cx: &mut Context<Self>,
 6408    ) -> Option<Task<Result<()>>> {
 6409        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6410
 6411        let actions_menu =
 6412            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6413                menu
 6414            } else {
 6415                return None;
 6416            };
 6417
 6418        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6419        let action = actions_menu.actions.get(action_ix)?;
 6420        let title = action.label();
 6421        let buffer = actions_menu.buffer;
 6422        let workspace = self.workspace()?;
 6423
 6424        match action {
 6425            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6426                workspace.update(cx, |workspace, cx| {
 6427                    workspace.schedule_resolved_task(
 6428                        task_source_kind,
 6429                        resolved_task,
 6430                        false,
 6431                        window,
 6432                        cx,
 6433                    );
 6434
 6435                    Some(Task::ready(Ok(())))
 6436                })
 6437            }
 6438            CodeActionsItem::CodeAction {
 6439                excerpt_id,
 6440                action,
 6441                provider,
 6442            } => {
 6443                let apply_code_action =
 6444                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6445                let workspace = workspace.downgrade();
 6446                Some(cx.spawn_in(window, async move |editor, cx| {
 6447                    let project_transaction = apply_code_action.await?;
 6448                    Self::open_project_transaction(
 6449                        &editor,
 6450                        workspace,
 6451                        project_transaction,
 6452                        title,
 6453                        cx,
 6454                    )
 6455                    .await
 6456                }))
 6457            }
 6458            CodeActionsItem::DebugScenario(scenario) => {
 6459                let context = actions_menu.actions.context;
 6460
 6461                workspace.update(cx, |workspace, cx| {
 6462                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6463                    workspace.start_debug_session(
 6464                        scenario,
 6465                        context,
 6466                        Some(buffer),
 6467                        None,
 6468                        window,
 6469                        cx,
 6470                    );
 6471                });
 6472                Some(Task::ready(Ok(())))
 6473            }
 6474        }
 6475    }
 6476
 6477    pub async fn open_project_transaction(
 6478        editor: &WeakEntity<Editor>,
 6479        workspace: WeakEntity<Workspace>,
 6480        transaction: ProjectTransaction,
 6481        title: String,
 6482        cx: &mut AsyncWindowContext,
 6483    ) -> Result<()> {
 6484        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6485        cx.update(|_, cx| {
 6486            entries.sort_unstable_by_key(|(buffer, _)| {
 6487                buffer.read(cx).file().map(|f| f.path().clone())
 6488            });
 6489        })?;
 6490        if entries.is_empty() {
 6491            return Ok(());
 6492        }
 6493
 6494        // If the project transaction's edits are all contained within this editor, then
 6495        // avoid opening a new editor to display them.
 6496
 6497        if let [(buffer, transaction)] = &*entries {
 6498            let excerpt = editor.update(cx, |editor, cx| {
 6499                editor
 6500                    .buffer()
 6501                    .read(cx)
 6502                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6503            })?;
 6504            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6505                && excerpted_buffer == *buffer
 6506            {
 6507                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6508                    let excerpt_range = excerpt_range.to_offset(buffer);
 6509                    buffer
 6510                        .edited_ranges_for_transaction::<usize>(transaction)
 6511                        .all(|range| {
 6512                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6513                        })
 6514                })?;
 6515
 6516                if all_edits_within_excerpt {
 6517                    return Ok(());
 6518                }
 6519            }
 6520        }
 6521
 6522        let mut ranges_to_highlight = Vec::new();
 6523        let excerpt_buffer = cx.new(|cx| {
 6524            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6525            for (buffer_handle, transaction) in &entries {
 6526                let edited_ranges = buffer_handle
 6527                    .read(cx)
 6528                    .edited_ranges_for_transaction::<Point>(transaction)
 6529                    .collect::<Vec<_>>();
 6530                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6531                    PathKey::for_buffer(buffer_handle, cx),
 6532                    buffer_handle.clone(),
 6533                    edited_ranges,
 6534                    multibuffer_context_lines(cx),
 6535                    cx,
 6536                );
 6537
 6538                ranges_to_highlight.extend(ranges);
 6539            }
 6540            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6541            multibuffer
 6542        })?;
 6543
 6544        workspace.update_in(cx, |workspace, window, cx| {
 6545            let project = workspace.project().clone();
 6546            let editor =
 6547                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6548            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6549            editor.update(cx, |editor, cx| {
 6550                editor.highlight_background::<Self>(
 6551                    &ranges_to_highlight,
 6552                    |theme| theme.colors().editor_highlighted_line_background,
 6553                    cx,
 6554                );
 6555            });
 6556        })?;
 6557
 6558        Ok(())
 6559    }
 6560
 6561    pub fn clear_code_action_providers(&mut self) {
 6562        self.code_action_providers.clear();
 6563        self.available_code_actions.take();
 6564    }
 6565
 6566    pub fn add_code_action_provider(
 6567        &mut self,
 6568        provider: Rc<dyn CodeActionProvider>,
 6569        window: &mut Window,
 6570        cx: &mut Context<Self>,
 6571    ) {
 6572        if self
 6573            .code_action_providers
 6574            .iter()
 6575            .any(|existing_provider| existing_provider.id() == provider.id())
 6576        {
 6577            return;
 6578        }
 6579
 6580        self.code_action_providers.push(provider);
 6581        self.refresh_code_actions(window, cx);
 6582    }
 6583
 6584    pub fn remove_code_action_provider(
 6585        &mut self,
 6586        id: Arc<str>,
 6587        window: &mut Window,
 6588        cx: &mut Context<Self>,
 6589    ) {
 6590        self.code_action_providers
 6591            .retain(|provider| provider.id() != id);
 6592        self.refresh_code_actions(window, cx);
 6593    }
 6594
 6595    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6596        !self.code_action_providers.is_empty()
 6597            && EditorSettings::get_global(cx).toolbar.code_actions
 6598    }
 6599
 6600    pub fn has_available_code_actions(&self) -> bool {
 6601        self.available_code_actions
 6602            .as_ref()
 6603            .is_some_and(|(_, actions)| !actions.is_empty())
 6604    }
 6605
 6606    fn render_inline_code_actions(
 6607        &self,
 6608        icon_size: ui::IconSize,
 6609        display_row: DisplayRow,
 6610        is_active: bool,
 6611        cx: &mut Context<Self>,
 6612    ) -> AnyElement {
 6613        let show_tooltip = !self.context_menu_visible();
 6614        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6615            .icon_size(icon_size)
 6616            .shape(ui::IconButtonShape::Square)
 6617            .icon_color(ui::Color::Hidden)
 6618            .toggle_state(is_active)
 6619            .when(show_tooltip, |this| {
 6620                this.tooltip({
 6621                    let focus_handle = self.focus_handle.clone();
 6622                    move |_window, cx| {
 6623                        Tooltip::for_action_in(
 6624                            "Toggle Code Actions",
 6625                            &ToggleCodeActions {
 6626                                deployed_from: None,
 6627                                quick_launch: false,
 6628                            },
 6629                            &focus_handle,
 6630                            cx,
 6631                        )
 6632                    }
 6633                })
 6634            })
 6635            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6636                window.focus(&editor.focus_handle(cx));
 6637                editor.toggle_code_actions(
 6638                    &crate::actions::ToggleCodeActions {
 6639                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6640                            display_row,
 6641                        )),
 6642                        quick_launch: false,
 6643                    },
 6644                    window,
 6645                    cx,
 6646                );
 6647            }))
 6648            .into_any_element()
 6649    }
 6650
 6651    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6652        &self.context_menu
 6653    }
 6654
 6655    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6656        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6657            cx.background_executor()
 6658                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6659                .await;
 6660
 6661            let (start_buffer, start, _, end, newest_selection) = this
 6662                .update(cx, |this, cx| {
 6663                    let newest_selection = this.selections.newest_anchor().clone();
 6664                    if newest_selection.head().diff_base_anchor.is_some() {
 6665                        return None;
 6666                    }
 6667                    let display_snapshot = this.display_snapshot(cx);
 6668                    let newest_selection_adjusted =
 6669                        this.selections.newest_adjusted(&display_snapshot);
 6670                    let buffer = this.buffer.read(cx);
 6671
 6672                    let (start_buffer, start) =
 6673                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6674                    let (end_buffer, end) =
 6675                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6676
 6677                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6678                })?
 6679                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6680                .context(
 6681                    "Expected selection to lie in a single buffer when refreshing code actions",
 6682                )?;
 6683            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6684                let providers = this.code_action_providers.clone();
 6685                let tasks = this
 6686                    .code_action_providers
 6687                    .iter()
 6688                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6689                    .collect::<Vec<_>>();
 6690                (providers, tasks)
 6691            })?;
 6692
 6693            let mut actions = Vec::new();
 6694            for (provider, provider_actions) in
 6695                providers.into_iter().zip(future::join_all(tasks).await)
 6696            {
 6697                if let Some(provider_actions) = provider_actions.log_err() {
 6698                    actions.extend(provider_actions.into_iter().map(|action| {
 6699                        AvailableCodeAction {
 6700                            excerpt_id: newest_selection.start.excerpt_id,
 6701                            action,
 6702                            provider: provider.clone(),
 6703                        }
 6704                    }));
 6705                }
 6706            }
 6707
 6708            this.update(cx, |this, cx| {
 6709                this.available_code_actions = if actions.is_empty() {
 6710                    None
 6711                } else {
 6712                    Some((
 6713                        Location {
 6714                            buffer: start_buffer,
 6715                            range: start..end,
 6716                        },
 6717                        actions.into(),
 6718                    ))
 6719                };
 6720                cx.notify();
 6721            })
 6722        }));
 6723    }
 6724
 6725    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6726        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6727            self.show_git_blame_inline = false;
 6728
 6729            self.show_git_blame_inline_delay_task =
 6730                Some(cx.spawn_in(window, async move |this, cx| {
 6731                    cx.background_executor().timer(delay).await;
 6732
 6733                    this.update(cx, |this, cx| {
 6734                        this.show_git_blame_inline = true;
 6735                        cx.notify();
 6736                    })
 6737                    .log_err();
 6738                }));
 6739        }
 6740    }
 6741
 6742    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6743        let snapshot = self.snapshot(window, cx);
 6744        let cursor = self
 6745            .selections
 6746            .newest::<Point>(&snapshot.display_snapshot)
 6747            .head();
 6748        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6749        else {
 6750            return;
 6751        };
 6752
 6753        let Some(blame) = self.blame.as_ref() else {
 6754            return;
 6755        };
 6756
 6757        let row_info = RowInfo {
 6758            buffer_id: Some(buffer.remote_id()),
 6759            buffer_row: Some(point.row),
 6760            ..Default::default()
 6761        };
 6762        let Some((buffer, blame_entry)) = blame
 6763            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6764            .flatten()
 6765        else {
 6766            return;
 6767        };
 6768
 6769        let anchor = self.selections.newest_anchor().head();
 6770        let position = self.to_pixel_point(anchor, &snapshot, window);
 6771        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6772            self.show_blame_popover(
 6773                buffer,
 6774                &blame_entry,
 6775                position + last_bounds.origin,
 6776                true,
 6777                cx,
 6778            );
 6779        };
 6780    }
 6781
 6782    fn show_blame_popover(
 6783        &mut self,
 6784        buffer: BufferId,
 6785        blame_entry: &BlameEntry,
 6786        position: gpui::Point<Pixels>,
 6787        ignore_timeout: bool,
 6788        cx: &mut Context<Self>,
 6789    ) {
 6790        if let Some(state) = &mut self.inline_blame_popover {
 6791            state.hide_task.take();
 6792        } else {
 6793            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6794            let blame_entry = blame_entry.clone();
 6795            let show_task = cx.spawn(async move |editor, cx| {
 6796                if !ignore_timeout {
 6797                    cx.background_executor()
 6798                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6799                        .await;
 6800                }
 6801                editor
 6802                    .update(cx, |editor, cx| {
 6803                        editor.inline_blame_popover_show_task.take();
 6804                        let Some(blame) = editor.blame.as_ref() else {
 6805                            return;
 6806                        };
 6807                        let blame = blame.read(cx);
 6808                        let details = blame.details_for_entry(buffer, &blame_entry);
 6809                        let markdown = cx.new(|cx| {
 6810                            Markdown::new(
 6811                                details
 6812                                    .as_ref()
 6813                                    .map(|message| message.message.clone())
 6814                                    .unwrap_or_default(),
 6815                                None,
 6816                                None,
 6817                                cx,
 6818                            )
 6819                        });
 6820                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6821                            position,
 6822                            hide_task: None,
 6823                            popover_bounds: None,
 6824                            popover_state: InlineBlamePopoverState {
 6825                                scroll_handle: ScrollHandle::new(),
 6826                                commit_message: details,
 6827                                markdown,
 6828                            },
 6829                            keyboard_grace: ignore_timeout,
 6830                        });
 6831                        cx.notify();
 6832                    })
 6833                    .ok();
 6834            });
 6835            self.inline_blame_popover_show_task = Some(show_task);
 6836        }
 6837    }
 6838
 6839    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6840        self.inline_blame_popover_show_task.take();
 6841        if let Some(state) = &mut self.inline_blame_popover {
 6842            let hide_task = cx.spawn(async move |editor, cx| {
 6843                if !ignore_timeout {
 6844                    cx.background_executor()
 6845                        .timer(std::time::Duration::from_millis(100))
 6846                        .await;
 6847                }
 6848                editor
 6849                    .update(cx, |editor, cx| {
 6850                        editor.inline_blame_popover.take();
 6851                        cx.notify();
 6852                    })
 6853                    .ok();
 6854            });
 6855            state.hide_task = Some(hide_task);
 6856            true
 6857        } else {
 6858            false
 6859        }
 6860    }
 6861
 6862    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6863        if self.pending_rename.is_some() {
 6864            return None;
 6865        }
 6866
 6867        let provider = self.semantics_provider.clone()?;
 6868        let buffer = self.buffer.read(cx);
 6869        let newest_selection = self.selections.newest_anchor().clone();
 6870        let cursor_position = newest_selection.head();
 6871        let (cursor_buffer, cursor_buffer_position) =
 6872            buffer.text_anchor_for_position(cursor_position, cx)?;
 6873        let (tail_buffer, tail_buffer_position) =
 6874            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6875        if cursor_buffer != tail_buffer {
 6876            return None;
 6877        }
 6878
 6879        let snapshot = cursor_buffer.read(cx).snapshot();
 6880        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6881        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6882        if start_word_range != end_word_range {
 6883            self.document_highlights_task.take();
 6884            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6885            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6886            return None;
 6887        }
 6888
 6889        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6890        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6891            cx.background_executor()
 6892                .timer(Duration::from_millis(debounce))
 6893                .await;
 6894
 6895            let highlights = if let Some(highlights) = cx
 6896                .update(|cx| {
 6897                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6898                })
 6899                .ok()
 6900                .flatten()
 6901            {
 6902                highlights.await.log_err()
 6903            } else {
 6904                None
 6905            };
 6906
 6907            if let Some(highlights) = highlights {
 6908                this.update(cx, |this, cx| {
 6909                    if this.pending_rename.is_some() {
 6910                        return;
 6911                    }
 6912
 6913                    let buffer = this.buffer.read(cx);
 6914                    if buffer
 6915                        .text_anchor_for_position(cursor_position, cx)
 6916                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6917                    {
 6918                        return;
 6919                    }
 6920
 6921                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6922                    let mut write_ranges = Vec::new();
 6923                    let mut read_ranges = Vec::new();
 6924                    for highlight in highlights {
 6925                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6926                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6927                        {
 6928                            let start = highlight
 6929                                .range
 6930                                .start
 6931                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6932                            let end = highlight
 6933                                .range
 6934                                .end
 6935                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6936                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6937                                continue;
 6938                            }
 6939
 6940                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 6941                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6942                                write_ranges.push(range);
 6943                            } else {
 6944                                read_ranges.push(range);
 6945                            }
 6946                        }
 6947                    }
 6948
 6949                    this.highlight_background::<DocumentHighlightRead>(
 6950                        &read_ranges,
 6951                        |theme| theme.colors().editor_document_highlight_read_background,
 6952                        cx,
 6953                    );
 6954                    this.highlight_background::<DocumentHighlightWrite>(
 6955                        &write_ranges,
 6956                        |theme| theme.colors().editor_document_highlight_write_background,
 6957                        cx,
 6958                    );
 6959                    cx.notify();
 6960                })
 6961                .log_err();
 6962            }
 6963        }));
 6964        None
 6965    }
 6966
 6967    fn prepare_highlight_query_from_selection(
 6968        &mut self,
 6969        window: &Window,
 6970        cx: &mut Context<Editor>,
 6971    ) -> Option<(String, Range<Anchor>)> {
 6972        if matches!(self.mode, EditorMode::SingleLine) {
 6973            return None;
 6974        }
 6975        if !EditorSettings::get_global(cx).selection_highlight {
 6976            return None;
 6977        }
 6978        if self.selections.count() != 1 || self.selections.line_mode() {
 6979            return None;
 6980        }
 6981        let snapshot = self.snapshot(window, cx);
 6982        let selection = self.selections.newest::<Point>(&snapshot);
 6983        // If the selection spans multiple rows OR it is empty
 6984        if selection.start.row != selection.end.row
 6985            || selection.start.column == selection.end.column
 6986        {
 6987            return None;
 6988        }
 6989        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6990        let query = snapshot
 6991            .buffer_snapshot()
 6992            .text_for_range(selection_anchor_range.clone())
 6993            .collect::<String>();
 6994        if query.trim().is_empty() {
 6995            return None;
 6996        }
 6997        Some((query, selection_anchor_range))
 6998    }
 6999
 7000    fn update_selection_occurrence_highlights(
 7001        &mut self,
 7002        query_text: String,
 7003        query_range: Range<Anchor>,
 7004        multi_buffer_range_to_query: Range<Point>,
 7005        use_debounce: bool,
 7006        window: &mut Window,
 7007        cx: &mut Context<Editor>,
 7008    ) -> Task<()> {
 7009        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7010        cx.spawn_in(window, async move |editor, cx| {
 7011            if use_debounce {
 7012                cx.background_executor()
 7013                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7014                    .await;
 7015            }
 7016            let match_task = cx.background_spawn(async move {
 7017                let buffer_ranges = multi_buffer_snapshot
 7018                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7019                    .into_iter()
 7020                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7021                let mut match_ranges = Vec::new();
 7022                let Ok(regex) = project::search::SearchQuery::text(
 7023                    query_text.clone(),
 7024                    false,
 7025                    false,
 7026                    false,
 7027                    Default::default(),
 7028                    Default::default(),
 7029                    false,
 7030                    None,
 7031                ) else {
 7032                    return Vec::default();
 7033                };
 7034                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7035                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7036                    match_ranges.extend(
 7037                        regex
 7038                            .search(
 7039                                buffer_snapshot,
 7040                                Some(search_range.start.0..search_range.end.0),
 7041                            )
 7042                            .await
 7043                            .into_iter()
 7044                            .filter_map(|match_range| {
 7045                                let match_start = buffer_snapshot
 7046                                    .anchor_after(search_range.start + match_range.start);
 7047                                let match_end = buffer_snapshot
 7048                                    .anchor_before(search_range.start + match_range.end);
 7049                                let match_anchor_range =
 7050                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7051                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7052                            }),
 7053                    );
 7054                }
 7055                match_ranges
 7056            });
 7057            let match_ranges = match_task.await;
 7058            editor
 7059                .update_in(cx, |editor, _, cx| {
 7060                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7061                    if !match_ranges.is_empty() {
 7062                        editor.highlight_background::<SelectedTextHighlight>(
 7063                            &match_ranges,
 7064                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7065                            cx,
 7066                        )
 7067                    }
 7068                })
 7069                .log_err();
 7070        })
 7071    }
 7072
 7073    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7074        struct NewlineFold;
 7075        let type_id = std::any::TypeId::of::<NewlineFold>();
 7076        if !self.mode.is_single_line() {
 7077            return;
 7078        }
 7079        let snapshot = self.snapshot(window, cx);
 7080        if snapshot.buffer_snapshot().max_point().row == 0 {
 7081            return;
 7082        }
 7083        let task = cx.background_spawn(async move {
 7084            let new_newlines = snapshot
 7085                .buffer_chars_at(MultiBufferOffset(0))
 7086                .filter_map(|(c, i)| {
 7087                    if c == '\n' {
 7088                        Some(
 7089                            snapshot.buffer_snapshot().anchor_after(i)
 7090                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7091                        )
 7092                    } else {
 7093                        None
 7094                    }
 7095                })
 7096                .collect::<Vec<_>>();
 7097            let existing_newlines = snapshot
 7098                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7099                .filter_map(|fold| {
 7100                    if fold.placeholder.type_tag == Some(type_id) {
 7101                        Some(fold.range.start..fold.range.end)
 7102                    } else {
 7103                        None
 7104                    }
 7105                })
 7106                .collect::<Vec<_>>();
 7107
 7108            (new_newlines, existing_newlines)
 7109        });
 7110        self.folding_newlines = cx.spawn(async move |this, cx| {
 7111            let (new_newlines, existing_newlines) = task.await;
 7112            if new_newlines == existing_newlines {
 7113                return;
 7114            }
 7115            let placeholder = FoldPlaceholder {
 7116                render: Arc::new(move |_, _, cx| {
 7117                    div()
 7118                        .bg(cx.theme().status().hint_background)
 7119                        .border_b_1()
 7120                        .size_full()
 7121                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7122                        .border_color(cx.theme().status().hint)
 7123                        .child("\\n")
 7124                        .into_any()
 7125                }),
 7126                constrain_width: false,
 7127                merge_adjacent: false,
 7128                type_tag: Some(type_id),
 7129            };
 7130            let creases = new_newlines
 7131                .into_iter()
 7132                .map(|range| Crease::simple(range, placeholder.clone()))
 7133                .collect();
 7134            this.update(cx, |this, cx| {
 7135                this.display_map.update(cx, |display_map, cx| {
 7136                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7137                    display_map.fold(creases, cx);
 7138                });
 7139            })
 7140            .ok();
 7141        });
 7142    }
 7143
 7144    fn refresh_selected_text_highlights(
 7145        &mut self,
 7146        on_buffer_edit: bool,
 7147        window: &mut Window,
 7148        cx: &mut Context<Editor>,
 7149    ) {
 7150        let Some((query_text, query_range)) =
 7151            self.prepare_highlight_query_from_selection(window, cx)
 7152        else {
 7153            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7154            self.quick_selection_highlight_task.take();
 7155            self.debounced_selection_highlight_task.take();
 7156            return;
 7157        };
 7158        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7159        if on_buffer_edit
 7160            || self
 7161                .quick_selection_highlight_task
 7162                .as_ref()
 7163                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7164        {
 7165            let multi_buffer_visible_start = self
 7166                .scroll_manager
 7167                .anchor()
 7168                .anchor
 7169                .to_point(&multi_buffer_snapshot);
 7170            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7171                multi_buffer_visible_start
 7172                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7173                Bias::Left,
 7174            );
 7175            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7176            self.quick_selection_highlight_task = Some((
 7177                query_range.clone(),
 7178                self.update_selection_occurrence_highlights(
 7179                    query_text.clone(),
 7180                    query_range.clone(),
 7181                    multi_buffer_visible_range,
 7182                    false,
 7183                    window,
 7184                    cx,
 7185                ),
 7186            ));
 7187        }
 7188        if on_buffer_edit
 7189            || self
 7190                .debounced_selection_highlight_task
 7191                .as_ref()
 7192                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7193        {
 7194            let multi_buffer_start = multi_buffer_snapshot
 7195                .anchor_before(MultiBufferOffset(0))
 7196                .to_point(&multi_buffer_snapshot);
 7197            let multi_buffer_end = multi_buffer_snapshot
 7198                .anchor_after(multi_buffer_snapshot.len())
 7199                .to_point(&multi_buffer_snapshot);
 7200            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7201            self.debounced_selection_highlight_task = Some((
 7202                query_range.clone(),
 7203                self.update_selection_occurrence_highlights(
 7204                    query_text,
 7205                    query_range,
 7206                    multi_buffer_full_range,
 7207                    true,
 7208                    window,
 7209                    cx,
 7210                ),
 7211            ));
 7212        }
 7213    }
 7214
 7215    pub fn refresh_edit_prediction(
 7216        &mut self,
 7217        debounce: bool,
 7218        user_requested: bool,
 7219        window: &mut Window,
 7220        cx: &mut Context<Self>,
 7221    ) -> Option<()> {
 7222        if DisableAiSettings::get_global(cx).disable_ai {
 7223            return None;
 7224        }
 7225
 7226        let provider = self.edit_prediction_provider()?;
 7227        let cursor = self.selections.newest_anchor().head();
 7228        let (buffer, cursor_buffer_position) =
 7229            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7230
 7231        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7232            self.discard_edit_prediction(false, cx);
 7233            return None;
 7234        }
 7235
 7236        self.update_visible_edit_prediction(window, cx);
 7237
 7238        if !user_requested
 7239            && (!self.should_show_edit_predictions()
 7240                || !self.is_focused(window)
 7241                || buffer.read(cx).is_empty())
 7242        {
 7243            self.discard_edit_prediction(false, cx);
 7244            return None;
 7245        }
 7246
 7247        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7248        Some(())
 7249    }
 7250
 7251    fn show_edit_predictions_in_menu(&self) -> bool {
 7252        match self.edit_prediction_settings {
 7253            EditPredictionSettings::Disabled => false,
 7254            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7255        }
 7256    }
 7257
 7258    pub fn edit_predictions_enabled(&self) -> bool {
 7259        match self.edit_prediction_settings {
 7260            EditPredictionSettings::Disabled => false,
 7261            EditPredictionSettings::Enabled { .. } => true,
 7262        }
 7263    }
 7264
 7265    fn edit_prediction_requires_modifier(&self) -> bool {
 7266        match self.edit_prediction_settings {
 7267            EditPredictionSettings::Disabled => false,
 7268            EditPredictionSettings::Enabled {
 7269                preview_requires_modifier,
 7270                ..
 7271            } => preview_requires_modifier,
 7272        }
 7273    }
 7274
 7275    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7276        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7277            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7278            self.discard_edit_prediction(false, cx);
 7279        } else {
 7280            let selection = self.selections.newest_anchor();
 7281            let cursor = selection.head();
 7282
 7283            if let Some((buffer, cursor_buffer_position)) =
 7284                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7285            {
 7286                self.edit_prediction_settings =
 7287                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7288            }
 7289        }
 7290    }
 7291
 7292    fn edit_prediction_settings_at_position(
 7293        &self,
 7294        buffer: &Entity<Buffer>,
 7295        buffer_position: language::Anchor,
 7296        cx: &App,
 7297    ) -> EditPredictionSettings {
 7298        if !self.mode.is_full()
 7299            || !self.show_edit_predictions_override.unwrap_or(true)
 7300            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7301        {
 7302            return EditPredictionSettings::Disabled;
 7303        }
 7304
 7305        let buffer = buffer.read(cx);
 7306
 7307        let file = buffer.file();
 7308
 7309        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7310            return EditPredictionSettings::Disabled;
 7311        };
 7312
 7313        let by_provider = matches!(
 7314            self.menu_edit_predictions_policy,
 7315            MenuEditPredictionsPolicy::ByProvider
 7316        );
 7317
 7318        let show_in_menu = by_provider
 7319            && self
 7320                .edit_prediction_provider
 7321                .as_ref()
 7322                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7323
 7324        let preview_requires_modifier =
 7325            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7326
 7327        EditPredictionSettings::Enabled {
 7328            show_in_menu,
 7329            preview_requires_modifier,
 7330        }
 7331    }
 7332
 7333    fn should_show_edit_predictions(&self) -> bool {
 7334        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7335    }
 7336
 7337    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7338        matches!(
 7339            self.edit_prediction_preview,
 7340            EditPredictionPreview::Active { .. }
 7341        )
 7342    }
 7343
 7344    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7345        let cursor = self.selections.newest_anchor().head();
 7346        if let Some((buffer, cursor_position)) =
 7347            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7348        {
 7349            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7350        } else {
 7351            false
 7352        }
 7353    }
 7354
 7355    pub fn supports_minimap(&self, cx: &App) -> bool {
 7356        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7357    }
 7358
 7359    fn edit_predictions_enabled_in_buffer(
 7360        &self,
 7361        buffer: &Entity<Buffer>,
 7362        buffer_position: language::Anchor,
 7363        cx: &App,
 7364    ) -> bool {
 7365        maybe!({
 7366            if self.read_only(cx) {
 7367                return Some(false);
 7368            }
 7369            let provider = self.edit_prediction_provider()?;
 7370            if !provider.is_enabled(buffer, buffer_position, cx) {
 7371                return Some(false);
 7372            }
 7373            let buffer = buffer.read(cx);
 7374            let Some(file) = buffer.file() else {
 7375                return Some(true);
 7376            };
 7377            let settings = all_language_settings(Some(file), cx);
 7378            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7379        })
 7380        .unwrap_or(false)
 7381    }
 7382
 7383    fn cycle_edit_prediction(
 7384        &mut self,
 7385        direction: Direction,
 7386        window: &mut Window,
 7387        cx: &mut Context<Self>,
 7388    ) -> Option<()> {
 7389        let provider = self.edit_prediction_provider()?;
 7390        let cursor = self.selections.newest_anchor().head();
 7391        let (buffer, cursor_buffer_position) =
 7392            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7393        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7394            return None;
 7395        }
 7396
 7397        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7398        self.update_visible_edit_prediction(window, cx);
 7399
 7400        Some(())
 7401    }
 7402
 7403    pub fn show_edit_prediction(
 7404        &mut self,
 7405        _: &ShowEditPrediction,
 7406        window: &mut Window,
 7407        cx: &mut Context<Self>,
 7408    ) {
 7409        if !self.has_active_edit_prediction() {
 7410            self.refresh_edit_prediction(false, true, window, cx);
 7411            return;
 7412        }
 7413
 7414        self.update_visible_edit_prediction(window, cx);
 7415    }
 7416
 7417    pub fn display_cursor_names(
 7418        &mut self,
 7419        _: &DisplayCursorNames,
 7420        window: &mut Window,
 7421        cx: &mut Context<Self>,
 7422    ) {
 7423        self.show_cursor_names(window, cx);
 7424    }
 7425
 7426    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7427        self.show_cursor_names = true;
 7428        cx.notify();
 7429        cx.spawn_in(window, async move |this, cx| {
 7430            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7431            this.update(cx, |this, cx| {
 7432                this.show_cursor_names = false;
 7433                cx.notify()
 7434            })
 7435            .ok()
 7436        })
 7437        .detach();
 7438    }
 7439
 7440    pub fn next_edit_prediction(
 7441        &mut self,
 7442        _: &NextEditPrediction,
 7443        window: &mut Window,
 7444        cx: &mut Context<Self>,
 7445    ) {
 7446        if self.has_active_edit_prediction() {
 7447            self.cycle_edit_prediction(Direction::Next, window, cx);
 7448        } else {
 7449            let is_copilot_disabled = self
 7450                .refresh_edit_prediction(false, true, window, cx)
 7451                .is_none();
 7452            if is_copilot_disabled {
 7453                cx.propagate();
 7454            }
 7455        }
 7456    }
 7457
 7458    pub fn previous_edit_prediction(
 7459        &mut self,
 7460        _: &PreviousEditPrediction,
 7461        window: &mut Window,
 7462        cx: &mut Context<Self>,
 7463    ) {
 7464        if self.has_active_edit_prediction() {
 7465            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7466        } else {
 7467            let is_copilot_disabled = self
 7468                .refresh_edit_prediction(false, true, window, cx)
 7469                .is_none();
 7470            if is_copilot_disabled {
 7471                cx.propagate();
 7472            }
 7473        }
 7474    }
 7475
 7476    pub fn accept_edit_prediction(
 7477        &mut self,
 7478        _: &AcceptEditPrediction,
 7479        window: &mut Window,
 7480        cx: &mut Context<Self>,
 7481    ) {
 7482        if self.show_edit_predictions_in_menu() {
 7483            self.hide_context_menu(window, cx);
 7484        }
 7485
 7486        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7487            return;
 7488        };
 7489
 7490        match &active_edit_prediction.completion {
 7491            EditPrediction::MoveWithin { target, .. } => {
 7492                let target = *target;
 7493
 7494                if let Some(position_map) = &self.last_position_map {
 7495                    if position_map
 7496                        .visible_row_range
 7497                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7498                        || !self.edit_prediction_requires_modifier()
 7499                    {
 7500                        self.unfold_ranges(&[target..target], true, false, cx);
 7501                        // Note that this is also done in vim's handler of the Tab action.
 7502                        self.change_selections(
 7503                            SelectionEffects::scroll(Autoscroll::newest()),
 7504                            window,
 7505                            cx,
 7506                            |selections| {
 7507                                selections.select_anchor_ranges([target..target]);
 7508                            },
 7509                        );
 7510                        self.clear_row_highlights::<EditPredictionPreview>();
 7511
 7512                        self.edit_prediction_preview
 7513                            .set_previous_scroll_position(None);
 7514                    } else {
 7515                        self.edit_prediction_preview
 7516                            .set_previous_scroll_position(Some(
 7517                                position_map.snapshot.scroll_anchor,
 7518                            ));
 7519
 7520                        self.highlight_rows::<EditPredictionPreview>(
 7521                            target..target,
 7522                            cx.theme().colors().editor_highlighted_line_background,
 7523                            RowHighlightOptions {
 7524                                autoscroll: true,
 7525                                ..Default::default()
 7526                            },
 7527                            cx,
 7528                        );
 7529                        self.request_autoscroll(Autoscroll::fit(), cx);
 7530                    }
 7531                }
 7532            }
 7533            EditPrediction::MoveOutside { snapshot, target } => {
 7534                if let Some(workspace) = self.workspace() {
 7535                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7536                        .detach_and_log_err(cx);
 7537                }
 7538            }
 7539            EditPrediction::Edit { edits, .. } => {
 7540                self.report_edit_prediction_event(
 7541                    active_edit_prediction.completion_id.clone(),
 7542                    true,
 7543                    cx,
 7544                );
 7545
 7546                if let Some(provider) = self.edit_prediction_provider() {
 7547                    provider.accept(cx);
 7548                }
 7549
 7550                // Store the transaction ID and selections before applying the edit
 7551                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7552
 7553                let snapshot = self.buffer.read(cx).snapshot(cx);
 7554                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7555
 7556                self.buffer.update(cx, |buffer, cx| {
 7557                    buffer.edit(edits.iter().cloned(), None, cx)
 7558                });
 7559
 7560                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7561                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7562                });
 7563
 7564                let selections = self.selections.disjoint_anchors_arc();
 7565                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7566                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7567                    if has_new_transaction {
 7568                        self.selection_history
 7569                            .insert_transaction(transaction_id_now, selections);
 7570                    }
 7571                }
 7572
 7573                self.update_visible_edit_prediction(window, cx);
 7574                if self.active_edit_prediction.is_none() {
 7575                    self.refresh_edit_prediction(true, true, window, cx);
 7576                }
 7577
 7578                cx.notify();
 7579            }
 7580        }
 7581
 7582        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7583    }
 7584
 7585    pub fn accept_partial_edit_prediction(
 7586        &mut self,
 7587        _: &AcceptPartialEditPrediction,
 7588        window: &mut Window,
 7589        cx: &mut Context<Self>,
 7590    ) {
 7591        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7592            return;
 7593        };
 7594        if self.selections.count() != 1 {
 7595            return;
 7596        }
 7597
 7598        match &active_edit_prediction.completion {
 7599            EditPrediction::MoveWithin { target, .. } => {
 7600                let target = *target;
 7601                self.change_selections(
 7602                    SelectionEffects::scroll(Autoscroll::newest()),
 7603                    window,
 7604                    cx,
 7605                    |selections| {
 7606                        selections.select_anchor_ranges([target..target]);
 7607                    },
 7608                );
 7609            }
 7610            EditPrediction::MoveOutside { snapshot, target } => {
 7611                if let Some(workspace) = self.workspace() {
 7612                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7613                        .detach_and_log_err(cx);
 7614                }
 7615            }
 7616            EditPrediction::Edit { edits, .. } => {
 7617                self.report_edit_prediction_event(
 7618                    active_edit_prediction.completion_id.clone(),
 7619                    true,
 7620                    cx,
 7621                );
 7622
 7623                // Find an insertion that starts at the cursor position.
 7624                let snapshot = self.buffer.read(cx).snapshot(cx);
 7625                let cursor_offset = self
 7626                    .selections
 7627                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7628                    .head();
 7629                let insertion = edits.iter().find_map(|(range, text)| {
 7630                    let range = range.to_offset(&snapshot);
 7631                    if range.is_empty() && range.start == cursor_offset {
 7632                        Some(text)
 7633                    } else {
 7634                        None
 7635                    }
 7636                });
 7637
 7638                if let Some(text) = insertion {
 7639                    let mut partial_completion = text
 7640                        .chars()
 7641                        .by_ref()
 7642                        .take_while(|c| c.is_alphabetic())
 7643                        .collect::<String>();
 7644                    if partial_completion.is_empty() {
 7645                        partial_completion = text
 7646                            .chars()
 7647                            .by_ref()
 7648                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7649                            .collect::<String>();
 7650                    }
 7651
 7652                    cx.emit(EditorEvent::InputHandled {
 7653                        utf16_range_to_replace: None,
 7654                        text: partial_completion.clone().into(),
 7655                    });
 7656
 7657                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7658
 7659                    self.refresh_edit_prediction(true, true, window, cx);
 7660                    cx.notify();
 7661                } else {
 7662                    self.accept_edit_prediction(&Default::default(), window, cx);
 7663                }
 7664            }
 7665        }
 7666    }
 7667
 7668    fn discard_edit_prediction(
 7669        &mut self,
 7670        should_report_edit_prediction_event: bool,
 7671        cx: &mut Context<Self>,
 7672    ) -> bool {
 7673        if should_report_edit_prediction_event {
 7674            let completion_id = self
 7675                .active_edit_prediction
 7676                .as_ref()
 7677                .and_then(|active_completion| active_completion.completion_id.clone());
 7678
 7679            self.report_edit_prediction_event(completion_id, false, cx);
 7680        }
 7681
 7682        if let Some(provider) = self.edit_prediction_provider() {
 7683            provider.discard(cx);
 7684        }
 7685
 7686        self.take_active_edit_prediction(cx)
 7687    }
 7688
 7689    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7690        let Some(provider) = self.edit_prediction_provider() else {
 7691            return;
 7692        };
 7693
 7694        let Some((_, buffer, _)) = self
 7695            .buffer
 7696            .read(cx)
 7697            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7698        else {
 7699            return;
 7700        };
 7701
 7702        let extension = buffer
 7703            .read(cx)
 7704            .file()
 7705            .and_then(|file| Some(file.path().extension()?.to_string()));
 7706
 7707        let event_type = match accepted {
 7708            true => "Edit Prediction Accepted",
 7709            false => "Edit Prediction Discarded",
 7710        };
 7711        telemetry::event!(
 7712            event_type,
 7713            provider = provider.name(),
 7714            prediction_id = id,
 7715            suggestion_accepted = accepted,
 7716            file_extension = extension,
 7717        );
 7718    }
 7719
 7720    fn open_editor_at_anchor(
 7721        snapshot: &language::BufferSnapshot,
 7722        target: language::Anchor,
 7723        workspace: &Entity<Workspace>,
 7724        window: &mut Window,
 7725        cx: &mut App,
 7726    ) -> Task<Result<()>> {
 7727        workspace.update(cx, |workspace, cx| {
 7728            let path = snapshot.file().map(|file| file.full_path(cx));
 7729            let Some(path) =
 7730                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7731            else {
 7732                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7733            };
 7734            let target = text::ToPoint::to_point(&target, snapshot);
 7735            let item = workspace.open_path(path, None, true, window, cx);
 7736            window.spawn(cx, async move |cx| {
 7737                let Some(editor) = item.await?.downcast::<Editor>() else {
 7738                    return Ok(());
 7739                };
 7740                editor
 7741                    .update_in(cx, |editor, window, cx| {
 7742                        editor.go_to_singleton_buffer_point(target, window, cx);
 7743                    })
 7744                    .ok();
 7745                anyhow::Ok(())
 7746            })
 7747        })
 7748    }
 7749
 7750    pub fn has_active_edit_prediction(&self) -> bool {
 7751        self.active_edit_prediction.is_some()
 7752    }
 7753
 7754    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7755        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7756            return false;
 7757        };
 7758
 7759        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7760        self.clear_highlights::<EditPredictionHighlight>(cx);
 7761        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7762        true
 7763    }
 7764
 7765    /// Returns true when we're displaying the edit prediction popover below the cursor
 7766    /// like we are not previewing and the LSP autocomplete menu is visible
 7767    /// or we are in `when_holding_modifier` mode.
 7768    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7769        if self.edit_prediction_preview_is_active()
 7770            || !self.show_edit_predictions_in_menu()
 7771            || !self.edit_predictions_enabled()
 7772        {
 7773            return false;
 7774        }
 7775
 7776        if self.has_visible_completions_menu() {
 7777            return true;
 7778        }
 7779
 7780        has_completion && self.edit_prediction_requires_modifier()
 7781    }
 7782
 7783    fn handle_modifiers_changed(
 7784        &mut self,
 7785        modifiers: Modifiers,
 7786        position_map: &PositionMap,
 7787        window: &mut Window,
 7788        cx: &mut Context<Self>,
 7789    ) {
 7790        // Ensure that the edit prediction preview is updated, even when not
 7791        // enabled, if there's an active edit prediction preview.
 7792        if self.show_edit_predictions_in_menu()
 7793            || matches!(
 7794                self.edit_prediction_preview,
 7795                EditPredictionPreview::Active { .. }
 7796            )
 7797        {
 7798            self.update_edit_prediction_preview(&modifiers, window, cx);
 7799        }
 7800
 7801        self.update_selection_mode(&modifiers, position_map, window, cx);
 7802
 7803        let mouse_position = window.mouse_position();
 7804        if !position_map.text_hitbox.is_hovered(window) {
 7805            return;
 7806        }
 7807
 7808        self.update_hovered_link(
 7809            position_map.point_for_position(mouse_position),
 7810            &position_map.snapshot,
 7811            modifiers,
 7812            window,
 7813            cx,
 7814        )
 7815    }
 7816
 7817    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7818        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7819            MultiCursorModifier::Alt => modifiers.secondary(),
 7820            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7821        }
 7822    }
 7823
 7824    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7825        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7826            MultiCursorModifier::Alt => modifiers.alt,
 7827            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7828        }
 7829    }
 7830
 7831    fn columnar_selection_mode(
 7832        modifiers: &Modifiers,
 7833        cx: &mut Context<Self>,
 7834    ) -> Option<ColumnarMode> {
 7835        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7836            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7837                Some(ColumnarMode::FromMouse)
 7838            } else if Self::is_alt_pressed(modifiers, cx) {
 7839                Some(ColumnarMode::FromSelection)
 7840            } else {
 7841                None
 7842            }
 7843        } else {
 7844            None
 7845        }
 7846    }
 7847
 7848    fn update_selection_mode(
 7849        &mut self,
 7850        modifiers: &Modifiers,
 7851        position_map: &PositionMap,
 7852        window: &mut Window,
 7853        cx: &mut Context<Self>,
 7854    ) {
 7855        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7856            return;
 7857        };
 7858        if self.selections.pending_anchor().is_none() {
 7859            return;
 7860        }
 7861
 7862        let mouse_position = window.mouse_position();
 7863        let point_for_position = position_map.point_for_position(mouse_position);
 7864        let position = point_for_position.previous_valid;
 7865
 7866        self.select(
 7867            SelectPhase::BeginColumnar {
 7868                position,
 7869                reset: false,
 7870                mode,
 7871                goal_column: point_for_position.exact_unclipped.column(),
 7872            },
 7873            window,
 7874            cx,
 7875        );
 7876    }
 7877
 7878    fn update_edit_prediction_preview(
 7879        &mut self,
 7880        modifiers: &Modifiers,
 7881        window: &mut Window,
 7882        cx: &mut Context<Self>,
 7883    ) {
 7884        let mut modifiers_held = false;
 7885        if let Some(accept_keystroke) = self
 7886            .accept_edit_prediction_keybind(false, window, cx)
 7887            .keystroke()
 7888        {
 7889            modifiers_held = modifiers_held
 7890                || (accept_keystroke.modifiers() == modifiers
 7891                    && accept_keystroke.modifiers().modified());
 7892        };
 7893        if let Some(accept_partial_keystroke) = self
 7894            .accept_edit_prediction_keybind(true, window, cx)
 7895            .keystroke()
 7896        {
 7897            modifiers_held = modifiers_held
 7898                || (accept_partial_keystroke.modifiers() == modifiers
 7899                    && accept_partial_keystroke.modifiers().modified());
 7900        }
 7901
 7902        if modifiers_held {
 7903            if matches!(
 7904                self.edit_prediction_preview,
 7905                EditPredictionPreview::Inactive { .. }
 7906            ) {
 7907                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7908                    provider.provider.did_show(cx)
 7909                }
 7910
 7911                self.edit_prediction_preview = EditPredictionPreview::Active {
 7912                    previous_scroll_position: None,
 7913                    since: Instant::now(),
 7914                };
 7915
 7916                self.update_visible_edit_prediction(window, cx);
 7917                cx.notify();
 7918            }
 7919        } else if let EditPredictionPreview::Active {
 7920            previous_scroll_position,
 7921            since,
 7922        } = self.edit_prediction_preview
 7923        {
 7924            if let (Some(previous_scroll_position), Some(position_map)) =
 7925                (previous_scroll_position, self.last_position_map.as_ref())
 7926            {
 7927                self.set_scroll_position(
 7928                    previous_scroll_position
 7929                        .scroll_position(&position_map.snapshot.display_snapshot),
 7930                    window,
 7931                    cx,
 7932                );
 7933            }
 7934
 7935            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7936                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7937            };
 7938            self.clear_row_highlights::<EditPredictionPreview>();
 7939            self.update_visible_edit_prediction(window, cx);
 7940            cx.notify();
 7941        }
 7942    }
 7943
 7944    fn update_visible_edit_prediction(
 7945        &mut self,
 7946        _window: &mut Window,
 7947        cx: &mut Context<Self>,
 7948    ) -> Option<()> {
 7949        if DisableAiSettings::get_global(cx).disable_ai {
 7950            return None;
 7951        }
 7952
 7953        if self.ime_transaction.is_some() {
 7954            self.discard_edit_prediction(false, cx);
 7955            return None;
 7956        }
 7957
 7958        let selection = self.selections.newest_anchor();
 7959        let cursor = selection.head();
 7960        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7961        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7962        let excerpt_id = cursor.excerpt_id;
 7963
 7964        let show_in_menu = self.show_edit_predictions_in_menu();
 7965        let completions_menu_has_precedence = !show_in_menu
 7966            && (self.context_menu.borrow().is_some()
 7967                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7968
 7969        if completions_menu_has_precedence
 7970            || !offset_selection.is_empty()
 7971            || self
 7972                .active_edit_prediction
 7973                .as_ref()
 7974                .is_some_and(|completion| {
 7975                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7976                        return false;
 7977                    };
 7978                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7979                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7980                    !invalidation_range.contains(&offset_selection.head())
 7981                })
 7982        {
 7983            self.discard_edit_prediction(false, cx);
 7984            return None;
 7985        }
 7986
 7987        self.take_active_edit_prediction(cx);
 7988        let Some(provider) = self.edit_prediction_provider() else {
 7989            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7990            return None;
 7991        };
 7992
 7993        let (buffer, cursor_buffer_position) =
 7994            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7995
 7996        self.edit_prediction_settings =
 7997            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7998
 7999        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8000
 8001        if self.edit_prediction_indent_conflict {
 8002            let cursor_point = cursor.to_point(&multibuffer);
 8003
 8004            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8005
 8006            if let Some((_, indent)) = indents.iter().next()
 8007                && indent.len == cursor_point.column
 8008            {
 8009                self.edit_prediction_indent_conflict = false;
 8010            }
 8011        }
 8012
 8013        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8014
 8015        let (completion_id, edits, edit_preview) = match edit_prediction {
 8016            edit_prediction::EditPrediction::Local {
 8017                id,
 8018                edits,
 8019                edit_preview,
 8020            } => (id, edits, edit_preview),
 8021            edit_prediction::EditPrediction::Jump {
 8022                id,
 8023                snapshot,
 8024                target,
 8025            } => {
 8026                self.stale_edit_prediction_in_menu = None;
 8027                self.active_edit_prediction = Some(EditPredictionState {
 8028                    inlay_ids: vec![],
 8029                    completion: EditPrediction::MoveOutside { snapshot, target },
 8030                    completion_id: id,
 8031                    invalidation_range: None,
 8032                });
 8033                cx.notify();
 8034                return Some(());
 8035            }
 8036        };
 8037
 8038        let edits = edits
 8039            .into_iter()
 8040            .flat_map(|(range, new_text)| {
 8041                Some((
 8042                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8043                    new_text,
 8044                ))
 8045            })
 8046            .collect::<Vec<_>>();
 8047        if edits.is_empty() {
 8048            return None;
 8049        }
 8050
 8051        let first_edit_start = edits.first().unwrap().0.start;
 8052        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8053        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8054
 8055        let last_edit_end = edits.last().unwrap().0.end;
 8056        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8057        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8058
 8059        let cursor_row = cursor.to_point(&multibuffer).row;
 8060
 8061        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8062
 8063        let mut inlay_ids = Vec::new();
 8064        let invalidation_row_range;
 8065        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8066            Some(cursor_row..edit_end_row)
 8067        } else if cursor_row > edit_end_row {
 8068            Some(edit_start_row..cursor_row)
 8069        } else {
 8070            None
 8071        };
 8072        let supports_jump = self
 8073            .edit_prediction_provider
 8074            .as_ref()
 8075            .map(|provider| provider.provider.supports_jump_to_edit())
 8076            .unwrap_or(true);
 8077
 8078        let is_move = supports_jump
 8079            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8080        let completion = if is_move {
 8081            invalidation_row_range =
 8082                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8083            let target = first_edit_start;
 8084            EditPrediction::MoveWithin { target, snapshot }
 8085        } else {
 8086            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8087                && !self.edit_predictions_hidden_for_vim_mode;
 8088
 8089            if show_completions_in_buffer {
 8090                if let Some(provider) = &self.edit_prediction_provider {
 8091                    provider.provider.did_show(cx);
 8092                }
 8093                if edits
 8094                    .iter()
 8095                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8096                {
 8097                    let mut inlays = Vec::new();
 8098                    for (range, new_text) in &edits {
 8099                        let inlay = Inlay::edit_prediction(
 8100                            post_inc(&mut self.next_inlay_id),
 8101                            range.start,
 8102                            new_text.as_ref(),
 8103                        );
 8104                        inlay_ids.push(inlay.id);
 8105                        inlays.push(inlay);
 8106                    }
 8107
 8108                    self.splice_inlays(&[], inlays, cx);
 8109                } else {
 8110                    let background_color = cx.theme().status().deleted_background;
 8111                    self.highlight_text::<EditPredictionHighlight>(
 8112                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8113                        HighlightStyle {
 8114                            background_color: Some(background_color),
 8115                            ..Default::default()
 8116                        },
 8117                        cx,
 8118                    );
 8119                }
 8120            }
 8121
 8122            invalidation_row_range = edit_start_row..edit_end_row;
 8123
 8124            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8125                if provider.show_tab_accept_marker() {
 8126                    EditDisplayMode::TabAccept
 8127                } else {
 8128                    EditDisplayMode::Inline
 8129                }
 8130            } else {
 8131                EditDisplayMode::DiffPopover
 8132            };
 8133
 8134            EditPrediction::Edit {
 8135                edits,
 8136                edit_preview,
 8137                display_mode,
 8138                snapshot,
 8139            }
 8140        };
 8141
 8142        let invalidation_range = multibuffer
 8143            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8144            ..multibuffer.anchor_after(Point::new(
 8145                invalidation_row_range.end,
 8146                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8147            ));
 8148
 8149        self.stale_edit_prediction_in_menu = None;
 8150        self.active_edit_prediction = Some(EditPredictionState {
 8151            inlay_ids,
 8152            completion,
 8153            completion_id,
 8154            invalidation_range: Some(invalidation_range),
 8155        });
 8156
 8157        cx.notify();
 8158
 8159        Some(())
 8160    }
 8161
 8162    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8163        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8164    }
 8165
 8166    fn clear_tasks(&mut self) {
 8167        self.tasks.clear()
 8168    }
 8169
 8170    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8171        if self.tasks.insert(key, value).is_some() {
 8172            // This case should hopefully be rare, but just in case...
 8173            log::error!(
 8174                "multiple different run targets found on a single line, only the last target will be rendered"
 8175            )
 8176        }
 8177    }
 8178
 8179    /// Get all display points of breakpoints that will be rendered within editor
 8180    ///
 8181    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8182    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8183    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8184    fn active_breakpoints(
 8185        &self,
 8186        range: Range<DisplayRow>,
 8187        window: &mut Window,
 8188        cx: &mut Context<Self>,
 8189    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8190        let mut breakpoint_display_points = HashMap::default();
 8191
 8192        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8193            return breakpoint_display_points;
 8194        };
 8195
 8196        let snapshot = self.snapshot(window, cx);
 8197
 8198        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8199        let Some(project) = self.project() else {
 8200            return breakpoint_display_points;
 8201        };
 8202
 8203        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8204            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8205
 8206        for (buffer_snapshot, range, excerpt_id) in
 8207            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8208        {
 8209            let Some(buffer) = project
 8210                .read(cx)
 8211                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8212            else {
 8213                continue;
 8214            };
 8215            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8216                &buffer,
 8217                Some(
 8218                    buffer_snapshot.anchor_before(range.start)
 8219                        ..buffer_snapshot.anchor_after(range.end),
 8220                ),
 8221                buffer_snapshot,
 8222                cx,
 8223            );
 8224            for (breakpoint, state) in breakpoints {
 8225                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8226                let position = multi_buffer_anchor
 8227                    .to_point(&multi_buffer_snapshot)
 8228                    .to_display_point(&snapshot);
 8229
 8230                breakpoint_display_points.insert(
 8231                    position.row(),
 8232                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8233                );
 8234            }
 8235        }
 8236
 8237        breakpoint_display_points
 8238    }
 8239
 8240    fn breakpoint_context_menu(
 8241        &self,
 8242        anchor: Anchor,
 8243        window: &mut Window,
 8244        cx: &mut Context<Self>,
 8245    ) -> Entity<ui::ContextMenu> {
 8246        let weak_editor = cx.weak_entity();
 8247        let focus_handle = self.focus_handle(cx);
 8248
 8249        let row = self
 8250            .buffer
 8251            .read(cx)
 8252            .snapshot(cx)
 8253            .summary_for_anchor::<Point>(&anchor)
 8254            .row;
 8255
 8256        let breakpoint = self
 8257            .breakpoint_at_row(row, window, cx)
 8258            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8259
 8260        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8261            "Edit Log Breakpoint"
 8262        } else {
 8263            "Set Log Breakpoint"
 8264        };
 8265
 8266        let condition_breakpoint_msg = if breakpoint
 8267            .as_ref()
 8268            .is_some_and(|bp| bp.1.condition.is_some())
 8269        {
 8270            "Edit Condition Breakpoint"
 8271        } else {
 8272            "Set Condition Breakpoint"
 8273        };
 8274
 8275        let hit_condition_breakpoint_msg = if breakpoint
 8276            .as_ref()
 8277            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8278        {
 8279            "Edit Hit Condition Breakpoint"
 8280        } else {
 8281            "Set Hit Condition Breakpoint"
 8282        };
 8283
 8284        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8285            "Unset Breakpoint"
 8286        } else {
 8287            "Set Breakpoint"
 8288        };
 8289
 8290        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8291
 8292        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8293            BreakpointState::Enabled => Some("Disable"),
 8294            BreakpointState::Disabled => Some("Enable"),
 8295        });
 8296
 8297        let (anchor, breakpoint) =
 8298            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8299
 8300        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8301            menu.on_blur_subscription(Subscription::new(|| {}))
 8302                .context(focus_handle)
 8303                .when(run_to_cursor, |this| {
 8304                    let weak_editor = weak_editor.clone();
 8305                    this.entry("Run to cursor", None, move |window, cx| {
 8306                        weak_editor
 8307                            .update(cx, |editor, cx| {
 8308                                editor.change_selections(
 8309                                    SelectionEffects::no_scroll(),
 8310                                    window,
 8311                                    cx,
 8312                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8313                                );
 8314                            })
 8315                            .ok();
 8316
 8317                        window.dispatch_action(Box::new(RunToCursor), cx);
 8318                    })
 8319                    .separator()
 8320                })
 8321                .when_some(toggle_state_msg, |this, msg| {
 8322                    this.entry(msg, None, {
 8323                        let weak_editor = weak_editor.clone();
 8324                        let breakpoint = breakpoint.clone();
 8325                        move |_window, cx| {
 8326                            weak_editor
 8327                                .update(cx, |this, cx| {
 8328                                    this.edit_breakpoint_at_anchor(
 8329                                        anchor,
 8330                                        breakpoint.as_ref().clone(),
 8331                                        BreakpointEditAction::InvertState,
 8332                                        cx,
 8333                                    );
 8334                                })
 8335                                .log_err();
 8336                        }
 8337                    })
 8338                })
 8339                .entry(set_breakpoint_msg, None, {
 8340                    let weak_editor = weak_editor.clone();
 8341                    let breakpoint = breakpoint.clone();
 8342                    move |_window, cx| {
 8343                        weak_editor
 8344                            .update(cx, |this, cx| {
 8345                                this.edit_breakpoint_at_anchor(
 8346                                    anchor,
 8347                                    breakpoint.as_ref().clone(),
 8348                                    BreakpointEditAction::Toggle,
 8349                                    cx,
 8350                                );
 8351                            })
 8352                            .log_err();
 8353                    }
 8354                })
 8355                .entry(log_breakpoint_msg, None, {
 8356                    let breakpoint = breakpoint.clone();
 8357                    let weak_editor = weak_editor.clone();
 8358                    move |window, cx| {
 8359                        weak_editor
 8360                            .update(cx, |this, cx| {
 8361                                this.add_edit_breakpoint_block(
 8362                                    anchor,
 8363                                    breakpoint.as_ref(),
 8364                                    BreakpointPromptEditAction::Log,
 8365                                    window,
 8366                                    cx,
 8367                                );
 8368                            })
 8369                            .log_err();
 8370                    }
 8371                })
 8372                .entry(condition_breakpoint_msg, None, {
 8373                    let breakpoint = breakpoint.clone();
 8374                    let weak_editor = weak_editor.clone();
 8375                    move |window, cx| {
 8376                        weak_editor
 8377                            .update(cx, |this, cx| {
 8378                                this.add_edit_breakpoint_block(
 8379                                    anchor,
 8380                                    breakpoint.as_ref(),
 8381                                    BreakpointPromptEditAction::Condition,
 8382                                    window,
 8383                                    cx,
 8384                                );
 8385                            })
 8386                            .log_err();
 8387                    }
 8388                })
 8389                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8390                    weak_editor
 8391                        .update(cx, |this, cx| {
 8392                            this.add_edit_breakpoint_block(
 8393                                anchor,
 8394                                breakpoint.as_ref(),
 8395                                BreakpointPromptEditAction::HitCondition,
 8396                                window,
 8397                                cx,
 8398                            );
 8399                        })
 8400                        .log_err();
 8401                })
 8402        })
 8403    }
 8404
 8405    fn render_breakpoint(
 8406        &self,
 8407        position: Anchor,
 8408        row: DisplayRow,
 8409        breakpoint: &Breakpoint,
 8410        state: Option<BreakpointSessionState>,
 8411        cx: &mut Context<Self>,
 8412    ) -> IconButton {
 8413        let is_rejected = state.is_some_and(|s| !s.verified);
 8414        // Is it a breakpoint that shows up when hovering over gutter?
 8415        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8416            (false, false),
 8417            |PhantomBreakpointIndicator {
 8418                 is_active,
 8419                 display_row,
 8420                 collides_with_existing_breakpoint,
 8421             }| {
 8422                (
 8423                    is_active && display_row == row,
 8424                    collides_with_existing_breakpoint,
 8425                )
 8426            },
 8427        );
 8428
 8429        let (color, icon) = {
 8430            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8431                (false, false) => ui::IconName::DebugBreakpoint,
 8432                (true, false) => ui::IconName::DebugLogBreakpoint,
 8433                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8434                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8435            };
 8436
 8437            let color = cx.theme().colors();
 8438
 8439            let color = if is_phantom {
 8440                if collides_with_existing {
 8441                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8442                } else {
 8443                    Color::Hint
 8444                }
 8445            } else if is_rejected {
 8446                Color::Disabled
 8447            } else {
 8448                Color::Debugger
 8449            };
 8450
 8451            (color, icon)
 8452        };
 8453
 8454        let breakpoint = Arc::from(breakpoint.clone());
 8455
 8456        let alt_as_text = gpui::Keystroke {
 8457            modifiers: Modifiers::secondary_key(),
 8458            ..Default::default()
 8459        };
 8460        let primary_action_text = if breakpoint.is_disabled() {
 8461            "Enable breakpoint"
 8462        } else if is_phantom && !collides_with_existing {
 8463            "Set breakpoint"
 8464        } else {
 8465            "Unset breakpoint"
 8466        };
 8467        let focus_handle = self.focus_handle.clone();
 8468
 8469        let meta = if is_rejected {
 8470            SharedString::from("No executable code is associated with this line.")
 8471        } else if collides_with_existing && !breakpoint.is_disabled() {
 8472            SharedString::from(format!(
 8473                "{alt_as_text}-click to disable,\nright-click for more options."
 8474            ))
 8475        } else {
 8476            SharedString::from("Right-click for more options.")
 8477        };
 8478        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8479            .icon_size(IconSize::XSmall)
 8480            .size(ui::ButtonSize::None)
 8481            .when(is_rejected, |this| {
 8482                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8483            })
 8484            .icon_color(color)
 8485            .style(ButtonStyle::Transparent)
 8486            .on_click(cx.listener({
 8487                move |editor, event: &ClickEvent, window, cx| {
 8488                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8489                        BreakpointEditAction::InvertState
 8490                    } else {
 8491                        BreakpointEditAction::Toggle
 8492                    };
 8493
 8494                    window.focus(&editor.focus_handle(cx));
 8495                    editor.edit_breakpoint_at_anchor(
 8496                        position,
 8497                        breakpoint.as_ref().clone(),
 8498                        edit_action,
 8499                        cx,
 8500                    );
 8501                }
 8502            }))
 8503            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8504                editor.set_breakpoint_context_menu(
 8505                    row,
 8506                    Some(position),
 8507                    event.position(),
 8508                    window,
 8509                    cx,
 8510                );
 8511            }))
 8512            .tooltip(move |_window, cx| {
 8513                Tooltip::with_meta_in(
 8514                    primary_action_text,
 8515                    Some(&ToggleBreakpoint),
 8516                    meta.clone(),
 8517                    &focus_handle,
 8518                    cx,
 8519                )
 8520            })
 8521    }
 8522
 8523    fn build_tasks_context(
 8524        project: &Entity<Project>,
 8525        buffer: &Entity<Buffer>,
 8526        buffer_row: u32,
 8527        tasks: &Arc<RunnableTasks>,
 8528        cx: &mut Context<Self>,
 8529    ) -> Task<Option<task::TaskContext>> {
 8530        let position = Point::new(buffer_row, tasks.column);
 8531        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8532        let location = Location {
 8533            buffer: buffer.clone(),
 8534            range: range_start..range_start,
 8535        };
 8536        // Fill in the environmental variables from the tree-sitter captures
 8537        let mut captured_task_variables = TaskVariables::default();
 8538        for (capture_name, value) in tasks.extra_variables.clone() {
 8539            captured_task_variables.insert(
 8540                task::VariableName::Custom(capture_name.into()),
 8541                value.clone(),
 8542            );
 8543        }
 8544        project.update(cx, |project, cx| {
 8545            project.task_store().update(cx, |task_store, cx| {
 8546                task_store.task_context_for_location(captured_task_variables, location, cx)
 8547            })
 8548        })
 8549    }
 8550
 8551    pub fn spawn_nearest_task(
 8552        &mut self,
 8553        action: &SpawnNearestTask,
 8554        window: &mut Window,
 8555        cx: &mut Context<Self>,
 8556    ) {
 8557        let Some((workspace, _)) = self.workspace.clone() else {
 8558            return;
 8559        };
 8560        let Some(project) = self.project.clone() else {
 8561            return;
 8562        };
 8563
 8564        // Try to find a closest, enclosing node using tree-sitter that has a task
 8565        let Some((buffer, buffer_row, tasks)) = self
 8566            .find_enclosing_node_task(cx)
 8567            // Or find the task that's closest in row-distance.
 8568            .or_else(|| self.find_closest_task(cx))
 8569        else {
 8570            return;
 8571        };
 8572
 8573        let reveal_strategy = action.reveal;
 8574        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8575        cx.spawn_in(window, async move |_, cx| {
 8576            let context = task_context.await?;
 8577            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8578
 8579            let resolved = &mut resolved_task.resolved;
 8580            resolved.reveal = reveal_strategy;
 8581
 8582            workspace
 8583                .update_in(cx, |workspace, window, cx| {
 8584                    workspace.schedule_resolved_task(
 8585                        task_source_kind,
 8586                        resolved_task,
 8587                        false,
 8588                        window,
 8589                        cx,
 8590                    );
 8591                })
 8592                .ok()
 8593        })
 8594        .detach();
 8595    }
 8596
 8597    fn find_closest_task(
 8598        &mut self,
 8599        cx: &mut Context<Self>,
 8600    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8601        let cursor_row = self
 8602            .selections
 8603            .newest_adjusted(&self.display_snapshot(cx))
 8604            .head()
 8605            .row;
 8606
 8607        let ((buffer_id, row), tasks) = self
 8608            .tasks
 8609            .iter()
 8610            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8611
 8612        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8613        let tasks = Arc::new(tasks.to_owned());
 8614        Some((buffer, *row, tasks))
 8615    }
 8616
 8617    fn find_enclosing_node_task(
 8618        &mut self,
 8619        cx: &mut Context<Self>,
 8620    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8621        let snapshot = self.buffer.read(cx).snapshot(cx);
 8622        let offset = self
 8623            .selections
 8624            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8625            .head();
 8626        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8627        let offset = excerpt.map_offset_to_buffer(offset);
 8628        let buffer_id = excerpt.buffer().remote_id();
 8629
 8630        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8631        let mut cursor = layer.node().walk();
 8632
 8633        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8634            if cursor.node().end_byte() == offset.0 {
 8635                cursor.goto_next_sibling();
 8636            }
 8637        }
 8638
 8639        // Ascend to the smallest ancestor that contains the range and has a task.
 8640        loop {
 8641            let node = cursor.node();
 8642            let node_range = node.byte_range();
 8643            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8644
 8645            // Check if this node contains our offset
 8646            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8647                // If it contains offset, check for task
 8648                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8649                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8650                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8651                }
 8652            }
 8653
 8654            if !cursor.goto_parent() {
 8655                break;
 8656            }
 8657        }
 8658        None
 8659    }
 8660
 8661    fn render_run_indicator(
 8662        &self,
 8663        _style: &EditorStyle,
 8664        is_active: bool,
 8665        row: DisplayRow,
 8666        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8667        cx: &mut Context<Self>,
 8668    ) -> IconButton {
 8669        let color = Color::Muted;
 8670        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8671
 8672        IconButton::new(
 8673            ("run_indicator", row.0 as usize),
 8674            ui::IconName::PlayOutlined,
 8675        )
 8676        .shape(ui::IconButtonShape::Square)
 8677        .icon_size(IconSize::XSmall)
 8678        .icon_color(color)
 8679        .toggle_state(is_active)
 8680        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8681            let quick_launch = match e {
 8682                ClickEvent::Keyboard(_) => true,
 8683                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8684            };
 8685
 8686            window.focus(&editor.focus_handle(cx));
 8687            editor.toggle_code_actions(
 8688                &ToggleCodeActions {
 8689                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8690                    quick_launch,
 8691                },
 8692                window,
 8693                cx,
 8694            );
 8695        }))
 8696        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8697            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8698        }))
 8699    }
 8700
 8701    pub fn context_menu_visible(&self) -> bool {
 8702        !self.edit_prediction_preview_is_active()
 8703            && self
 8704                .context_menu
 8705                .borrow()
 8706                .as_ref()
 8707                .is_some_and(|menu| menu.visible())
 8708    }
 8709
 8710    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8711        self.context_menu
 8712            .borrow()
 8713            .as_ref()
 8714            .map(|menu| menu.origin())
 8715    }
 8716
 8717    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8718        self.context_menu_options = Some(options);
 8719    }
 8720
 8721    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8722    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8723
 8724    fn render_edit_prediction_popover(
 8725        &mut self,
 8726        text_bounds: &Bounds<Pixels>,
 8727        content_origin: gpui::Point<Pixels>,
 8728        right_margin: Pixels,
 8729        editor_snapshot: &EditorSnapshot,
 8730        visible_row_range: Range<DisplayRow>,
 8731        scroll_top: ScrollOffset,
 8732        scroll_bottom: ScrollOffset,
 8733        line_layouts: &[LineWithInvisibles],
 8734        line_height: Pixels,
 8735        scroll_position: gpui::Point<ScrollOffset>,
 8736        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8737        newest_selection_head: Option<DisplayPoint>,
 8738        editor_width: Pixels,
 8739        style: &EditorStyle,
 8740        window: &mut Window,
 8741        cx: &mut App,
 8742    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8743        if self.mode().is_minimap() {
 8744            return None;
 8745        }
 8746        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8747
 8748        if self.edit_prediction_visible_in_cursor_popover(true) {
 8749            return None;
 8750        }
 8751
 8752        match &active_edit_prediction.completion {
 8753            EditPrediction::MoveWithin { target, .. } => {
 8754                let target_display_point = target.to_display_point(editor_snapshot);
 8755
 8756                if self.edit_prediction_requires_modifier() {
 8757                    if !self.edit_prediction_preview_is_active() {
 8758                        return None;
 8759                    }
 8760
 8761                    self.render_edit_prediction_modifier_jump_popover(
 8762                        text_bounds,
 8763                        content_origin,
 8764                        visible_row_range,
 8765                        line_layouts,
 8766                        line_height,
 8767                        scroll_pixel_position,
 8768                        newest_selection_head,
 8769                        target_display_point,
 8770                        window,
 8771                        cx,
 8772                    )
 8773                } else {
 8774                    self.render_edit_prediction_eager_jump_popover(
 8775                        text_bounds,
 8776                        content_origin,
 8777                        editor_snapshot,
 8778                        visible_row_range,
 8779                        scroll_top,
 8780                        scroll_bottom,
 8781                        line_height,
 8782                        scroll_pixel_position,
 8783                        target_display_point,
 8784                        editor_width,
 8785                        window,
 8786                        cx,
 8787                    )
 8788                }
 8789            }
 8790            EditPrediction::Edit {
 8791                display_mode: EditDisplayMode::Inline,
 8792                ..
 8793            } => None,
 8794            EditPrediction::Edit {
 8795                display_mode: EditDisplayMode::TabAccept,
 8796                edits,
 8797                ..
 8798            } => {
 8799                let range = &edits.first()?.0;
 8800                let target_display_point = range.end.to_display_point(editor_snapshot);
 8801
 8802                self.render_edit_prediction_end_of_line_popover(
 8803                    "Accept",
 8804                    editor_snapshot,
 8805                    visible_row_range,
 8806                    target_display_point,
 8807                    line_height,
 8808                    scroll_pixel_position,
 8809                    content_origin,
 8810                    editor_width,
 8811                    window,
 8812                    cx,
 8813                )
 8814            }
 8815            EditPrediction::Edit {
 8816                edits,
 8817                edit_preview,
 8818                display_mode: EditDisplayMode::DiffPopover,
 8819                snapshot,
 8820            } => self.render_edit_prediction_diff_popover(
 8821                text_bounds,
 8822                content_origin,
 8823                right_margin,
 8824                editor_snapshot,
 8825                visible_row_range,
 8826                line_layouts,
 8827                line_height,
 8828                scroll_position,
 8829                scroll_pixel_position,
 8830                newest_selection_head,
 8831                editor_width,
 8832                style,
 8833                edits,
 8834                edit_preview,
 8835                snapshot,
 8836                window,
 8837                cx,
 8838            ),
 8839            EditPrediction::MoveOutside { snapshot, .. } => {
 8840                let mut element = self
 8841                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8842                    .into_any();
 8843
 8844                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8845                let origin_x = text_bounds.size.width - size.width - px(30.);
 8846                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8847                element.prepaint_at(origin, window, cx);
 8848
 8849                Some((element, origin))
 8850            }
 8851        }
 8852    }
 8853
 8854    fn render_edit_prediction_modifier_jump_popover(
 8855        &mut self,
 8856        text_bounds: &Bounds<Pixels>,
 8857        content_origin: gpui::Point<Pixels>,
 8858        visible_row_range: Range<DisplayRow>,
 8859        line_layouts: &[LineWithInvisibles],
 8860        line_height: Pixels,
 8861        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8862        newest_selection_head: Option<DisplayPoint>,
 8863        target_display_point: DisplayPoint,
 8864        window: &mut Window,
 8865        cx: &mut App,
 8866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8867        let scrolled_content_origin =
 8868            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8869
 8870        const SCROLL_PADDING_Y: Pixels = px(12.);
 8871
 8872        if target_display_point.row() < visible_row_range.start {
 8873            return self.render_edit_prediction_scroll_popover(
 8874                |_| SCROLL_PADDING_Y,
 8875                IconName::ArrowUp,
 8876                visible_row_range,
 8877                line_layouts,
 8878                newest_selection_head,
 8879                scrolled_content_origin,
 8880                window,
 8881                cx,
 8882            );
 8883        } else if target_display_point.row() >= visible_row_range.end {
 8884            return self.render_edit_prediction_scroll_popover(
 8885                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8886                IconName::ArrowDown,
 8887                visible_row_range,
 8888                line_layouts,
 8889                newest_selection_head,
 8890                scrolled_content_origin,
 8891                window,
 8892                cx,
 8893            );
 8894        }
 8895
 8896        const POLE_WIDTH: Pixels = px(2.);
 8897
 8898        let line_layout =
 8899            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8900        let target_column = target_display_point.column() as usize;
 8901
 8902        let target_x = line_layout.x_for_index(target_column);
 8903        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8904            - scroll_pixel_position.y;
 8905
 8906        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8907
 8908        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8909        border_color.l += 0.001;
 8910
 8911        let mut element = v_flex()
 8912            .items_end()
 8913            .when(flag_on_right, |el| el.items_start())
 8914            .child(if flag_on_right {
 8915                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8916                    .rounded_bl(px(0.))
 8917                    .rounded_tl(px(0.))
 8918                    .border_l_2()
 8919                    .border_color(border_color)
 8920            } else {
 8921                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8922                    .rounded_br(px(0.))
 8923                    .rounded_tr(px(0.))
 8924                    .border_r_2()
 8925                    .border_color(border_color)
 8926            })
 8927            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8928            .into_any();
 8929
 8930        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8931
 8932        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8933            - point(
 8934                if flag_on_right {
 8935                    POLE_WIDTH
 8936                } else {
 8937                    size.width - POLE_WIDTH
 8938                },
 8939                size.height - line_height,
 8940            );
 8941
 8942        origin.x = origin.x.max(content_origin.x);
 8943
 8944        element.prepaint_at(origin, window, cx);
 8945
 8946        Some((element, origin))
 8947    }
 8948
 8949    fn render_edit_prediction_scroll_popover(
 8950        &mut self,
 8951        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8952        scroll_icon: IconName,
 8953        visible_row_range: Range<DisplayRow>,
 8954        line_layouts: &[LineWithInvisibles],
 8955        newest_selection_head: Option<DisplayPoint>,
 8956        scrolled_content_origin: gpui::Point<Pixels>,
 8957        window: &mut Window,
 8958        cx: &mut App,
 8959    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8960        let mut element = self
 8961            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8962            .into_any();
 8963
 8964        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8965
 8966        let cursor = newest_selection_head?;
 8967        let cursor_row_layout =
 8968            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8969        let cursor_column = cursor.column() as usize;
 8970
 8971        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8972
 8973        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8974
 8975        element.prepaint_at(origin, window, cx);
 8976        Some((element, origin))
 8977    }
 8978
 8979    fn render_edit_prediction_eager_jump_popover(
 8980        &mut self,
 8981        text_bounds: &Bounds<Pixels>,
 8982        content_origin: gpui::Point<Pixels>,
 8983        editor_snapshot: &EditorSnapshot,
 8984        visible_row_range: Range<DisplayRow>,
 8985        scroll_top: ScrollOffset,
 8986        scroll_bottom: ScrollOffset,
 8987        line_height: Pixels,
 8988        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8989        target_display_point: DisplayPoint,
 8990        editor_width: Pixels,
 8991        window: &mut Window,
 8992        cx: &mut App,
 8993    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8994        if target_display_point.row().as_f64() < scroll_top {
 8995            let mut element = self
 8996                .render_edit_prediction_line_popover(
 8997                    "Jump to Edit",
 8998                    Some(IconName::ArrowUp),
 8999                    window,
 9000                    cx,
 9001                )
 9002                .into_any();
 9003
 9004            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9005            let offset = point(
 9006                (text_bounds.size.width - size.width) / 2.,
 9007                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9008            );
 9009
 9010            let origin = text_bounds.origin + offset;
 9011            element.prepaint_at(origin, window, cx);
 9012            Some((element, origin))
 9013        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9014            let mut element = self
 9015                .render_edit_prediction_line_popover(
 9016                    "Jump to Edit",
 9017                    Some(IconName::ArrowDown),
 9018                    window,
 9019                    cx,
 9020                )
 9021                .into_any();
 9022
 9023            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9024            let offset = point(
 9025                (text_bounds.size.width - size.width) / 2.,
 9026                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9027            );
 9028
 9029            let origin = text_bounds.origin + offset;
 9030            element.prepaint_at(origin, window, cx);
 9031            Some((element, origin))
 9032        } else {
 9033            self.render_edit_prediction_end_of_line_popover(
 9034                "Jump to Edit",
 9035                editor_snapshot,
 9036                visible_row_range,
 9037                target_display_point,
 9038                line_height,
 9039                scroll_pixel_position,
 9040                content_origin,
 9041                editor_width,
 9042                window,
 9043                cx,
 9044            )
 9045        }
 9046    }
 9047
 9048    fn render_edit_prediction_end_of_line_popover(
 9049        self: &mut Editor,
 9050        label: &'static str,
 9051        editor_snapshot: &EditorSnapshot,
 9052        visible_row_range: Range<DisplayRow>,
 9053        target_display_point: DisplayPoint,
 9054        line_height: Pixels,
 9055        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9056        content_origin: gpui::Point<Pixels>,
 9057        editor_width: Pixels,
 9058        window: &mut Window,
 9059        cx: &mut App,
 9060    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9061        let target_line_end = DisplayPoint::new(
 9062            target_display_point.row(),
 9063            editor_snapshot.line_len(target_display_point.row()),
 9064        );
 9065
 9066        let mut element = self
 9067            .render_edit_prediction_line_popover(label, None, window, cx)
 9068            .into_any();
 9069
 9070        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9071
 9072        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9073
 9074        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9075        let mut origin = start_point
 9076            + line_origin
 9077            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9078        origin.x = origin.x.max(content_origin.x);
 9079
 9080        let max_x = content_origin.x + editor_width - size.width;
 9081
 9082        if origin.x > max_x {
 9083            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9084
 9085            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9086                origin.y += offset;
 9087                IconName::ArrowUp
 9088            } else {
 9089                origin.y -= offset;
 9090                IconName::ArrowDown
 9091            };
 9092
 9093            element = self
 9094                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9095                .into_any();
 9096
 9097            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9098
 9099            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9100        }
 9101
 9102        element.prepaint_at(origin, window, cx);
 9103        Some((element, origin))
 9104    }
 9105
 9106    fn render_edit_prediction_diff_popover(
 9107        self: &Editor,
 9108        text_bounds: &Bounds<Pixels>,
 9109        content_origin: gpui::Point<Pixels>,
 9110        right_margin: Pixels,
 9111        editor_snapshot: &EditorSnapshot,
 9112        visible_row_range: Range<DisplayRow>,
 9113        line_layouts: &[LineWithInvisibles],
 9114        line_height: Pixels,
 9115        scroll_position: gpui::Point<ScrollOffset>,
 9116        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9117        newest_selection_head: Option<DisplayPoint>,
 9118        editor_width: Pixels,
 9119        style: &EditorStyle,
 9120        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9121        edit_preview: &Option<language::EditPreview>,
 9122        snapshot: &language::BufferSnapshot,
 9123        window: &mut Window,
 9124        cx: &mut App,
 9125    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9126        let edit_start = edits
 9127            .first()
 9128            .unwrap()
 9129            .0
 9130            .start
 9131            .to_display_point(editor_snapshot);
 9132        let edit_end = edits
 9133            .last()
 9134            .unwrap()
 9135            .0
 9136            .end
 9137            .to_display_point(editor_snapshot);
 9138
 9139        let is_visible = visible_row_range.contains(&edit_start.row())
 9140            || visible_row_range.contains(&edit_end.row());
 9141        if !is_visible {
 9142            return None;
 9143        }
 9144
 9145        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9146            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9147        } else {
 9148            // Fallback for providers without edit_preview
 9149            crate::edit_prediction_fallback_text(edits, cx)
 9150        };
 9151
 9152        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9153        let line_count = highlighted_edits.text.lines().count();
 9154
 9155        const BORDER_WIDTH: Pixels = px(1.);
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        let mut element = h_flex()
 9161            .items_start()
 9162            .child(
 9163                h_flex()
 9164                    .bg(cx.theme().colors().editor_background)
 9165                    .border(BORDER_WIDTH)
 9166                    .shadow_xs()
 9167                    .border_color(cx.theme().colors().border)
 9168                    .rounded_l_lg()
 9169                    .when(line_count > 1, |el| el.rounded_br_lg())
 9170                    .pr_1()
 9171                    .child(styled_text),
 9172            )
 9173            .child(
 9174                h_flex()
 9175                    .h(line_height + BORDER_WIDTH * 2.)
 9176                    .px_1p5()
 9177                    .gap_1()
 9178                    // Workaround: For some reason, there's a gap if we don't do this
 9179                    .ml(-BORDER_WIDTH)
 9180                    .shadow(vec![gpui::BoxShadow {
 9181                        color: gpui::black().opacity(0.05),
 9182                        offset: point(px(1.), px(1.)),
 9183                        blur_radius: px(2.),
 9184                        spread_radius: px(0.),
 9185                    }])
 9186                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9187                    .border(BORDER_WIDTH)
 9188                    .border_color(cx.theme().colors().border)
 9189                    .rounded_r_lg()
 9190                    .id("edit_prediction_diff_popover_keybind")
 9191                    .when(!has_keybind, |el| {
 9192                        let status_colors = cx.theme().status();
 9193
 9194                        el.bg(status_colors.error_background)
 9195                            .border_color(status_colors.error.opacity(0.6))
 9196                            .child(Icon::new(IconName::Info).color(Color::Error))
 9197                            .cursor_default()
 9198                            .hoverable_tooltip(move |_window, cx| {
 9199                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9200                            })
 9201                    })
 9202                    .children(keybind),
 9203            )
 9204            .into_any();
 9205
 9206        let longest_row =
 9207            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9208        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9209            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9210        } else {
 9211            layout_line(
 9212                longest_row,
 9213                editor_snapshot,
 9214                style,
 9215                editor_width,
 9216                |_| false,
 9217                window,
 9218                cx,
 9219            )
 9220            .width
 9221        };
 9222
 9223        let viewport_bounds =
 9224            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9225                right: -right_margin,
 9226                ..Default::default()
 9227            });
 9228
 9229        let x_after_longest = Pixels::from(
 9230            ScrollPixelOffset::from(
 9231                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9232            ) - scroll_pixel_position.x,
 9233        );
 9234
 9235        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9236
 9237        // Fully visible if it can be displayed within the window (allow overlapping other
 9238        // panes). However, this is only allowed if the popover starts within text_bounds.
 9239        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9240            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9241
 9242        let mut origin = if can_position_to_the_right {
 9243            point(
 9244                x_after_longest,
 9245                text_bounds.origin.y
 9246                    + Pixels::from(
 9247                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9248                            - scroll_pixel_position.y,
 9249                    ),
 9250            )
 9251        } else {
 9252            let cursor_row = newest_selection_head.map(|head| head.row());
 9253            let above_edit = edit_start
 9254                .row()
 9255                .0
 9256                .checked_sub(line_count as u32)
 9257                .map(DisplayRow);
 9258            let below_edit = Some(edit_end.row() + 1);
 9259            let above_cursor =
 9260                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9261            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9262
 9263            // Place the edit popover adjacent to the edit if there is a location
 9264            // available that is onscreen and does not obscure the cursor. Otherwise,
 9265            // place it adjacent to the cursor.
 9266            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9267                .into_iter()
 9268                .flatten()
 9269                .find(|&start_row| {
 9270                    let end_row = start_row + line_count as u32;
 9271                    visible_row_range.contains(&start_row)
 9272                        && visible_row_range.contains(&end_row)
 9273                        && cursor_row
 9274                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9275                })?;
 9276
 9277            content_origin
 9278                + point(
 9279                    Pixels::from(-scroll_pixel_position.x),
 9280                    Pixels::from(
 9281                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9282                    ),
 9283                )
 9284        };
 9285
 9286        origin.x -= BORDER_WIDTH;
 9287
 9288        window.defer_draw(element, origin, 1);
 9289
 9290        // Do not return an element, since it will already be drawn due to defer_draw.
 9291        None
 9292    }
 9293
 9294    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9295        px(30.)
 9296    }
 9297
 9298    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9299        if self.read_only(cx) {
 9300            cx.theme().players().read_only()
 9301        } else {
 9302            self.style.as_ref().unwrap().local_player
 9303        }
 9304    }
 9305
 9306    fn render_edit_prediction_accept_keybind(
 9307        &self,
 9308        window: &mut Window,
 9309        cx: &mut App,
 9310    ) -> Option<AnyElement> {
 9311        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9312        let accept_keystroke = accept_binding.keystroke()?;
 9313
 9314        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9315
 9316        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9317            Color::Accent
 9318        } else {
 9319            Color::Muted
 9320        };
 9321
 9322        h_flex()
 9323            .px_0p5()
 9324            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9325            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9326            .text_size(TextSize::XSmall.rems(cx))
 9327            .child(h_flex().children(ui::render_modifiers(
 9328                accept_keystroke.modifiers(),
 9329                PlatformStyle::platform(),
 9330                Some(modifiers_color),
 9331                Some(IconSize::XSmall.rems().into()),
 9332                true,
 9333            )))
 9334            .when(is_platform_style_mac, |parent| {
 9335                parent.child(accept_keystroke.key().to_string())
 9336            })
 9337            .when(!is_platform_style_mac, |parent| {
 9338                parent.child(
 9339                    Key::new(
 9340                        util::capitalize(accept_keystroke.key()),
 9341                        Some(Color::Default),
 9342                    )
 9343                    .size(Some(IconSize::XSmall.rems().into())),
 9344                )
 9345            })
 9346            .into_any()
 9347            .into()
 9348    }
 9349
 9350    fn render_edit_prediction_line_popover(
 9351        &self,
 9352        label: impl Into<SharedString>,
 9353        icon: Option<IconName>,
 9354        window: &mut Window,
 9355        cx: &mut App,
 9356    ) -> Stateful<Div> {
 9357        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9358
 9359        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9360        let has_keybind = keybind.is_some();
 9361
 9362        h_flex()
 9363            .id("ep-line-popover")
 9364            .py_0p5()
 9365            .pl_1()
 9366            .pr(padding_right)
 9367            .gap_1()
 9368            .rounded_md()
 9369            .border_1()
 9370            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9371            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9372            .shadow_xs()
 9373            .when(!has_keybind, |el| {
 9374                let status_colors = cx.theme().status();
 9375
 9376                el.bg(status_colors.error_background)
 9377                    .border_color(status_colors.error.opacity(0.6))
 9378                    .pl_2()
 9379                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9380                    .cursor_default()
 9381                    .hoverable_tooltip(move |_window, cx| {
 9382                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9383                    })
 9384            })
 9385            .children(keybind)
 9386            .child(
 9387                Label::new(label)
 9388                    .size(LabelSize::Small)
 9389                    .when(!has_keybind, |el| {
 9390                        el.color(cx.theme().status().error.into()).strikethrough()
 9391                    }),
 9392            )
 9393            .when(!has_keybind, |el| {
 9394                el.child(
 9395                    h_flex().ml_1().child(
 9396                        Icon::new(IconName::Info)
 9397                            .size(IconSize::Small)
 9398                            .color(cx.theme().status().error.into()),
 9399                    ),
 9400                )
 9401            })
 9402            .when_some(icon, |element, icon| {
 9403                element.child(
 9404                    div()
 9405                        .mt(px(1.5))
 9406                        .child(Icon::new(icon).size(IconSize::Small)),
 9407                )
 9408            })
 9409    }
 9410
 9411    fn render_edit_prediction_jump_outside_popover(
 9412        &self,
 9413        snapshot: &BufferSnapshot,
 9414        window: &mut Window,
 9415        cx: &mut App,
 9416    ) -> Stateful<Div> {
 9417        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9418        let has_keybind = keybind.is_some();
 9419
 9420        let file_name = snapshot
 9421            .file()
 9422            .map(|file| SharedString::new(file.file_name(cx)))
 9423            .unwrap_or(SharedString::new_static("untitled"));
 9424
 9425        h_flex()
 9426            .id("ep-jump-outside-popover")
 9427            .py_1()
 9428            .px_2()
 9429            .gap_1()
 9430            .rounded_md()
 9431            .border_1()
 9432            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9433            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9434            .shadow_xs()
 9435            .when(!has_keybind, |el| {
 9436                let status_colors = cx.theme().status();
 9437
 9438                el.bg(status_colors.error_background)
 9439                    .border_color(status_colors.error.opacity(0.6))
 9440                    .pl_2()
 9441                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9442                    .cursor_default()
 9443                    .hoverable_tooltip(move |_window, cx| {
 9444                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9445                    })
 9446            })
 9447            .children(keybind)
 9448            .child(
 9449                Label::new(file_name)
 9450                    .size(LabelSize::Small)
 9451                    .buffer_font(cx)
 9452                    .when(!has_keybind, |el| {
 9453                        el.color(cx.theme().status().error.into()).strikethrough()
 9454                    }),
 9455            )
 9456            .when(!has_keybind, |el| {
 9457                el.child(
 9458                    h_flex().ml_1().child(
 9459                        Icon::new(IconName::Info)
 9460                            .size(IconSize::Small)
 9461                            .color(cx.theme().status().error.into()),
 9462                    ),
 9463                )
 9464            })
 9465            .child(
 9466                div()
 9467                    .mt(px(1.5))
 9468                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9469            )
 9470    }
 9471
 9472    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9473        let accent_color = cx.theme().colors().text_accent;
 9474        let editor_bg_color = cx.theme().colors().editor_background;
 9475        editor_bg_color.blend(accent_color.opacity(0.1))
 9476    }
 9477
 9478    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9479        let accent_color = cx.theme().colors().text_accent;
 9480        let editor_bg_color = cx.theme().colors().editor_background;
 9481        editor_bg_color.blend(accent_color.opacity(0.6))
 9482    }
 9483    fn get_prediction_provider_icon_name(
 9484        provider: &Option<RegisteredEditPredictionProvider>,
 9485    ) -> IconName {
 9486        match provider {
 9487            Some(provider) => match provider.provider.name() {
 9488                "copilot" => IconName::Copilot,
 9489                "supermaven" => IconName::Supermaven,
 9490                _ => IconName::ZedPredict,
 9491            },
 9492            None => IconName::ZedPredict,
 9493        }
 9494    }
 9495
 9496    fn render_edit_prediction_cursor_popover(
 9497        &self,
 9498        min_width: Pixels,
 9499        max_width: Pixels,
 9500        cursor_point: Point,
 9501        style: &EditorStyle,
 9502        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9503        _window: &Window,
 9504        cx: &mut Context<Editor>,
 9505    ) -> Option<AnyElement> {
 9506        let provider = self.edit_prediction_provider.as_ref()?;
 9507        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9508
 9509        let is_refreshing = provider.provider.is_refreshing(cx);
 9510
 9511        fn pending_completion_container(icon: IconName) -> Div {
 9512            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9513        }
 9514
 9515        let completion = match &self.active_edit_prediction {
 9516            Some(prediction) => {
 9517                if !self.has_visible_completions_menu() {
 9518                    const RADIUS: Pixels = px(6.);
 9519                    const BORDER_WIDTH: Pixels = px(1.);
 9520
 9521                    return Some(
 9522                        h_flex()
 9523                            .elevation_2(cx)
 9524                            .border(BORDER_WIDTH)
 9525                            .border_color(cx.theme().colors().border)
 9526                            .when(accept_keystroke.is_none(), |el| {
 9527                                el.border_color(cx.theme().status().error)
 9528                            })
 9529                            .rounded(RADIUS)
 9530                            .rounded_tl(px(0.))
 9531                            .overflow_hidden()
 9532                            .child(div().px_1p5().child(match &prediction.completion {
 9533                                EditPrediction::MoveWithin { target, snapshot } => {
 9534                                    use text::ToPoint as _;
 9535                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9536                                    {
 9537                                        Icon::new(IconName::ZedPredictDown)
 9538                                    } else {
 9539                                        Icon::new(IconName::ZedPredictUp)
 9540                                    }
 9541                                }
 9542                                EditPrediction::MoveOutside { .. } => {
 9543                                    // TODO [zeta2] custom icon for external jump?
 9544                                    Icon::new(provider_icon)
 9545                                }
 9546                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9547                            }))
 9548                            .child(
 9549                                h_flex()
 9550                                    .gap_1()
 9551                                    .py_1()
 9552                                    .px_2()
 9553                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9554                                    .border_l_1()
 9555                                    .border_color(cx.theme().colors().border)
 9556                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9557                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9558                                        el.child(
 9559                                            Label::new("Hold")
 9560                                                .size(LabelSize::Small)
 9561                                                .when(accept_keystroke.is_none(), |el| {
 9562                                                    el.strikethrough()
 9563                                                })
 9564                                                .line_height_style(LineHeightStyle::UiLabel),
 9565                                        )
 9566                                    })
 9567                                    .id("edit_prediction_cursor_popover_keybind")
 9568                                    .when(accept_keystroke.is_none(), |el| {
 9569                                        let status_colors = cx.theme().status();
 9570
 9571                                        el.bg(status_colors.error_background)
 9572                                            .border_color(status_colors.error.opacity(0.6))
 9573                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9574                                            .cursor_default()
 9575                                            .hoverable_tooltip(move |_window, cx| {
 9576                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9577                                                    .into()
 9578                                            })
 9579                                    })
 9580                                    .when_some(
 9581                                        accept_keystroke.as_ref(),
 9582                                        |el, accept_keystroke| {
 9583                                            el.child(h_flex().children(ui::render_modifiers(
 9584                                                accept_keystroke.modifiers(),
 9585                                                PlatformStyle::platform(),
 9586                                                Some(Color::Default),
 9587                                                Some(IconSize::XSmall.rems().into()),
 9588                                                false,
 9589                                            )))
 9590                                        },
 9591                                    ),
 9592                            )
 9593                            .into_any(),
 9594                    );
 9595                }
 9596
 9597                self.render_edit_prediction_cursor_popover_preview(
 9598                    prediction,
 9599                    cursor_point,
 9600                    style,
 9601                    cx,
 9602                )?
 9603            }
 9604
 9605            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9606                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9607                    stale_completion,
 9608                    cursor_point,
 9609                    style,
 9610                    cx,
 9611                )?,
 9612
 9613                None => pending_completion_container(provider_icon)
 9614                    .child(Label::new("...").size(LabelSize::Small)),
 9615            },
 9616
 9617            None => pending_completion_container(provider_icon)
 9618                .child(Label::new("...").size(LabelSize::Small)),
 9619        };
 9620
 9621        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9622            completion
 9623                .with_animation(
 9624                    "loading-completion",
 9625                    Animation::new(Duration::from_secs(2))
 9626                        .repeat()
 9627                        .with_easing(pulsating_between(0.4, 0.8)),
 9628                    |label, delta| label.opacity(delta),
 9629                )
 9630                .into_any_element()
 9631        } else {
 9632            completion.into_any_element()
 9633        };
 9634
 9635        let has_completion = self.active_edit_prediction.is_some();
 9636
 9637        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9638        Some(
 9639            h_flex()
 9640                .min_w(min_width)
 9641                .max_w(max_width)
 9642                .flex_1()
 9643                .elevation_2(cx)
 9644                .border_color(cx.theme().colors().border)
 9645                .child(
 9646                    div()
 9647                        .flex_1()
 9648                        .py_1()
 9649                        .px_2()
 9650                        .overflow_hidden()
 9651                        .child(completion),
 9652                )
 9653                .when_some(accept_keystroke, |el, accept_keystroke| {
 9654                    if !accept_keystroke.modifiers().modified() {
 9655                        return el;
 9656                    }
 9657
 9658                    el.child(
 9659                        h_flex()
 9660                            .h_full()
 9661                            .border_l_1()
 9662                            .rounded_r_lg()
 9663                            .border_color(cx.theme().colors().border)
 9664                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9665                            .gap_1()
 9666                            .py_1()
 9667                            .px_2()
 9668                            .child(
 9669                                h_flex()
 9670                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9671                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9672                                    .child(h_flex().children(ui::render_modifiers(
 9673                                        accept_keystroke.modifiers(),
 9674                                        PlatformStyle::platform(),
 9675                                        Some(if !has_completion {
 9676                                            Color::Muted
 9677                                        } else {
 9678                                            Color::Default
 9679                                        }),
 9680                                        None,
 9681                                        false,
 9682                                    ))),
 9683                            )
 9684                            .child(Label::new("Preview").into_any_element())
 9685                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9686                    )
 9687                })
 9688                .into_any(),
 9689        )
 9690    }
 9691
 9692    fn render_edit_prediction_cursor_popover_preview(
 9693        &self,
 9694        completion: &EditPredictionState,
 9695        cursor_point: Point,
 9696        style: &EditorStyle,
 9697        cx: &mut Context<Editor>,
 9698    ) -> Option<Div> {
 9699        use text::ToPoint as _;
 9700
 9701        fn render_relative_row_jump(
 9702            prefix: impl Into<String>,
 9703            current_row: u32,
 9704            target_row: u32,
 9705        ) -> Div {
 9706            let (row_diff, arrow) = if target_row < current_row {
 9707                (current_row - target_row, IconName::ArrowUp)
 9708            } else {
 9709                (target_row - current_row, IconName::ArrowDown)
 9710            };
 9711
 9712            h_flex()
 9713                .child(
 9714                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9715                        .color(Color::Muted)
 9716                        .size(LabelSize::Small),
 9717                )
 9718                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9719        }
 9720
 9721        let supports_jump = self
 9722            .edit_prediction_provider
 9723            .as_ref()
 9724            .map(|provider| provider.provider.supports_jump_to_edit())
 9725            .unwrap_or(true);
 9726
 9727        match &completion.completion {
 9728            EditPrediction::MoveWithin {
 9729                target, snapshot, ..
 9730            } => {
 9731                if !supports_jump {
 9732                    return None;
 9733                }
 9734
 9735                Some(
 9736                    h_flex()
 9737                        .px_2()
 9738                        .gap_2()
 9739                        .flex_1()
 9740                        .child(
 9741                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9742                                Icon::new(IconName::ZedPredictDown)
 9743                            } else {
 9744                                Icon::new(IconName::ZedPredictUp)
 9745                            },
 9746                        )
 9747                        .child(Label::new("Jump to Edit")),
 9748                )
 9749            }
 9750            EditPrediction::MoveOutside { snapshot, .. } => {
 9751                let file_name = snapshot
 9752                    .file()
 9753                    .map(|file| file.file_name(cx))
 9754                    .unwrap_or("untitled");
 9755                Some(
 9756                    h_flex()
 9757                        .px_2()
 9758                        .gap_2()
 9759                        .flex_1()
 9760                        .child(Icon::new(IconName::ZedPredict))
 9761                        .child(Label::new(format!("Jump to {file_name}"))),
 9762                )
 9763            }
 9764            EditPrediction::Edit {
 9765                edits,
 9766                edit_preview,
 9767                snapshot,
 9768                display_mode: _,
 9769            } => {
 9770                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9771
 9772                let (highlighted_edits, has_more_lines) =
 9773                    if let Some(edit_preview) = edit_preview.as_ref() {
 9774                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9775                            .first_line_preview()
 9776                    } else {
 9777                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9778                    };
 9779
 9780                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9781                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9782
 9783                let preview = h_flex()
 9784                    .gap_1()
 9785                    .min_w_16()
 9786                    .child(styled_text)
 9787                    .when(has_more_lines, |parent| parent.child(""));
 9788
 9789                let left = if supports_jump && first_edit_row != cursor_point.row {
 9790                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9791                        .into_any_element()
 9792                } else {
 9793                    let icon_name =
 9794                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9795                    Icon::new(icon_name).into_any_element()
 9796                };
 9797
 9798                Some(
 9799                    h_flex()
 9800                        .h_full()
 9801                        .flex_1()
 9802                        .gap_2()
 9803                        .pr_1()
 9804                        .overflow_x_hidden()
 9805                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9806                        .child(left)
 9807                        .child(preview),
 9808                )
 9809            }
 9810        }
 9811    }
 9812
 9813    pub fn render_context_menu(
 9814        &self,
 9815        style: &EditorStyle,
 9816        max_height_in_lines: u32,
 9817        window: &mut Window,
 9818        cx: &mut Context<Editor>,
 9819    ) -> Option<AnyElement> {
 9820        let menu = self.context_menu.borrow();
 9821        let menu = menu.as_ref()?;
 9822        if !menu.visible() {
 9823            return None;
 9824        };
 9825        Some(menu.render(style, max_height_in_lines, window, cx))
 9826    }
 9827
 9828    fn render_context_menu_aside(
 9829        &mut self,
 9830        max_size: Size<Pixels>,
 9831        window: &mut Window,
 9832        cx: &mut Context<Editor>,
 9833    ) -> Option<AnyElement> {
 9834        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9835            if menu.visible() {
 9836                menu.render_aside(max_size, window, cx)
 9837            } else {
 9838                None
 9839            }
 9840        })
 9841    }
 9842
 9843    fn hide_context_menu(
 9844        &mut self,
 9845        window: &mut Window,
 9846        cx: &mut Context<Self>,
 9847    ) -> Option<CodeContextMenu> {
 9848        cx.notify();
 9849        self.completion_tasks.clear();
 9850        let context_menu = self.context_menu.borrow_mut().take();
 9851        self.stale_edit_prediction_in_menu.take();
 9852        self.update_visible_edit_prediction(window, cx);
 9853        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9854            && let Some(completion_provider) = &self.completion_provider
 9855        {
 9856            completion_provider.selection_changed(None, window, cx);
 9857        }
 9858        context_menu
 9859    }
 9860
 9861    fn show_snippet_choices(
 9862        &mut self,
 9863        choices: &Vec<String>,
 9864        selection: Range<Anchor>,
 9865        cx: &mut Context<Self>,
 9866    ) {
 9867        let Some((_, buffer, _)) = self
 9868            .buffer()
 9869            .read(cx)
 9870            .excerpt_containing(selection.start, cx)
 9871        else {
 9872            return;
 9873        };
 9874        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9875        else {
 9876            return;
 9877        };
 9878        if buffer != end_buffer {
 9879            log::error!("expected anchor range to have matching buffer IDs");
 9880            return;
 9881        }
 9882
 9883        let id = post_inc(&mut self.next_completion_id);
 9884        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9885        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9886            CompletionsMenu::new_snippet_choices(
 9887                id,
 9888                true,
 9889                choices,
 9890                selection,
 9891                buffer,
 9892                snippet_sort_order,
 9893            ),
 9894        ));
 9895    }
 9896
 9897    pub fn insert_snippet(
 9898        &mut self,
 9899        insertion_ranges: &[Range<MultiBufferOffset>],
 9900        snippet: Snippet,
 9901        window: &mut Window,
 9902        cx: &mut Context<Self>,
 9903    ) -> Result<()> {
 9904        struct Tabstop<T> {
 9905            is_end_tabstop: bool,
 9906            ranges: Vec<Range<T>>,
 9907            choices: Option<Vec<String>>,
 9908        }
 9909
 9910        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9911            let snippet_text: Arc<str> = snippet.text.clone().into();
 9912            let edits = insertion_ranges
 9913                .iter()
 9914                .cloned()
 9915                .map(|range| (range, snippet_text.clone()));
 9916            let autoindent_mode = AutoindentMode::Block {
 9917                original_indent_columns: Vec::new(),
 9918            };
 9919            buffer.edit(edits, Some(autoindent_mode), cx);
 9920
 9921            let snapshot = &*buffer.read(cx);
 9922            let snippet = &snippet;
 9923            snippet
 9924                .tabstops
 9925                .iter()
 9926                .map(|tabstop| {
 9927                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9928                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9929                    });
 9930                    let mut tabstop_ranges = tabstop
 9931                        .ranges
 9932                        .iter()
 9933                        .flat_map(|tabstop_range| {
 9934                            let mut delta = 0_isize;
 9935                            insertion_ranges.iter().map(move |insertion_range| {
 9936                                let insertion_start = insertion_range.start + delta;
 9937                                delta += snippet.text.len() as isize
 9938                                    - (insertion_range.end - insertion_range.start) as isize;
 9939
 9940                                let start =
 9941                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9942                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9943                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9944                            })
 9945                        })
 9946                        .collect::<Vec<_>>();
 9947                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9948
 9949                    Tabstop {
 9950                        is_end_tabstop,
 9951                        ranges: tabstop_ranges,
 9952                        choices: tabstop.choices.clone(),
 9953                    }
 9954                })
 9955                .collect::<Vec<_>>()
 9956        });
 9957        if let Some(tabstop) = tabstops.first() {
 9958            self.change_selections(Default::default(), window, cx, |s| {
 9959                // Reverse order so that the first range is the newest created selection.
 9960                // Completions will use it and autoscroll will prioritize it.
 9961                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9962            });
 9963
 9964            if let Some(choices) = &tabstop.choices
 9965                && let Some(selection) = tabstop.ranges.first()
 9966            {
 9967                self.show_snippet_choices(choices, selection.clone(), cx)
 9968            }
 9969
 9970            // If we're already at the last tabstop and it's at the end of the snippet,
 9971            // we're done, we don't need to keep the state around.
 9972            if !tabstop.is_end_tabstop {
 9973                let choices = tabstops
 9974                    .iter()
 9975                    .map(|tabstop| tabstop.choices.clone())
 9976                    .collect();
 9977
 9978                let ranges = tabstops
 9979                    .into_iter()
 9980                    .map(|tabstop| tabstop.ranges)
 9981                    .collect::<Vec<_>>();
 9982
 9983                self.snippet_stack.push(SnippetState {
 9984                    active_index: 0,
 9985                    ranges,
 9986                    choices,
 9987                });
 9988            }
 9989
 9990            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9991            if self.autoclose_regions.is_empty() {
 9992                let snapshot = self.buffer.read(cx).snapshot(cx);
 9993                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9994                    let selection_head = selection.head();
 9995                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9996                        continue;
 9997                    };
 9998
 9999                    let mut bracket_pair = None;
10000                    let max_lookup_length = scope
10001                        .brackets()
10002                        .map(|(pair, _)| {
10003                            pair.start
10004                                .as_str()
10005                                .chars()
10006                                .count()
10007                                .max(pair.end.as_str().chars().count())
10008                        })
10009                        .max();
10010                    if let Some(max_lookup_length) = max_lookup_length {
10011                        let next_text = snapshot
10012                            .chars_at(selection_head)
10013                            .take(max_lookup_length)
10014                            .collect::<String>();
10015                        let prev_text = snapshot
10016                            .reversed_chars_at(selection_head)
10017                            .take(max_lookup_length)
10018                            .collect::<String>();
10019
10020                        for (pair, enabled) in scope.brackets() {
10021                            if enabled
10022                                && pair.close
10023                                && prev_text.starts_with(pair.start.as_str())
10024                                && next_text.starts_with(pair.end.as_str())
10025                            {
10026                                bracket_pair = Some(pair.clone());
10027                                break;
10028                            }
10029                        }
10030                    }
10031
10032                    if let Some(pair) = bracket_pair {
10033                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10034                        let autoclose_enabled =
10035                            self.use_autoclose && snapshot_settings.use_autoclose;
10036                        if autoclose_enabled {
10037                            let start = snapshot.anchor_after(selection_head);
10038                            let end = snapshot.anchor_after(selection_head);
10039                            self.autoclose_regions.push(AutocloseRegion {
10040                                selection_id: selection.id,
10041                                range: start..end,
10042                                pair,
10043                            });
10044                        }
10045                    }
10046                }
10047            }
10048        }
10049        Ok(())
10050    }
10051
10052    pub fn move_to_next_snippet_tabstop(
10053        &mut self,
10054        window: &mut Window,
10055        cx: &mut Context<Self>,
10056    ) -> bool {
10057        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10058    }
10059
10060    pub fn move_to_prev_snippet_tabstop(
10061        &mut self,
10062        window: &mut Window,
10063        cx: &mut Context<Self>,
10064    ) -> bool {
10065        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10066    }
10067
10068    pub fn move_to_snippet_tabstop(
10069        &mut self,
10070        bias: Bias,
10071        window: &mut Window,
10072        cx: &mut Context<Self>,
10073    ) -> bool {
10074        if let Some(mut snippet) = self.snippet_stack.pop() {
10075            match bias {
10076                Bias::Left => {
10077                    if snippet.active_index > 0 {
10078                        snippet.active_index -= 1;
10079                    } else {
10080                        self.snippet_stack.push(snippet);
10081                        return false;
10082                    }
10083                }
10084                Bias::Right => {
10085                    if snippet.active_index + 1 < snippet.ranges.len() {
10086                        snippet.active_index += 1;
10087                    } else {
10088                        self.snippet_stack.push(snippet);
10089                        return false;
10090                    }
10091                }
10092            }
10093            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10094                self.change_selections(Default::default(), window, cx, |s| {
10095                    // Reverse order so that the first range is the newest created selection.
10096                    // Completions will use it and autoscroll will prioritize it.
10097                    s.select_ranges(current_ranges.iter().rev().cloned())
10098                });
10099
10100                if let Some(choices) = &snippet.choices[snippet.active_index]
10101                    && let Some(selection) = current_ranges.first()
10102                {
10103                    self.show_snippet_choices(choices, selection.clone(), cx);
10104                }
10105
10106                // If snippet state is not at the last tabstop, push it back on the stack
10107                if snippet.active_index + 1 < snippet.ranges.len() {
10108                    self.snippet_stack.push(snippet);
10109                }
10110                return true;
10111            }
10112        }
10113
10114        false
10115    }
10116
10117    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10118        self.transact(window, cx, |this, window, cx| {
10119            this.select_all(&SelectAll, window, cx);
10120            this.insert("", window, cx);
10121        });
10122    }
10123
10124    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10125        if self.read_only(cx) {
10126            return;
10127        }
10128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10129        self.transact(window, cx, |this, window, cx| {
10130            this.select_autoclose_pair(window, cx);
10131
10132            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10133
10134            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10135            if !this.linked_edit_ranges.is_empty() {
10136                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10137                let snapshot = this.buffer.read(cx).snapshot(cx);
10138
10139                for selection in selections.iter() {
10140                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10141                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10142                    if selection_start.buffer_id != selection_end.buffer_id {
10143                        continue;
10144                    }
10145                    if let Some(ranges) =
10146                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10147                    {
10148                        for (buffer, entries) in ranges {
10149                            linked_ranges.entry(buffer).or_default().extend(entries);
10150                        }
10151                    }
10152                }
10153            }
10154
10155            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10156            for selection in &mut selections {
10157                if selection.is_empty() {
10158                    let old_head = selection.head();
10159                    let mut new_head =
10160                        movement::left(&display_map, old_head.to_display_point(&display_map))
10161                            .to_point(&display_map);
10162                    if let Some((buffer, line_buffer_range)) = display_map
10163                        .buffer_snapshot()
10164                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10165                    {
10166                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10167                        let indent_len = match indent_size.kind {
10168                            IndentKind::Space => {
10169                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10170                            }
10171                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10172                        };
10173                        if old_head.column <= indent_size.len && old_head.column > 0 {
10174                            let indent_len = indent_len.get();
10175                            new_head = cmp::min(
10176                                new_head,
10177                                MultiBufferPoint::new(
10178                                    old_head.row,
10179                                    ((old_head.column - 1) / indent_len) * indent_len,
10180                                ),
10181                            );
10182                        }
10183                    }
10184
10185                    selection.set_head(new_head, SelectionGoal::None);
10186                }
10187            }
10188
10189            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10190            this.insert("", window, cx);
10191            let empty_str: Arc<str> = Arc::from("");
10192            for (buffer, edits) in linked_ranges {
10193                let snapshot = buffer.read(cx).snapshot();
10194                use text::ToPoint as TP;
10195
10196                let edits = edits
10197                    .into_iter()
10198                    .map(|range| {
10199                        let end_point = TP::to_point(&range.end, &snapshot);
10200                        let mut start_point = TP::to_point(&range.start, &snapshot);
10201
10202                        if end_point == start_point {
10203                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10204                                .saturating_sub(1);
10205                            start_point =
10206                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10207                        };
10208
10209                        (start_point..end_point, empty_str.clone())
10210                    })
10211                    .sorted_by_key(|(range, _)| range.start)
10212                    .collect::<Vec<_>>();
10213                buffer.update(cx, |this, cx| {
10214                    this.edit(edits, None, cx);
10215                })
10216            }
10217            this.refresh_edit_prediction(true, false, window, cx);
10218            refresh_linked_ranges(this, window, cx);
10219        });
10220    }
10221
10222    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10223        if self.read_only(cx) {
10224            return;
10225        }
10226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10227        self.transact(window, cx, |this, window, cx| {
10228            this.change_selections(Default::default(), window, cx, |s| {
10229                s.move_with(|map, selection| {
10230                    if selection.is_empty() {
10231                        let cursor = movement::right(map, selection.head());
10232                        selection.end = cursor;
10233                        selection.reversed = true;
10234                        selection.goal = SelectionGoal::None;
10235                    }
10236                })
10237            });
10238            this.insert("", window, cx);
10239            this.refresh_edit_prediction(true, false, window, cx);
10240        });
10241    }
10242
10243    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10244        if self.mode.is_single_line() {
10245            cx.propagate();
10246            return;
10247        }
10248
10249        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10250        if self.move_to_prev_snippet_tabstop(window, cx) {
10251            return;
10252        }
10253        self.outdent(&Outdent, window, cx);
10254    }
10255
10256    pub fn next_snippet_tabstop(
10257        &mut self,
10258        _: &NextSnippetTabstop,
10259        window: &mut Window,
10260        cx: &mut Context<Self>,
10261    ) {
10262        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10263            cx.propagate();
10264            return;
10265        }
10266
10267        if self.move_to_next_snippet_tabstop(window, cx) {
10268            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10269            return;
10270        }
10271        cx.propagate();
10272    }
10273
10274    pub fn previous_snippet_tabstop(
10275        &mut self,
10276        _: &PreviousSnippetTabstop,
10277        window: &mut Window,
10278        cx: &mut Context<Self>,
10279    ) {
10280        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10281            cx.propagate();
10282            return;
10283        }
10284
10285        if self.move_to_prev_snippet_tabstop(window, cx) {
10286            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10287            return;
10288        }
10289        cx.propagate();
10290    }
10291
10292    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10293        if self.mode.is_single_line() {
10294            cx.propagate();
10295            return;
10296        }
10297
10298        if self.move_to_next_snippet_tabstop(window, cx) {
10299            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10300            return;
10301        }
10302        if self.read_only(cx) {
10303            return;
10304        }
10305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10306        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10307        let buffer = self.buffer.read(cx);
10308        let snapshot = buffer.snapshot(cx);
10309        let rows_iter = selections.iter().map(|s| s.head().row);
10310        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10311
10312        let has_some_cursor_in_whitespace = selections
10313            .iter()
10314            .filter(|selection| selection.is_empty())
10315            .any(|selection| {
10316                let cursor = selection.head();
10317                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10318                cursor.column < current_indent.len
10319            });
10320
10321        let mut edits = Vec::new();
10322        let mut prev_edited_row = 0;
10323        let mut row_delta = 0;
10324        for selection in &mut selections {
10325            if selection.start.row != prev_edited_row {
10326                row_delta = 0;
10327            }
10328            prev_edited_row = selection.end.row;
10329
10330            // If the selection is non-empty, then increase the indentation of the selected lines.
10331            if !selection.is_empty() {
10332                row_delta =
10333                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10334                continue;
10335            }
10336
10337            let cursor = selection.head();
10338            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10339            if let Some(suggested_indent) =
10340                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10341            {
10342                // Don't do anything if already at suggested indent
10343                // and there is any other cursor which is not
10344                if has_some_cursor_in_whitespace
10345                    && cursor.column == current_indent.len
10346                    && current_indent.len == suggested_indent.len
10347                {
10348                    continue;
10349                }
10350
10351                // Adjust line and move cursor to suggested indent
10352                // if cursor is not at suggested indent
10353                if cursor.column < suggested_indent.len
10354                    && cursor.column <= current_indent.len
10355                    && current_indent.len <= suggested_indent.len
10356                {
10357                    selection.start = Point::new(cursor.row, suggested_indent.len);
10358                    selection.end = selection.start;
10359                    if row_delta == 0 {
10360                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10361                            cursor.row,
10362                            current_indent,
10363                            suggested_indent,
10364                        ));
10365                        row_delta = suggested_indent.len - current_indent.len;
10366                    }
10367                    continue;
10368                }
10369
10370                // If current indent is more than suggested indent
10371                // only move cursor to current indent and skip indent
10372                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10373                    selection.start = Point::new(cursor.row, current_indent.len);
10374                    selection.end = selection.start;
10375                    continue;
10376                }
10377            }
10378
10379            // Otherwise, insert a hard or soft tab.
10380            let settings = buffer.language_settings_at(cursor, cx);
10381            let tab_size = if settings.hard_tabs {
10382                IndentSize::tab()
10383            } else {
10384                let tab_size = settings.tab_size.get();
10385                let indent_remainder = snapshot
10386                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10387                    .flat_map(str::chars)
10388                    .fold(row_delta % tab_size, |counter: u32, c| {
10389                        if c == '\t' {
10390                            0
10391                        } else {
10392                            (counter + 1) % tab_size
10393                        }
10394                    });
10395
10396                let chars_to_next_tab_stop = tab_size - indent_remainder;
10397                IndentSize::spaces(chars_to_next_tab_stop)
10398            };
10399            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10400            selection.end = selection.start;
10401            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10402            row_delta += tab_size.len;
10403        }
10404
10405        self.transact(window, cx, |this, window, cx| {
10406            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10407            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10408            this.refresh_edit_prediction(true, false, window, cx);
10409        });
10410    }
10411
10412    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10413        if self.read_only(cx) {
10414            return;
10415        }
10416        if self.mode.is_single_line() {
10417            cx.propagate();
10418            return;
10419        }
10420
10421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10422        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10423        let mut prev_edited_row = 0;
10424        let mut row_delta = 0;
10425        let mut edits = Vec::new();
10426        let buffer = self.buffer.read(cx);
10427        let snapshot = buffer.snapshot(cx);
10428        for selection in &mut selections {
10429            if selection.start.row != prev_edited_row {
10430                row_delta = 0;
10431            }
10432            prev_edited_row = selection.end.row;
10433
10434            row_delta =
10435                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10436        }
10437
10438        self.transact(window, cx, |this, window, cx| {
10439            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10440            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10441        });
10442    }
10443
10444    fn indent_selection(
10445        buffer: &MultiBuffer,
10446        snapshot: &MultiBufferSnapshot,
10447        selection: &mut Selection<Point>,
10448        edits: &mut Vec<(Range<Point>, String)>,
10449        delta_for_start_row: u32,
10450        cx: &App,
10451    ) -> u32 {
10452        let settings = buffer.language_settings_at(selection.start, cx);
10453        let tab_size = settings.tab_size.get();
10454        let indent_kind = if settings.hard_tabs {
10455            IndentKind::Tab
10456        } else {
10457            IndentKind::Space
10458        };
10459        let mut start_row = selection.start.row;
10460        let mut end_row = selection.end.row + 1;
10461
10462        // If a selection ends at the beginning of a line, don't indent
10463        // that last line.
10464        if selection.end.column == 0 && selection.end.row > selection.start.row {
10465            end_row -= 1;
10466        }
10467
10468        // Avoid re-indenting a row that has already been indented by a
10469        // previous selection, but still update this selection's column
10470        // to reflect that indentation.
10471        if delta_for_start_row > 0 {
10472            start_row += 1;
10473            selection.start.column += delta_for_start_row;
10474            if selection.end.row == selection.start.row {
10475                selection.end.column += delta_for_start_row;
10476            }
10477        }
10478
10479        let mut delta_for_end_row = 0;
10480        let has_multiple_rows = start_row + 1 != end_row;
10481        for row in start_row..end_row {
10482            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10483            let indent_delta = match (current_indent.kind, indent_kind) {
10484                (IndentKind::Space, IndentKind::Space) => {
10485                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10486                    IndentSize::spaces(columns_to_next_tab_stop)
10487                }
10488                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10489                (_, IndentKind::Tab) => IndentSize::tab(),
10490            };
10491
10492            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10493                0
10494            } else {
10495                selection.start.column
10496            };
10497            let row_start = Point::new(row, start);
10498            edits.push((
10499                row_start..row_start,
10500                indent_delta.chars().collect::<String>(),
10501            ));
10502
10503            // Update this selection's endpoints to reflect the indentation.
10504            if row == selection.start.row {
10505                selection.start.column += indent_delta.len;
10506            }
10507            if row == selection.end.row {
10508                selection.end.column += indent_delta.len;
10509                delta_for_end_row = indent_delta.len;
10510            }
10511        }
10512
10513        if selection.start.row == selection.end.row {
10514            delta_for_start_row + delta_for_end_row
10515        } else {
10516            delta_for_end_row
10517        }
10518    }
10519
10520    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10521        if self.read_only(cx) {
10522            return;
10523        }
10524        if self.mode.is_single_line() {
10525            cx.propagate();
10526            return;
10527        }
10528
10529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10530        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10531        let selections = self.selections.all::<Point>(&display_map);
10532        let mut deletion_ranges = Vec::new();
10533        let mut last_outdent = None;
10534        {
10535            let buffer = self.buffer.read(cx);
10536            let snapshot = buffer.snapshot(cx);
10537            for selection in &selections {
10538                let settings = buffer.language_settings_at(selection.start, cx);
10539                let tab_size = settings.tab_size.get();
10540                let mut rows = selection.spanned_rows(false, &display_map);
10541
10542                // Avoid re-outdenting a row that has already been outdented by a
10543                // previous selection.
10544                if let Some(last_row) = last_outdent
10545                    && last_row == rows.start
10546                {
10547                    rows.start = rows.start.next_row();
10548                }
10549                let has_multiple_rows = rows.len() > 1;
10550                for row in rows.iter_rows() {
10551                    let indent_size = snapshot.indent_size_for_line(row);
10552                    if indent_size.len > 0 {
10553                        let deletion_len = match indent_size.kind {
10554                            IndentKind::Space => {
10555                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10556                                if columns_to_prev_tab_stop == 0 {
10557                                    tab_size
10558                                } else {
10559                                    columns_to_prev_tab_stop
10560                                }
10561                            }
10562                            IndentKind::Tab => 1,
10563                        };
10564                        let start = if has_multiple_rows
10565                            || deletion_len > selection.start.column
10566                            || indent_size.len < selection.start.column
10567                        {
10568                            0
10569                        } else {
10570                            selection.start.column - deletion_len
10571                        };
10572                        deletion_ranges.push(
10573                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10574                        );
10575                        last_outdent = Some(row);
10576                    }
10577                }
10578            }
10579        }
10580
10581        self.transact(window, cx, |this, window, cx| {
10582            this.buffer.update(cx, |buffer, cx| {
10583                let empty_str: Arc<str> = Arc::default();
10584                buffer.edit(
10585                    deletion_ranges
10586                        .into_iter()
10587                        .map(|range| (range, empty_str.clone())),
10588                    None,
10589                    cx,
10590                );
10591            });
10592            let selections = this
10593                .selections
10594                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10595            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10596        });
10597    }
10598
10599    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10600        if self.read_only(cx) {
10601            return;
10602        }
10603        if self.mode.is_single_line() {
10604            cx.propagate();
10605            return;
10606        }
10607
10608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10609        let selections = self
10610            .selections
10611            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10612            .into_iter()
10613            .map(|s| s.range());
10614
10615        self.transact(window, cx, |this, window, cx| {
10616            this.buffer.update(cx, |buffer, cx| {
10617                buffer.autoindent_ranges(selections, cx);
10618            });
10619            let selections = this
10620                .selections
10621                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10622            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10623        });
10624    }
10625
10626    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10628        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10629        let selections = self.selections.all::<Point>(&display_map);
10630
10631        let mut new_cursors = Vec::new();
10632        let mut edit_ranges = Vec::new();
10633        let mut selections = selections.iter().peekable();
10634        while let Some(selection) = selections.next() {
10635            let mut rows = selection.spanned_rows(false, &display_map);
10636
10637            // Accumulate contiguous regions of rows that we want to delete.
10638            while let Some(next_selection) = selections.peek() {
10639                let next_rows = next_selection.spanned_rows(false, &display_map);
10640                if next_rows.start <= rows.end {
10641                    rows.end = next_rows.end;
10642                    selections.next().unwrap();
10643                } else {
10644                    break;
10645                }
10646            }
10647
10648            let buffer = display_map.buffer_snapshot();
10649            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10650            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10651                // If there's a line after the range, delete the \n from the end of the row range
10652                (
10653                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10654                    rows.end,
10655                )
10656            } else {
10657                // If there isn't a line after the range, delete the \n from the line before the
10658                // start of the row range
10659                edit_start = edit_start.saturating_sub_usize(1);
10660                (buffer.len(), rows.start.previous_row())
10661            };
10662
10663            let text_layout_details = self.text_layout_details(window);
10664            let x = display_map.x_for_display_point(
10665                selection.head().to_display_point(&display_map),
10666                &text_layout_details,
10667            );
10668            let row = Point::new(target_row.0, 0)
10669                .to_display_point(&display_map)
10670                .row();
10671            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10672
10673            new_cursors.push((
10674                selection.id,
10675                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10676                SelectionGoal::None,
10677            ));
10678            edit_ranges.push(edit_start..edit_end);
10679        }
10680
10681        self.transact(window, cx, |this, window, cx| {
10682            let buffer = this.buffer.update(cx, |buffer, cx| {
10683                let empty_str: Arc<str> = Arc::default();
10684                buffer.edit(
10685                    edit_ranges
10686                        .into_iter()
10687                        .map(|range| (range, empty_str.clone())),
10688                    None,
10689                    cx,
10690                );
10691                buffer.snapshot(cx)
10692            });
10693            let new_selections = new_cursors
10694                .into_iter()
10695                .map(|(id, cursor, goal)| {
10696                    let cursor = cursor.to_point(&buffer);
10697                    Selection {
10698                        id,
10699                        start: cursor,
10700                        end: cursor,
10701                        reversed: false,
10702                        goal,
10703                    }
10704                })
10705                .collect();
10706
10707            this.change_selections(Default::default(), window, cx, |s| {
10708                s.select(new_selections);
10709            });
10710        });
10711    }
10712
10713    pub fn join_lines_impl(
10714        &mut self,
10715        insert_whitespace: bool,
10716        window: &mut Window,
10717        cx: &mut Context<Self>,
10718    ) {
10719        if self.read_only(cx) {
10720            return;
10721        }
10722        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10723        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10724            let start = MultiBufferRow(selection.start.row);
10725            // Treat single line selections as if they include the next line. Otherwise this action
10726            // would do nothing for single line selections individual cursors.
10727            let end = if selection.start.row == selection.end.row {
10728                MultiBufferRow(selection.start.row + 1)
10729            } else {
10730                MultiBufferRow(selection.end.row)
10731            };
10732
10733            if let Some(last_row_range) = row_ranges.last_mut()
10734                && start <= last_row_range.end
10735            {
10736                last_row_range.end = end;
10737                continue;
10738            }
10739            row_ranges.push(start..end);
10740        }
10741
10742        let snapshot = self.buffer.read(cx).snapshot(cx);
10743        let mut cursor_positions = Vec::new();
10744        for row_range in &row_ranges {
10745            let anchor = snapshot.anchor_before(Point::new(
10746                row_range.end.previous_row().0,
10747                snapshot.line_len(row_range.end.previous_row()),
10748            ));
10749            cursor_positions.push(anchor..anchor);
10750        }
10751
10752        self.transact(window, cx, |this, window, cx| {
10753            for row_range in row_ranges.into_iter().rev() {
10754                for row in row_range.iter_rows().rev() {
10755                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10756                    let next_line_row = row.next_row();
10757                    let indent = snapshot.indent_size_for_line(next_line_row);
10758                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10759
10760                    let replace =
10761                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10762                            " "
10763                        } else {
10764                            ""
10765                        };
10766
10767                    this.buffer.update(cx, |buffer, cx| {
10768                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10769                    });
10770                }
10771            }
10772
10773            this.change_selections(Default::default(), window, cx, |s| {
10774                s.select_anchor_ranges(cursor_positions)
10775            });
10776        });
10777    }
10778
10779    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10781        self.join_lines_impl(true, window, cx);
10782    }
10783
10784    pub fn sort_lines_case_sensitive(
10785        &mut self,
10786        _: &SortLinesCaseSensitive,
10787        window: &mut Window,
10788        cx: &mut Context<Self>,
10789    ) {
10790        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10791    }
10792
10793    pub fn sort_lines_by_length(
10794        &mut self,
10795        _: &SortLinesByLength,
10796        window: &mut Window,
10797        cx: &mut Context<Self>,
10798    ) {
10799        self.manipulate_immutable_lines(window, cx, |lines| {
10800            lines.sort_by_key(|&line| line.chars().count())
10801        })
10802    }
10803
10804    pub fn sort_lines_case_insensitive(
10805        &mut self,
10806        _: &SortLinesCaseInsensitive,
10807        window: &mut Window,
10808        cx: &mut Context<Self>,
10809    ) {
10810        self.manipulate_immutable_lines(window, cx, |lines| {
10811            lines.sort_by_key(|line| line.to_lowercase())
10812        })
10813    }
10814
10815    pub fn unique_lines_case_insensitive(
10816        &mut self,
10817        _: &UniqueLinesCaseInsensitive,
10818        window: &mut Window,
10819        cx: &mut Context<Self>,
10820    ) {
10821        self.manipulate_immutable_lines(window, cx, |lines| {
10822            let mut seen = HashSet::default();
10823            lines.retain(|line| seen.insert(line.to_lowercase()));
10824        })
10825    }
10826
10827    pub fn unique_lines_case_sensitive(
10828        &mut self,
10829        _: &UniqueLinesCaseSensitive,
10830        window: &mut Window,
10831        cx: &mut Context<Self>,
10832    ) {
10833        self.manipulate_immutable_lines(window, cx, |lines| {
10834            let mut seen = HashSet::default();
10835            lines.retain(|line| seen.insert(*line));
10836        })
10837    }
10838
10839    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10840        let snapshot = self.buffer.read(cx).snapshot(cx);
10841        for selection in self.selections.disjoint_anchors_arc().iter() {
10842            if snapshot
10843                .language_at(selection.start)
10844                .and_then(|lang| lang.config().wrap_characters.as_ref())
10845                .is_some()
10846            {
10847                return true;
10848            }
10849        }
10850        false
10851    }
10852
10853    fn wrap_selections_in_tag(
10854        &mut self,
10855        _: &WrapSelectionsInTag,
10856        window: &mut Window,
10857        cx: &mut Context<Self>,
10858    ) {
10859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10860
10861        let snapshot = self.buffer.read(cx).snapshot(cx);
10862
10863        let mut edits = Vec::new();
10864        let mut boundaries = Vec::new();
10865
10866        for selection in self
10867            .selections
10868            .all_adjusted(&self.display_snapshot(cx))
10869            .iter()
10870        {
10871            let Some(wrap_config) = snapshot
10872                .language_at(selection.start)
10873                .and_then(|lang| lang.config().wrap_characters.clone())
10874            else {
10875                continue;
10876            };
10877
10878            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10879            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10880
10881            let start_before = snapshot.anchor_before(selection.start);
10882            let end_after = snapshot.anchor_after(selection.end);
10883
10884            edits.push((start_before..start_before, open_tag));
10885            edits.push((end_after..end_after, close_tag));
10886
10887            boundaries.push((
10888                start_before,
10889                end_after,
10890                wrap_config.start_prefix.len(),
10891                wrap_config.end_suffix.len(),
10892            ));
10893        }
10894
10895        if edits.is_empty() {
10896            return;
10897        }
10898
10899        self.transact(window, cx, |this, window, cx| {
10900            let buffer = this.buffer.update(cx, |buffer, cx| {
10901                buffer.edit(edits, None, cx);
10902                buffer.snapshot(cx)
10903            });
10904
10905            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10906            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10907                boundaries.into_iter()
10908            {
10909                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10910                let close_offset = end_after
10911                    .to_offset(&buffer)
10912                    .saturating_sub_usize(end_suffix_len);
10913                new_selections.push(open_offset..open_offset);
10914                new_selections.push(close_offset..close_offset);
10915            }
10916
10917            this.change_selections(Default::default(), window, cx, |s| {
10918                s.select_ranges(new_selections);
10919            });
10920
10921            this.request_autoscroll(Autoscroll::fit(), cx);
10922        });
10923    }
10924
10925    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10926        let Some(project) = self.project.clone() else {
10927            return;
10928        };
10929        self.reload(project, window, cx)
10930            .detach_and_notify_err(window, cx);
10931    }
10932
10933    pub fn restore_file(
10934        &mut self,
10935        _: &::git::RestoreFile,
10936        window: &mut Window,
10937        cx: &mut Context<Self>,
10938    ) {
10939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10940        let mut buffer_ids = HashSet::default();
10941        let snapshot = self.buffer().read(cx).snapshot(cx);
10942        for selection in self
10943            .selections
10944            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10945        {
10946            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10947        }
10948
10949        let buffer = self.buffer().read(cx);
10950        let ranges = buffer_ids
10951            .into_iter()
10952            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10953            .collect::<Vec<_>>();
10954
10955        self.restore_hunks_in_ranges(ranges, window, cx);
10956    }
10957
10958    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10960        let selections = self
10961            .selections
10962            .all(&self.display_snapshot(cx))
10963            .into_iter()
10964            .map(|s| s.range())
10965            .collect();
10966        self.restore_hunks_in_ranges(selections, window, cx);
10967    }
10968
10969    pub fn restore_hunks_in_ranges(
10970        &mut self,
10971        ranges: Vec<Range<Point>>,
10972        window: &mut Window,
10973        cx: &mut Context<Editor>,
10974    ) {
10975        let mut revert_changes = HashMap::default();
10976        let chunk_by = self
10977            .snapshot(window, cx)
10978            .hunks_for_ranges(ranges)
10979            .into_iter()
10980            .chunk_by(|hunk| hunk.buffer_id);
10981        for (buffer_id, hunks) in &chunk_by {
10982            let hunks = hunks.collect::<Vec<_>>();
10983            for hunk in &hunks {
10984                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10985            }
10986            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10987        }
10988        drop(chunk_by);
10989        if !revert_changes.is_empty() {
10990            self.transact(window, cx, |editor, window, cx| {
10991                editor.restore(revert_changes, window, cx);
10992            });
10993        }
10994    }
10995
10996    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10997        if let Some(status) = self
10998            .addons
10999            .iter()
11000            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11001        {
11002            return Some(status);
11003        }
11004        self.project
11005            .as_ref()?
11006            .read(cx)
11007            .status_for_buffer_id(buffer_id, cx)
11008    }
11009
11010    pub fn open_active_item_in_terminal(
11011        &mut self,
11012        _: &OpenInTerminal,
11013        window: &mut Window,
11014        cx: &mut Context<Self>,
11015    ) {
11016        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11017            let project_path = buffer.read(cx).project_path(cx)?;
11018            let project = self.project()?.read(cx);
11019            let entry = project.entry_for_path(&project_path, cx)?;
11020            let parent = match &entry.canonical_path {
11021                Some(canonical_path) => canonical_path.to_path_buf(),
11022                None => project.absolute_path(&project_path, cx)?,
11023            }
11024            .parent()?
11025            .to_path_buf();
11026            Some(parent)
11027        }) {
11028            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11029        }
11030    }
11031
11032    fn set_breakpoint_context_menu(
11033        &mut self,
11034        display_row: DisplayRow,
11035        position: Option<Anchor>,
11036        clicked_point: gpui::Point<Pixels>,
11037        window: &mut Window,
11038        cx: &mut Context<Self>,
11039    ) {
11040        let source = self
11041            .buffer
11042            .read(cx)
11043            .snapshot(cx)
11044            .anchor_before(Point::new(display_row.0, 0u32));
11045
11046        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11047
11048        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11049            self,
11050            source,
11051            clicked_point,
11052            context_menu,
11053            window,
11054            cx,
11055        );
11056    }
11057
11058    fn add_edit_breakpoint_block(
11059        &mut self,
11060        anchor: Anchor,
11061        breakpoint: &Breakpoint,
11062        edit_action: BreakpointPromptEditAction,
11063        window: &mut Window,
11064        cx: &mut Context<Self>,
11065    ) {
11066        let weak_editor = cx.weak_entity();
11067        let bp_prompt = cx.new(|cx| {
11068            BreakpointPromptEditor::new(
11069                weak_editor,
11070                anchor,
11071                breakpoint.clone(),
11072                edit_action,
11073                window,
11074                cx,
11075            )
11076        });
11077
11078        let height = bp_prompt.update(cx, |this, cx| {
11079            this.prompt
11080                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11081        });
11082        let cloned_prompt = bp_prompt.clone();
11083        let blocks = vec![BlockProperties {
11084            style: BlockStyle::Sticky,
11085            placement: BlockPlacement::Above(anchor),
11086            height: Some(height),
11087            render: Arc::new(move |cx| {
11088                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11089                cloned_prompt.clone().into_any_element()
11090            }),
11091            priority: 0,
11092        }];
11093
11094        let focus_handle = bp_prompt.focus_handle(cx);
11095        window.focus(&focus_handle);
11096
11097        let block_ids = self.insert_blocks(blocks, None, cx);
11098        bp_prompt.update(cx, |prompt, _| {
11099            prompt.add_block_ids(block_ids);
11100        });
11101    }
11102
11103    pub(crate) fn breakpoint_at_row(
11104        &self,
11105        row: u32,
11106        window: &mut Window,
11107        cx: &mut Context<Self>,
11108    ) -> Option<(Anchor, Breakpoint)> {
11109        let snapshot = self.snapshot(window, cx);
11110        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11111
11112        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11113    }
11114
11115    pub(crate) fn breakpoint_at_anchor(
11116        &self,
11117        breakpoint_position: Anchor,
11118        snapshot: &EditorSnapshot,
11119        cx: &mut Context<Self>,
11120    ) -> Option<(Anchor, Breakpoint)> {
11121        let buffer = self
11122            .buffer
11123            .read(cx)
11124            .buffer_for_anchor(breakpoint_position, cx)?;
11125
11126        let enclosing_excerpt = breakpoint_position.excerpt_id;
11127        let buffer_snapshot = buffer.read(cx).snapshot();
11128
11129        let row = buffer_snapshot
11130            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11131            .row;
11132
11133        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11134        let anchor_end = snapshot
11135            .buffer_snapshot()
11136            .anchor_after(Point::new(row, line_len));
11137
11138        self.breakpoint_store
11139            .as_ref()?
11140            .read_with(cx, |breakpoint_store, cx| {
11141                breakpoint_store
11142                    .breakpoints(
11143                        &buffer,
11144                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11145                        &buffer_snapshot,
11146                        cx,
11147                    )
11148                    .next()
11149                    .and_then(|(bp, _)| {
11150                        let breakpoint_row = buffer_snapshot
11151                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11152                            .row;
11153
11154                        if breakpoint_row == row {
11155                            snapshot
11156                                .buffer_snapshot()
11157                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11158                                .map(|position| (position, bp.bp.clone()))
11159                        } else {
11160                            None
11161                        }
11162                    })
11163            })
11164    }
11165
11166    pub fn edit_log_breakpoint(
11167        &mut self,
11168        _: &EditLogBreakpoint,
11169        window: &mut Window,
11170        cx: &mut Context<Self>,
11171    ) {
11172        if self.breakpoint_store.is_none() {
11173            return;
11174        }
11175
11176        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11177            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11178                message: None,
11179                state: BreakpointState::Enabled,
11180                condition: None,
11181                hit_condition: None,
11182            });
11183
11184            self.add_edit_breakpoint_block(
11185                anchor,
11186                &breakpoint,
11187                BreakpointPromptEditAction::Log,
11188                window,
11189                cx,
11190            );
11191        }
11192    }
11193
11194    fn breakpoints_at_cursors(
11195        &self,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11199        let snapshot = self.snapshot(window, cx);
11200        let cursors = self
11201            .selections
11202            .disjoint_anchors_arc()
11203            .iter()
11204            .map(|selection| {
11205                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11206
11207                let breakpoint_position = self
11208                    .breakpoint_at_row(cursor_position.row, window, cx)
11209                    .map(|bp| bp.0)
11210                    .unwrap_or_else(|| {
11211                        snapshot
11212                            .display_snapshot
11213                            .buffer_snapshot()
11214                            .anchor_after(Point::new(cursor_position.row, 0))
11215                    });
11216
11217                let breakpoint = self
11218                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11219                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11220
11221                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11222            })
11223            // 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.
11224            .collect::<HashMap<Anchor, _>>();
11225
11226        cursors.into_iter().collect()
11227    }
11228
11229    pub fn enable_breakpoint(
11230        &mut self,
11231        _: &crate::actions::EnableBreakpoint,
11232        window: &mut Window,
11233        cx: &mut Context<Self>,
11234    ) {
11235        if self.breakpoint_store.is_none() {
11236            return;
11237        }
11238
11239        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11240            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11241                continue;
11242            };
11243            self.edit_breakpoint_at_anchor(
11244                anchor,
11245                breakpoint,
11246                BreakpointEditAction::InvertState,
11247                cx,
11248            );
11249        }
11250    }
11251
11252    pub fn disable_breakpoint(
11253        &mut self,
11254        _: &crate::actions::DisableBreakpoint,
11255        window: &mut Window,
11256        cx: &mut Context<Self>,
11257    ) {
11258        if self.breakpoint_store.is_none() {
11259            return;
11260        }
11261
11262        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11263            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11264                continue;
11265            };
11266            self.edit_breakpoint_at_anchor(
11267                anchor,
11268                breakpoint,
11269                BreakpointEditAction::InvertState,
11270                cx,
11271            );
11272        }
11273    }
11274
11275    pub fn toggle_breakpoint(
11276        &mut self,
11277        _: &crate::actions::ToggleBreakpoint,
11278        window: &mut Window,
11279        cx: &mut Context<Self>,
11280    ) {
11281        if self.breakpoint_store.is_none() {
11282            return;
11283        }
11284
11285        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11286            if let Some(breakpoint) = breakpoint {
11287                self.edit_breakpoint_at_anchor(
11288                    anchor,
11289                    breakpoint,
11290                    BreakpointEditAction::Toggle,
11291                    cx,
11292                );
11293            } else {
11294                self.edit_breakpoint_at_anchor(
11295                    anchor,
11296                    Breakpoint::new_standard(),
11297                    BreakpointEditAction::Toggle,
11298                    cx,
11299                );
11300            }
11301        }
11302    }
11303
11304    pub fn edit_breakpoint_at_anchor(
11305        &mut self,
11306        breakpoint_position: Anchor,
11307        breakpoint: Breakpoint,
11308        edit_action: BreakpointEditAction,
11309        cx: &mut Context<Self>,
11310    ) {
11311        let Some(breakpoint_store) = &self.breakpoint_store else {
11312            return;
11313        };
11314
11315        let Some(buffer) = self
11316            .buffer
11317            .read(cx)
11318            .buffer_for_anchor(breakpoint_position, cx)
11319        else {
11320            return;
11321        };
11322
11323        breakpoint_store.update(cx, |breakpoint_store, cx| {
11324            breakpoint_store.toggle_breakpoint(
11325                buffer,
11326                BreakpointWithPosition {
11327                    position: breakpoint_position.text_anchor,
11328                    bp: breakpoint,
11329                },
11330                edit_action,
11331                cx,
11332            );
11333        });
11334
11335        cx.notify();
11336    }
11337
11338    #[cfg(any(test, feature = "test-support"))]
11339    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11340        self.breakpoint_store.clone()
11341    }
11342
11343    pub fn prepare_restore_change(
11344        &self,
11345        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11346        hunk: &MultiBufferDiffHunk,
11347        cx: &mut App,
11348    ) -> Option<()> {
11349        if hunk.is_created_file() {
11350            return None;
11351        }
11352        let buffer = self.buffer.read(cx);
11353        let diff = buffer.diff_for(hunk.buffer_id)?;
11354        let buffer = buffer.buffer(hunk.buffer_id)?;
11355        let buffer = buffer.read(cx);
11356        let original_text = diff
11357            .read(cx)
11358            .base_text()
11359            .as_rope()
11360            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11361        let buffer_snapshot = buffer.snapshot();
11362        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11363        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11364            probe
11365                .0
11366                .start
11367                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11368                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11369        }) {
11370            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11371            Some(())
11372        } else {
11373            None
11374        }
11375    }
11376
11377    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11378        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11379    }
11380
11381    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11382        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11383    }
11384
11385    fn manipulate_lines<M>(
11386        &mut self,
11387        window: &mut Window,
11388        cx: &mut Context<Self>,
11389        mut manipulate: M,
11390    ) where
11391        M: FnMut(&str) -> LineManipulationResult,
11392    {
11393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11394
11395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11396        let buffer = self.buffer.read(cx).snapshot(cx);
11397
11398        let mut edits = Vec::new();
11399
11400        let selections = self.selections.all::<Point>(&display_map);
11401        let mut selections = selections.iter().peekable();
11402        let mut contiguous_row_selections = Vec::new();
11403        let mut new_selections = Vec::new();
11404        let mut added_lines = 0;
11405        let mut removed_lines = 0;
11406
11407        while let Some(selection) = selections.next() {
11408            let (start_row, end_row) = consume_contiguous_rows(
11409                &mut contiguous_row_selections,
11410                selection,
11411                &display_map,
11412                &mut selections,
11413            );
11414
11415            let start_point = Point::new(start_row.0, 0);
11416            let end_point = Point::new(
11417                end_row.previous_row().0,
11418                buffer.line_len(end_row.previous_row()),
11419            );
11420            let text = buffer
11421                .text_for_range(start_point..end_point)
11422                .collect::<String>();
11423
11424            let LineManipulationResult {
11425                new_text,
11426                line_count_before,
11427                line_count_after,
11428            } = manipulate(&text);
11429
11430            edits.push((start_point..end_point, new_text));
11431
11432            // Selections must change based on added and removed line count
11433            let start_row =
11434                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11435            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11436            new_selections.push(Selection {
11437                id: selection.id,
11438                start: start_row,
11439                end: end_row,
11440                goal: SelectionGoal::None,
11441                reversed: selection.reversed,
11442            });
11443
11444            if line_count_after > line_count_before {
11445                added_lines += line_count_after - line_count_before;
11446            } else if line_count_before > line_count_after {
11447                removed_lines += line_count_before - line_count_after;
11448            }
11449        }
11450
11451        self.transact(window, cx, |this, window, cx| {
11452            let buffer = this.buffer.update(cx, |buffer, cx| {
11453                buffer.edit(edits, None, cx);
11454                buffer.snapshot(cx)
11455            });
11456
11457            // Recalculate offsets on newly edited buffer
11458            let new_selections = new_selections
11459                .iter()
11460                .map(|s| {
11461                    let start_point = Point::new(s.start.0, 0);
11462                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11463                    Selection {
11464                        id: s.id,
11465                        start: buffer.point_to_offset(start_point),
11466                        end: buffer.point_to_offset(end_point),
11467                        goal: s.goal,
11468                        reversed: s.reversed,
11469                    }
11470                })
11471                .collect();
11472
11473            this.change_selections(Default::default(), window, cx, |s| {
11474                s.select(new_selections);
11475            });
11476
11477            this.request_autoscroll(Autoscroll::fit(), cx);
11478        });
11479    }
11480
11481    fn manipulate_immutable_lines<Fn>(
11482        &mut self,
11483        window: &mut Window,
11484        cx: &mut Context<Self>,
11485        mut callback: Fn,
11486    ) where
11487        Fn: FnMut(&mut Vec<&str>),
11488    {
11489        self.manipulate_lines(window, cx, |text| {
11490            let mut lines: Vec<&str> = text.split('\n').collect();
11491            let line_count_before = lines.len();
11492
11493            callback(&mut lines);
11494
11495            LineManipulationResult {
11496                new_text: lines.join("\n"),
11497                line_count_before,
11498                line_count_after: lines.len(),
11499            }
11500        });
11501    }
11502
11503    fn manipulate_mutable_lines<Fn>(
11504        &mut self,
11505        window: &mut Window,
11506        cx: &mut Context<Self>,
11507        mut callback: Fn,
11508    ) where
11509        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11510    {
11511        self.manipulate_lines(window, cx, |text| {
11512            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11513            let line_count_before = lines.len();
11514
11515            callback(&mut lines);
11516
11517            LineManipulationResult {
11518                new_text: lines.join("\n"),
11519                line_count_before,
11520                line_count_after: lines.len(),
11521            }
11522        });
11523    }
11524
11525    pub fn convert_indentation_to_spaces(
11526        &mut self,
11527        _: &ConvertIndentationToSpaces,
11528        window: &mut Window,
11529        cx: &mut Context<Self>,
11530    ) {
11531        let settings = self.buffer.read(cx).language_settings(cx);
11532        let tab_size = settings.tab_size.get() as usize;
11533
11534        self.manipulate_mutable_lines(window, cx, |lines| {
11535            // Allocates a reasonably sized scratch buffer once for the whole loop
11536            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11537            // Avoids recomputing spaces that could be inserted many times
11538            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11539                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11540                .collect();
11541
11542            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11543                let mut chars = line.as_ref().chars();
11544                let mut col = 0;
11545                let mut changed = false;
11546
11547                for ch in chars.by_ref() {
11548                    match ch {
11549                        ' ' => {
11550                            reindented_line.push(' ');
11551                            col += 1;
11552                        }
11553                        '\t' => {
11554                            // \t are converted to spaces depending on the current column
11555                            let spaces_len = tab_size - (col % tab_size);
11556                            reindented_line.extend(&space_cache[spaces_len - 1]);
11557                            col += spaces_len;
11558                            changed = true;
11559                        }
11560                        _ => {
11561                            // If we dont append before break, the character is consumed
11562                            reindented_line.push(ch);
11563                            break;
11564                        }
11565                    }
11566                }
11567
11568                if !changed {
11569                    reindented_line.clear();
11570                    continue;
11571                }
11572                // Append the rest of the line and replace old reference with new one
11573                reindented_line.extend(chars);
11574                *line = Cow::Owned(reindented_line.clone());
11575                reindented_line.clear();
11576            }
11577        });
11578    }
11579
11580    pub fn convert_indentation_to_tabs(
11581        &mut self,
11582        _: &ConvertIndentationToTabs,
11583        window: &mut Window,
11584        cx: &mut Context<Self>,
11585    ) {
11586        let settings = self.buffer.read(cx).language_settings(cx);
11587        let tab_size = settings.tab_size.get() as usize;
11588
11589        self.manipulate_mutable_lines(window, cx, |lines| {
11590            // Allocates a reasonably sized buffer once for the whole loop
11591            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11592            // Avoids recomputing spaces that could be inserted many times
11593            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11594                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11595                .collect();
11596
11597            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11598                let mut chars = line.chars();
11599                let mut spaces_count = 0;
11600                let mut first_non_indent_char = None;
11601                let mut changed = false;
11602
11603                for ch in chars.by_ref() {
11604                    match ch {
11605                        ' ' => {
11606                            // Keep track of spaces. Append \t when we reach tab_size
11607                            spaces_count += 1;
11608                            changed = true;
11609                            if spaces_count == tab_size {
11610                                reindented_line.push('\t');
11611                                spaces_count = 0;
11612                            }
11613                        }
11614                        '\t' => {
11615                            reindented_line.push('\t');
11616                            spaces_count = 0;
11617                        }
11618                        _ => {
11619                            // Dont append it yet, we might have remaining spaces
11620                            first_non_indent_char = Some(ch);
11621                            break;
11622                        }
11623                    }
11624                }
11625
11626                if !changed {
11627                    reindented_line.clear();
11628                    continue;
11629                }
11630                // Remaining spaces that didn't make a full tab stop
11631                if spaces_count > 0 {
11632                    reindented_line.extend(&space_cache[spaces_count - 1]);
11633                }
11634                // If we consume an extra character that was not indentation, add it back
11635                if let Some(extra_char) = first_non_indent_char {
11636                    reindented_line.push(extra_char);
11637                }
11638                // Append the rest of the line and replace old reference with new one
11639                reindented_line.extend(chars);
11640                *line = Cow::Owned(reindented_line.clone());
11641                reindented_line.clear();
11642            }
11643        });
11644    }
11645
11646    pub fn convert_to_upper_case(
11647        &mut self,
11648        _: &ConvertToUpperCase,
11649        window: &mut Window,
11650        cx: &mut Context<Self>,
11651    ) {
11652        self.manipulate_text(window, cx, |text| text.to_uppercase())
11653    }
11654
11655    pub fn convert_to_lower_case(
11656        &mut self,
11657        _: &ConvertToLowerCase,
11658        window: &mut Window,
11659        cx: &mut Context<Self>,
11660    ) {
11661        self.manipulate_text(window, cx, |text| text.to_lowercase())
11662    }
11663
11664    pub fn convert_to_title_case(
11665        &mut self,
11666        _: &ConvertToTitleCase,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.manipulate_text(window, cx, |text| {
11671            text.split('\n')
11672                .map(|line| line.to_case(Case::Title))
11673                .join("\n")
11674        })
11675    }
11676
11677    pub fn convert_to_snake_case(
11678        &mut self,
11679        _: &ConvertToSnakeCase,
11680        window: &mut Window,
11681        cx: &mut Context<Self>,
11682    ) {
11683        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11684    }
11685
11686    pub fn convert_to_kebab_case(
11687        &mut self,
11688        _: &ConvertToKebabCase,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11693    }
11694
11695    pub fn convert_to_upper_camel_case(
11696        &mut self,
11697        _: &ConvertToUpperCamelCase,
11698        window: &mut Window,
11699        cx: &mut Context<Self>,
11700    ) {
11701        self.manipulate_text(window, cx, |text| {
11702            text.split('\n')
11703                .map(|line| line.to_case(Case::UpperCamel))
11704                .join("\n")
11705        })
11706    }
11707
11708    pub fn convert_to_lower_camel_case(
11709        &mut self,
11710        _: &ConvertToLowerCamelCase,
11711        window: &mut Window,
11712        cx: &mut Context<Self>,
11713    ) {
11714        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11715    }
11716
11717    pub fn convert_to_opposite_case(
11718        &mut self,
11719        _: &ConvertToOppositeCase,
11720        window: &mut Window,
11721        cx: &mut Context<Self>,
11722    ) {
11723        self.manipulate_text(window, cx, |text| {
11724            text.chars()
11725                .fold(String::with_capacity(text.len()), |mut t, c| {
11726                    if c.is_uppercase() {
11727                        t.extend(c.to_lowercase());
11728                    } else {
11729                        t.extend(c.to_uppercase());
11730                    }
11731                    t
11732                })
11733        })
11734    }
11735
11736    pub fn convert_to_sentence_case(
11737        &mut self,
11738        _: &ConvertToSentenceCase,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11743    }
11744
11745    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11746        self.manipulate_text(window, cx, |text| {
11747            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11748            if has_upper_case_characters {
11749                text.to_lowercase()
11750            } else {
11751                text.to_uppercase()
11752            }
11753        })
11754    }
11755
11756    pub fn convert_to_rot13(
11757        &mut self,
11758        _: &ConvertToRot13,
11759        window: &mut Window,
11760        cx: &mut Context<Self>,
11761    ) {
11762        self.manipulate_text(window, cx, |text| {
11763            text.chars()
11764                .map(|c| match c {
11765                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11766                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11767                    _ => c,
11768                })
11769                .collect()
11770        })
11771    }
11772
11773    pub fn convert_to_rot47(
11774        &mut self,
11775        _: &ConvertToRot47,
11776        window: &mut Window,
11777        cx: &mut Context<Self>,
11778    ) {
11779        self.manipulate_text(window, cx, |text| {
11780            text.chars()
11781                .map(|c| {
11782                    let code_point = c as u32;
11783                    if code_point >= 33 && code_point <= 126 {
11784                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11785                    }
11786                    c
11787                })
11788                .collect()
11789        })
11790    }
11791
11792    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11793    where
11794        Fn: FnMut(&str) -> String,
11795    {
11796        let buffer = self.buffer.read(cx).snapshot(cx);
11797
11798        let mut new_selections = Vec::new();
11799        let mut edits = Vec::new();
11800        let mut selection_adjustment = 0isize;
11801
11802        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11803            let selection_is_empty = selection.is_empty();
11804
11805            let (start, end) = if selection_is_empty {
11806                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11807                (word_range.start, word_range.end)
11808            } else {
11809                (
11810                    buffer.point_to_offset(selection.start),
11811                    buffer.point_to_offset(selection.end),
11812                )
11813            };
11814
11815            let text = buffer.text_for_range(start..end).collect::<String>();
11816            let old_length = text.len() as isize;
11817            let text = callback(&text);
11818
11819            new_selections.push(Selection {
11820                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11821                end: MultiBufferOffset(
11822                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11823                ),
11824                goal: SelectionGoal::None,
11825                id: selection.id,
11826                reversed: selection.reversed,
11827            });
11828
11829            selection_adjustment += old_length - text.len() as isize;
11830
11831            edits.push((start..end, text));
11832        }
11833
11834        self.transact(window, cx, |this, window, cx| {
11835            this.buffer.update(cx, |buffer, cx| {
11836                buffer.edit(edits, None, cx);
11837            });
11838
11839            this.change_selections(Default::default(), window, cx, |s| {
11840                s.select(new_selections);
11841            });
11842
11843            this.request_autoscroll(Autoscroll::fit(), cx);
11844        });
11845    }
11846
11847    pub fn move_selection_on_drop(
11848        &mut self,
11849        selection: &Selection<Anchor>,
11850        target: DisplayPoint,
11851        is_cut: bool,
11852        window: &mut Window,
11853        cx: &mut Context<Self>,
11854    ) {
11855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11856        let buffer = display_map.buffer_snapshot();
11857        let mut edits = Vec::new();
11858        let insert_point = display_map
11859            .clip_point(target, Bias::Left)
11860            .to_point(&display_map);
11861        let text = buffer
11862            .text_for_range(selection.start..selection.end)
11863            .collect::<String>();
11864        if is_cut {
11865            edits.push(((selection.start..selection.end), String::new()));
11866        }
11867        let insert_anchor = buffer.anchor_before(insert_point);
11868        edits.push(((insert_anchor..insert_anchor), text));
11869        let last_edit_start = insert_anchor.bias_left(buffer);
11870        let last_edit_end = insert_anchor.bias_right(buffer);
11871        self.transact(window, cx, |this, window, cx| {
11872            this.buffer.update(cx, |buffer, cx| {
11873                buffer.edit(edits, None, cx);
11874            });
11875            this.change_selections(Default::default(), window, cx, |s| {
11876                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11877            });
11878        });
11879    }
11880
11881    pub fn clear_selection_drag_state(&mut self) {
11882        self.selection_drag_state = SelectionDragState::None;
11883    }
11884
11885    pub fn duplicate(
11886        &mut self,
11887        upwards: bool,
11888        whole_lines: bool,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11893
11894        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11895        let buffer = display_map.buffer_snapshot();
11896        let selections = self.selections.all::<Point>(&display_map);
11897
11898        let mut edits = Vec::new();
11899        let mut selections_iter = selections.iter().peekable();
11900        while let Some(selection) = selections_iter.next() {
11901            let mut rows = selection.spanned_rows(false, &display_map);
11902            // duplicate line-wise
11903            if whole_lines || selection.start == selection.end {
11904                // Avoid duplicating the same lines twice.
11905                while let Some(next_selection) = selections_iter.peek() {
11906                    let next_rows = next_selection.spanned_rows(false, &display_map);
11907                    if next_rows.start < rows.end {
11908                        rows.end = next_rows.end;
11909                        selections_iter.next().unwrap();
11910                    } else {
11911                        break;
11912                    }
11913                }
11914
11915                // Copy the text from the selected row region and splice it either at the start
11916                // or end of the region.
11917                let start = Point::new(rows.start.0, 0);
11918                let end = Point::new(
11919                    rows.end.previous_row().0,
11920                    buffer.line_len(rows.end.previous_row()),
11921                );
11922
11923                let mut text = buffer.text_for_range(start..end).collect::<String>();
11924
11925                let insert_location = if upwards {
11926                    // When duplicating upward, we need to insert before the current line.
11927                    // If we're on the last line and it doesn't end with a newline,
11928                    // we need to add a newline before the duplicated content.
11929                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11930                        && buffer.max_point().column > 0
11931                        && !text.ends_with('\n');
11932
11933                    if needs_leading_newline {
11934                        text.insert(0, '\n');
11935                        end
11936                    } else {
11937                        text.push('\n');
11938                        Point::new(rows.start.0, 0)
11939                    }
11940                } else {
11941                    text.push('\n');
11942                    start
11943                };
11944                edits.push((insert_location..insert_location, text));
11945            } else {
11946                // duplicate character-wise
11947                let start = selection.start;
11948                let end = selection.end;
11949                let text = buffer.text_for_range(start..end).collect::<String>();
11950                edits.push((selection.end..selection.end, text));
11951            }
11952        }
11953
11954        self.transact(window, cx, |this, window, cx| {
11955            this.buffer.update(cx, |buffer, cx| {
11956                buffer.edit(edits, None, cx);
11957            });
11958
11959            // When duplicating upward with whole lines, move the cursor to the duplicated line
11960            if upwards && whole_lines {
11961                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11962
11963                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11964                    let mut new_ranges = Vec::new();
11965                    let selections = s.all::<Point>(&display_map);
11966                    let mut selections_iter = selections.iter().peekable();
11967
11968                    while let Some(first_selection) = selections_iter.next() {
11969                        // Group contiguous selections together to find the total row span
11970                        let mut group_selections = vec![first_selection];
11971                        let mut rows = first_selection.spanned_rows(false, &display_map);
11972
11973                        while let Some(next_selection) = selections_iter.peek() {
11974                            let next_rows = next_selection.spanned_rows(false, &display_map);
11975                            if next_rows.start < rows.end {
11976                                rows.end = next_rows.end;
11977                                group_selections.push(selections_iter.next().unwrap());
11978                            } else {
11979                                break;
11980                            }
11981                        }
11982
11983                        let row_count = rows.end.0 - rows.start.0;
11984
11985                        // Move all selections in this group up by the total number of duplicated rows
11986                        for selection in group_selections {
11987                            let new_start = Point::new(
11988                                selection.start.row.saturating_sub(row_count),
11989                                selection.start.column,
11990                            );
11991
11992                            let new_end = Point::new(
11993                                selection.end.row.saturating_sub(row_count),
11994                                selection.end.column,
11995                            );
11996
11997                            new_ranges.push(new_start..new_end);
11998                        }
11999                    }
12000
12001                    s.select_ranges(new_ranges);
12002                });
12003            }
12004
12005            this.request_autoscroll(Autoscroll::fit(), cx);
12006        });
12007    }
12008
12009    pub fn duplicate_line_up(
12010        &mut self,
12011        _: &DuplicateLineUp,
12012        window: &mut Window,
12013        cx: &mut Context<Self>,
12014    ) {
12015        self.duplicate(true, true, window, cx);
12016    }
12017
12018    pub fn duplicate_line_down(
12019        &mut self,
12020        _: &DuplicateLineDown,
12021        window: &mut Window,
12022        cx: &mut Context<Self>,
12023    ) {
12024        self.duplicate(false, true, window, cx);
12025    }
12026
12027    pub fn duplicate_selection(
12028        &mut self,
12029        _: &DuplicateSelection,
12030        window: &mut Window,
12031        cx: &mut Context<Self>,
12032    ) {
12033        self.duplicate(false, false, window, cx);
12034    }
12035
12036    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12037        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12038        if self.mode.is_single_line() {
12039            cx.propagate();
12040            return;
12041        }
12042
12043        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12044        let buffer = self.buffer.read(cx).snapshot(cx);
12045
12046        let mut edits = Vec::new();
12047        let mut unfold_ranges = Vec::new();
12048        let mut refold_creases = Vec::new();
12049
12050        let selections = self.selections.all::<Point>(&display_map);
12051        let mut selections = selections.iter().peekable();
12052        let mut contiguous_row_selections = Vec::new();
12053        let mut new_selections = Vec::new();
12054
12055        while let Some(selection) = selections.next() {
12056            // Find all the selections that span a contiguous row range
12057            let (start_row, end_row) = consume_contiguous_rows(
12058                &mut contiguous_row_selections,
12059                selection,
12060                &display_map,
12061                &mut selections,
12062            );
12063
12064            // Move the text spanned by the row range to be before the line preceding the row range
12065            if start_row.0 > 0 {
12066                let range_to_move = Point::new(
12067                    start_row.previous_row().0,
12068                    buffer.line_len(start_row.previous_row()),
12069                )
12070                    ..Point::new(
12071                        end_row.previous_row().0,
12072                        buffer.line_len(end_row.previous_row()),
12073                    );
12074                let insertion_point = display_map
12075                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12076                    .0;
12077
12078                // Don't move lines across excerpts
12079                if buffer
12080                    .excerpt_containing(insertion_point..range_to_move.end)
12081                    .is_some()
12082                {
12083                    let text = buffer
12084                        .text_for_range(range_to_move.clone())
12085                        .flat_map(|s| s.chars())
12086                        .skip(1)
12087                        .chain(['\n'])
12088                        .collect::<String>();
12089
12090                    edits.push((
12091                        buffer.anchor_after(range_to_move.start)
12092                            ..buffer.anchor_before(range_to_move.end),
12093                        String::new(),
12094                    ));
12095                    let insertion_anchor = buffer.anchor_after(insertion_point);
12096                    edits.push((insertion_anchor..insertion_anchor, text));
12097
12098                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12099
12100                    // Move selections up
12101                    new_selections.extend(contiguous_row_selections.drain(..).map(
12102                        |mut selection| {
12103                            selection.start.row -= row_delta;
12104                            selection.end.row -= row_delta;
12105                            selection
12106                        },
12107                    ));
12108
12109                    // Move folds up
12110                    unfold_ranges.push(range_to_move.clone());
12111                    for fold in display_map.folds_in_range(
12112                        buffer.anchor_before(range_to_move.start)
12113                            ..buffer.anchor_after(range_to_move.end),
12114                    ) {
12115                        let mut start = fold.range.start.to_point(&buffer);
12116                        let mut end = fold.range.end.to_point(&buffer);
12117                        start.row -= row_delta;
12118                        end.row -= row_delta;
12119                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12120                    }
12121                }
12122            }
12123
12124            // If we didn't move line(s), preserve the existing selections
12125            new_selections.append(&mut contiguous_row_selections);
12126        }
12127
12128        self.transact(window, cx, |this, window, cx| {
12129            this.unfold_ranges(&unfold_ranges, true, true, cx);
12130            this.buffer.update(cx, |buffer, cx| {
12131                for (range, text) in edits {
12132                    buffer.edit([(range, text)], None, cx);
12133                }
12134            });
12135            this.fold_creases(refold_creases, true, window, cx);
12136            this.change_selections(Default::default(), window, cx, |s| {
12137                s.select(new_selections);
12138            })
12139        });
12140    }
12141
12142    pub fn move_line_down(
12143        &mut self,
12144        _: &MoveLineDown,
12145        window: &mut Window,
12146        cx: &mut Context<Self>,
12147    ) {
12148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12149        if self.mode.is_single_line() {
12150            cx.propagate();
12151            return;
12152        }
12153
12154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12155        let buffer = self.buffer.read(cx).snapshot(cx);
12156
12157        let mut edits = Vec::new();
12158        let mut unfold_ranges = Vec::new();
12159        let mut refold_creases = Vec::new();
12160
12161        let selections = self.selections.all::<Point>(&display_map);
12162        let mut selections = selections.iter().peekable();
12163        let mut contiguous_row_selections = Vec::new();
12164        let mut new_selections = Vec::new();
12165
12166        while let Some(selection) = selections.next() {
12167            // Find all the selections that span a contiguous row range
12168            let (start_row, end_row) = consume_contiguous_rows(
12169                &mut contiguous_row_selections,
12170                selection,
12171                &display_map,
12172                &mut selections,
12173            );
12174
12175            // Move the text spanned by the row range to be after the last line of the row range
12176            if end_row.0 <= buffer.max_point().row {
12177                let range_to_move =
12178                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12179                let insertion_point = display_map
12180                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12181                    .0;
12182
12183                // Don't move lines across excerpt boundaries
12184                if buffer
12185                    .excerpt_containing(range_to_move.start..insertion_point)
12186                    .is_some()
12187                {
12188                    let mut text = String::from("\n");
12189                    text.extend(buffer.text_for_range(range_to_move.clone()));
12190                    text.pop(); // Drop trailing newline
12191                    edits.push((
12192                        buffer.anchor_after(range_to_move.start)
12193                            ..buffer.anchor_before(range_to_move.end),
12194                        String::new(),
12195                    ));
12196                    let insertion_anchor = buffer.anchor_after(insertion_point);
12197                    edits.push((insertion_anchor..insertion_anchor, text));
12198
12199                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12200
12201                    // Move selections down
12202                    new_selections.extend(contiguous_row_selections.drain(..).map(
12203                        |mut selection| {
12204                            selection.start.row += row_delta;
12205                            selection.end.row += row_delta;
12206                            selection
12207                        },
12208                    ));
12209
12210                    // Move folds down
12211                    unfold_ranges.push(range_to_move.clone());
12212                    for fold in display_map.folds_in_range(
12213                        buffer.anchor_before(range_to_move.start)
12214                            ..buffer.anchor_after(range_to_move.end),
12215                    ) {
12216                        let mut start = fold.range.start.to_point(&buffer);
12217                        let mut end = fold.range.end.to_point(&buffer);
12218                        start.row += row_delta;
12219                        end.row += row_delta;
12220                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12221                    }
12222                }
12223            }
12224
12225            // If we didn't move line(s), preserve the existing selections
12226            new_selections.append(&mut contiguous_row_selections);
12227        }
12228
12229        self.transact(window, cx, |this, window, cx| {
12230            this.unfold_ranges(&unfold_ranges, true, true, cx);
12231            this.buffer.update(cx, |buffer, cx| {
12232                for (range, text) in edits {
12233                    buffer.edit([(range, text)], None, cx);
12234                }
12235            });
12236            this.fold_creases(refold_creases, true, window, cx);
12237            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12238        });
12239    }
12240
12241    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12243        let text_layout_details = &self.text_layout_details(window);
12244        self.transact(window, cx, |this, window, cx| {
12245            let edits = this.change_selections(Default::default(), window, cx, |s| {
12246                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12247                s.move_with(|display_map, selection| {
12248                    if !selection.is_empty() {
12249                        return;
12250                    }
12251
12252                    let mut head = selection.head();
12253                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12254                    if head.column() == display_map.line_len(head.row()) {
12255                        transpose_offset = display_map
12256                            .buffer_snapshot()
12257                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12258                    }
12259
12260                    if transpose_offset == MultiBufferOffset(0) {
12261                        return;
12262                    }
12263
12264                    *head.column_mut() += 1;
12265                    head = display_map.clip_point(head, Bias::Right);
12266                    let goal = SelectionGoal::HorizontalPosition(
12267                        display_map
12268                            .x_for_display_point(head, text_layout_details)
12269                            .into(),
12270                    );
12271                    selection.collapse_to(head, goal);
12272
12273                    let transpose_start = display_map
12274                        .buffer_snapshot()
12275                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12276                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12277                        let transpose_end = display_map
12278                            .buffer_snapshot()
12279                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12280                        if let Some(ch) = display_map
12281                            .buffer_snapshot()
12282                            .chars_at(transpose_start)
12283                            .next()
12284                        {
12285                            edits.push((transpose_start..transpose_offset, String::new()));
12286                            edits.push((transpose_end..transpose_end, ch.to_string()));
12287                        }
12288                    }
12289                });
12290                edits
12291            });
12292            this.buffer
12293                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12294            let selections = this
12295                .selections
12296                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12297            this.change_selections(Default::default(), window, cx, |s| {
12298                s.select(selections);
12299            });
12300        });
12301    }
12302
12303    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12305        if self.mode.is_single_line() {
12306            cx.propagate();
12307            return;
12308        }
12309
12310        self.rewrap_impl(RewrapOptions::default(), cx)
12311    }
12312
12313    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12314        let buffer = self.buffer.read(cx).snapshot(cx);
12315        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12316
12317        #[derive(Clone, Debug, PartialEq)]
12318        enum CommentFormat {
12319            /// single line comment, with prefix for line
12320            Line(String),
12321            /// single line within a block comment, with prefix for line
12322            BlockLine(String),
12323            /// a single line of a block comment that includes the initial delimiter
12324            BlockCommentWithStart(BlockCommentConfig),
12325            /// a single line of a block comment that includes the ending delimiter
12326            BlockCommentWithEnd(BlockCommentConfig),
12327        }
12328
12329        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12330        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12331            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12332                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12333                .peekable();
12334
12335            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12336                row
12337            } else {
12338                return Vec::new();
12339            };
12340
12341            let language_settings = buffer.language_settings_at(selection.head(), cx);
12342            let language_scope = buffer.language_scope_at(selection.head());
12343
12344            let indent_and_prefix_for_row =
12345                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12346                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12347                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12348                        &language_scope
12349                    {
12350                        let indent_end = Point::new(row, indent.len);
12351                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12352                        let line_text_after_indent = buffer
12353                            .text_for_range(indent_end..line_end)
12354                            .collect::<String>();
12355
12356                        let is_within_comment_override = buffer
12357                            .language_scope_at(indent_end)
12358                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12359                        let comment_delimiters = if is_within_comment_override {
12360                            // we are within a comment syntax node, but we don't
12361                            // yet know what kind of comment: block, doc or line
12362                            match (
12363                                language_scope.documentation_comment(),
12364                                language_scope.block_comment(),
12365                            ) {
12366                                (Some(config), _) | (_, Some(config))
12367                                    if buffer.contains_str_at(indent_end, &config.start) =>
12368                                {
12369                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12370                                }
12371                                (Some(config), _) | (_, Some(config))
12372                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12373                                {
12374                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12375                                }
12376                                (Some(config), _) | (_, Some(config))
12377                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12378                                {
12379                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12380                                }
12381                                (_, _) => language_scope
12382                                    .line_comment_prefixes()
12383                                    .iter()
12384                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12385                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12386                            }
12387                        } else {
12388                            // we not in an overridden comment node, but we may
12389                            // be within a non-overridden line comment node
12390                            language_scope
12391                                .line_comment_prefixes()
12392                                .iter()
12393                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12394                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12395                        };
12396
12397                        let rewrap_prefix = language_scope
12398                            .rewrap_prefixes()
12399                            .iter()
12400                            .find_map(|prefix_regex| {
12401                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12402                                    if mat.start() == 0 {
12403                                        Some(mat.as_str().to_string())
12404                                    } else {
12405                                        None
12406                                    }
12407                                })
12408                            })
12409                            .flatten();
12410                        (comment_delimiters, rewrap_prefix)
12411                    } else {
12412                        (None, None)
12413                    };
12414                    (indent, comment_prefix, rewrap_prefix)
12415                };
12416
12417            let mut ranges = Vec::new();
12418            let from_empty_selection = selection.is_empty();
12419
12420            let mut current_range_start = first_row;
12421            let mut prev_row = first_row;
12422            let (
12423                mut current_range_indent,
12424                mut current_range_comment_delimiters,
12425                mut current_range_rewrap_prefix,
12426            ) = indent_and_prefix_for_row(first_row);
12427
12428            for row in non_blank_rows_iter.skip(1) {
12429                let has_paragraph_break = row > prev_row + 1;
12430
12431                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12432                    indent_and_prefix_for_row(row);
12433
12434                let has_indent_change = row_indent != current_range_indent;
12435                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12436
12437                let has_boundary_change = has_comment_change
12438                    || row_rewrap_prefix.is_some()
12439                    || (has_indent_change && current_range_comment_delimiters.is_some());
12440
12441                if has_paragraph_break || has_boundary_change {
12442                    ranges.push((
12443                        language_settings.clone(),
12444                        Point::new(current_range_start, 0)
12445                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12446                        current_range_indent,
12447                        current_range_comment_delimiters.clone(),
12448                        current_range_rewrap_prefix.clone(),
12449                        from_empty_selection,
12450                    ));
12451                    current_range_start = row;
12452                    current_range_indent = row_indent;
12453                    current_range_comment_delimiters = row_comment_delimiters;
12454                    current_range_rewrap_prefix = row_rewrap_prefix;
12455                }
12456                prev_row = row;
12457            }
12458
12459            ranges.push((
12460                language_settings.clone(),
12461                Point::new(current_range_start, 0)
12462                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12463                current_range_indent,
12464                current_range_comment_delimiters,
12465                current_range_rewrap_prefix,
12466                from_empty_selection,
12467            ));
12468
12469            ranges
12470        });
12471
12472        let mut edits = Vec::new();
12473        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12474
12475        for (
12476            language_settings,
12477            wrap_range,
12478            mut indent_size,
12479            comment_prefix,
12480            rewrap_prefix,
12481            from_empty_selection,
12482        ) in wrap_ranges
12483        {
12484            let mut start_row = wrap_range.start.row;
12485            let mut end_row = wrap_range.end.row;
12486
12487            // Skip selections that overlap with a range that has already been rewrapped.
12488            let selection_range = start_row..end_row;
12489            if rewrapped_row_ranges
12490                .iter()
12491                .any(|range| range.overlaps(&selection_range))
12492            {
12493                continue;
12494            }
12495
12496            let tab_size = language_settings.tab_size;
12497
12498            let (line_prefix, inside_comment) = match &comment_prefix {
12499                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12500                    (Some(prefix.as_str()), true)
12501                }
12502                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12503                    (Some(prefix.as_ref()), true)
12504                }
12505                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12506                    start: _,
12507                    end: _,
12508                    prefix,
12509                    tab_size,
12510                })) => {
12511                    indent_size.len += tab_size;
12512                    (Some(prefix.as_ref()), true)
12513                }
12514                None => (None, false),
12515            };
12516            let indent_prefix = indent_size.chars().collect::<String>();
12517            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12518
12519            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12520                RewrapBehavior::InComments => inside_comment,
12521                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12522                RewrapBehavior::Anywhere => true,
12523            };
12524
12525            let should_rewrap = options.override_language_settings
12526                || allow_rewrap_based_on_language
12527                || self.hard_wrap.is_some();
12528            if !should_rewrap {
12529                continue;
12530            }
12531
12532            if from_empty_selection {
12533                'expand_upwards: while start_row > 0 {
12534                    let prev_row = start_row - 1;
12535                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12536                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12537                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12538                    {
12539                        start_row = prev_row;
12540                    } else {
12541                        break 'expand_upwards;
12542                    }
12543                }
12544
12545                'expand_downwards: while end_row < buffer.max_point().row {
12546                    let next_row = end_row + 1;
12547                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12548                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12549                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12550                    {
12551                        end_row = next_row;
12552                    } else {
12553                        break 'expand_downwards;
12554                    }
12555                }
12556            }
12557
12558            let start = Point::new(start_row, 0);
12559            let start_offset = ToOffset::to_offset(&start, &buffer);
12560            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12561            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12562            let mut first_line_delimiter = None;
12563            let mut last_line_delimiter = None;
12564            let Some(lines_without_prefixes) = selection_text
12565                .lines()
12566                .enumerate()
12567                .map(|(ix, line)| {
12568                    let line_trimmed = line.trim_start();
12569                    if rewrap_prefix.is_some() && ix > 0 {
12570                        Ok(line_trimmed)
12571                    } else if let Some(
12572                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12573                            start,
12574                            prefix,
12575                            end,
12576                            tab_size,
12577                        })
12578                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12579                            start,
12580                            prefix,
12581                            end,
12582                            tab_size,
12583                        }),
12584                    ) = &comment_prefix
12585                    {
12586                        let line_trimmed = line_trimmed
12587                            .strip_prefix(start.as_ref())
12588                            .map(|s| {
12589                                let mut indent_size = indent_size;
12590                                indent_size.len -= tab_size;
12591                                let indent_prefix: String = indent_size.chars().collect();
12592                                first_line_delimiter = Some((indent_prefix, start));
12593                                s.trim_start()
12594                            })
12595                            .unwrap_or(line_trimmed);
12596                        let line_trimmed = line_trimmed
12597                            .strip_suffix(end.as_ref())
12598                            .map(|s| {
12599                                last_line_delimiter = Some(end);
12600                                s.trim_end()
12601                            })
12602                            .unwrap_or(line_trimmed);
12603                        let line_trimmed = line_trimmed
12604                            .strip_prefix(prefix.as_ref())
12605                            .unwrap_or(line_trimmed);
12606                        Ok(line_trimmed)
12607                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12608                        line_trimmed.strip_prefix(prefix).with_context(|| {
12609                            format!("line did not start with prefix {prefix:?}: {line:?}")
12610                        })
12611                    } else {
12612                        line_trimmed
12613                            .strip_prefix(&line_prefix.trim_start())
12614                            .with_context(|| {
12615                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12616                            })
12617                    }
12618                })
12619                .collect::<Result<Vec<_>, _>>()
12620                .log_err()
12621            else {
12622                continue;
12623            };
12624
12625            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12626                buffer
12627                    .language_settings_at(Point::new(start_row, 0), cx)
12628                    .preferred_line_length as usize
12629            });
12630
12631            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12632                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12633            } else {
12634                line_prefix.clone()
12635            };
12636
12637            let wrapped_text = {
12638                let mut wrapped_text = wrap_with_prefix(
12639                    line_prefix,
12640                    subsequent_lines_prefix,
12641                    lines_without_prefixes.join("\n"),
12642                    wrap_column,
12643                    tab_size,
12644                    options.preserve_existing_whitespace,
12645                );
12646
12647                if let Some((indent, delimiter)) = first_line_delimiter {
12648                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12649                }
12650                if let Some(last_line) = last_line_delimiter {
12651                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12652                }
12653
12654                wrapped_text
12655            };
12656
12657            // TODO: should always use char-based diff while still supporting cursor behavior that
12658            // matches vim.
12659            let mut diff_options = DiffOptions::default();
12660            if options.override_language_settings {
12661                diff_options.max_word_diff_len = 0;
12662                diff_options.max_word_diff_line_count = 0;
12663            } else {
12664                diff_options.max_word_diff_len = usize::MAX;
12665                diff_options.max_word_diff_line_count = usize::MAX;
12666            }
12667
12668            for (old_range, new_text) in
12669                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12670            {
12671                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12672                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12673                edits.push((edit_start..edit_end, new_text));
12674            }
12675
12676            rewrapped_row_ranges.push(start_row..=end_row);
12677        }
12678
12679        self.buffer
12680            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12681    }
12682
12683    pub fn cut_common(
12684        &mut self,
12685        cut_no_selection_line: bool,
12686        window: &mut Window,
12687        cx: &mut Context<Self>,
12688    ) -> ClipboardItem {
12689        let mut text = String::new();
12690        let buffer = self.buffer.read(cx).snapshot(cx);
12691        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12692        let mut clipboard_selections = Vec::with_capacity(selections.len());
12693        {
12694            let max_point = buffer.max_point();
12695            let mut is_first = true;
12696            let mut prev_selection_was_entire_line = false;
12697            for selection in &mut selections {
12698                let is_entire_line =
12699                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12700                if is_entire_line {
12701                    selection.start = Point::new(selection.start.row, 0);
12702                    if !selection.is_empty() && selection.end.column == 0 {
12703                        selection.end = cmp::min(max_point, selection.end);
12704                    } else {
12705                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12706                    }
12707                    selection.goal = SelectionGoal::None;
12708                }
12709                if is_first {
12710                    is_first = false;
12711                } else if !prev_selection_was_entire_line {
12712                    text += "\n";
12713                }
12714                prev_selection_was_entire_line = is_entire_line;
12715                let mut len = 0;
12716                for chunk in buffer.text_for_range(selection.start..selection.end) {
12717                    text.push_str(chunk);
12718                    len += chunk.len();
12719                }
12720                clipboard_selections.push(ClipboardSelection {
12721                    len,
12722                    is_entire_line,
12723                    first_line_indent: buffer
12724                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12725                        .len,
12726                });
12727            }
12728        }
12729
12730        self.transact(window, cx, |this, window, cx| {
12731            this.change_selections(Default::default(), window, cx, |s| {
12732                s.select(selections);
12733            });
12734            this.insert("", window, cx);
12735        });
12736        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12737    }
12738
12739    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12741        let item = self.cut_common(true, window, cx);
12742        cx.write_to_clipboard(item);
12743    }
12744
12745    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12747        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12748            s.move_with(|snapshot, sel| {
12749                if sel.is_empty() {
12750                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12751                }
12752                if sel.is_empty() {
12753                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12754                }
12755            });
12756        });
12757        let item = self.cut_common(false, window, cx);
12758        cx.set_global(KillRing(item))
12759    }
12760
12761    pub fn kill_ring_yank(
12762        &mut self,
12763        _: &KillRingYank,
12764        window: &mut Window,
12765        cx: &mut Context<Self>,
12766    ) {
12767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12768        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12769            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12770                (kill_ring.text().to_string(), kill_ring.metadata_json())
12771            } else {
12772                return;
12773            }
12774        } else {
12775            return;
12776        };
12777        self.do_paste(&text, metadata, false, window, cx);
12778    }
12779
12780    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12781        self.do_copy(true, cx);
12782    }
12783
12784    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12785        self.do_copy(false, cx);
12786    }
12787
12788    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12789        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12790        let buffer = self.buffer.read(cx).read(cx);
12791        let mut text = String::new();
12792
12793        let mut clipboard_selections = Vec::with_capacity(selections.len());
12794        {
12795            let max_point = buffer.max_point();
12796            let mut is_first = true;
12797            let mut prev_selection_was_entire_line = false;
12798            for selection in &selections {
12799                let mut start = selection.start;
12800                let mut end = selection.end;
12801                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12802                let mut add_trailing_newline = false;
12803                if is_entire_line {
12804                    start = Point::new(start.row, 0);
12805                    let next_line_start = Point::new(end.row + 1, 0);
12806                    if next_line_start <= max_point {
12807                        end = next_line_start;
12808                    } else {
12809                        // We're on the last line without a trailing newline.
12810                        // Copy to the end of the line and add a newline afterwards.
12811                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12812                        add_trailing_newline = true;
12813                    }
12814                }
12815
12816                let mut trimmed_selections = Vec::new();
12817                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12818                    let row = MultiBufferRow(start.row);
12819                    let first_indent = buffer.indent_size_for_line(row);
12820                    if first_indent.len == 0 || start.column > first_indent.len {
12821                        trimmed_selections.push(start..end);
12822                    } else {
12823                        trimmed_selections.push(
12824                            Point::new(row.0, first_indent.len)
12825                                ..Point::new(row.0, buffer.line_len(row)),
12826                        );
12827                        for row in start.row + 1..=end.row {
12828                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12829                            if row == end.row {
12830                                line_len = end.column;
12831                            }
12832                            if line_len == 0 {
12833                                trimmed_selections
12834                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12835                                continue;
12836                            }
12837                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12838                            if row_indent_size.len >= first_indent.len {
12839                                trimmed_selections.push(
12840                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12841                                );
12842                            } else {
12843                                trimmed_selections.clear();
12844                                trimmed_selections.push(start..end);
12845                                break;
12846                            }
12847                        }
12848                    }
12849                } else {
12850                    trimmed_selections.push(start..end);
12851                }
12852
12853                for trimmed_range in trimmed_selections {
12854                    if is_first {
12855                        is_first = false;
12856                    } else if !prev_selection_was_entire_line {
12857                        text += "\n";
12858                    }
12859                    prev_selection_was_entire_line = is_entire_line;
12860                    let mut len = 0;
12861                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12862                        text.push_str(chunk);
12863                        len += chunk.len();
12864                    }
12865                    if add_trailing_newline {
12866                        text.push('\n');
12867                        len += 1;
12868                    }
12869                    clipboard_selections.push(ClipboardSelection {
12870                        len,
12871                        is_entire_line,
12872                        first_line_indent: buffer
12873                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12874                            .len,
12875                    });
12876                }
12877            }
12878        }
12879
12880        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12881            text,
12882            clipboard_selections,
12883        ));
12884    }
12885
12886    pub fn do_paste(
12887        &mut self,
12888        text: &String,
12889        clipboard_selections: Option<Vec<ClipboardSelection>>,
12890        handle_entire_lines: bool,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        if self.read_only(cx) {
12895            return;
12896        }
12897
12898        let clipboard_text = Cow::Borrowed(text.as_str());
12899
12900        self.transact(window, cx, |this, window, cx| {
12901            let had_active_edit_prediction = this.has_active_edit_prediction();
12902            let display_map = this.display_snapshot(cx);
12903            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12904            let cursor_offset = this
12905                .selections
12906                .last::<MultiBufferOffset>(&display_map)
12907                .head();
12908
12909            if let Some(mut clipboard_selections) = clipboard_selections {
12910                let all_selections_were_entire_line =
12911                    clipboard_selections.iter().all(|s| s.is_entire_line);
12912                let first_selection_indent_column =
12913                    clipboard_selections.first().map(|s| s.first_line_indent);
12914                if clipboard_selections.len() != old_selections.len() {
12915                    clipboard_selections.drain(..);
12916                }
12917                let mut auto_indent_on_paste = true;
12918
12919                this.buffer.update(cx, |buffer, cx| {
12920                    let snapshot = buffer.read(cx);
12921                    auto_indent_on_paste = snapshot
12922                        .language_settings_at(cursor_offset, cx)
12923                        .auto_indent_on_paste;
12924
12925                    let mut start_offset = 0;
12926                    let mut edits = Vec::new();
12927                    let mut original_indent_columns = Vec::new();
12928                    for (ix, selection) in old_selections.iter().enumerate() {
12929                        let to_insert;
12930                        let entire_line;
12931                        let original_indent_column;
12932                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12933                            let end_offset = start_offset + clipboard_selection.len;
12934                            to_insert = &clipboard_text[start_offset..end_offset];
12935                            entire_line = clipboard_selection.is_entire_line;
12936                            start_offset = if entire_line {
12937                                end_offset
12938                            } else {
12939                                end_offset + 1
12940                            };
12941                            original_indent_column = Some(clipboard_selection.first_line_indent);
12942                        } else {
12943                            to_insert = &*clipboard_text;
12944                            entire_line = all_selections_were_entire_line;
12945                            original_indent_column = first_selection_indent_column
12946                        }
12947
12948                        let (range, to_insert) =
12949                            if selection.is_empty() && handle_entire_lines && entire_line {
12950                                // If the corresponding selection was empty when this slice of the
12951                                // clipboard text was written, then the entire line containing the
12952                                // selection was copied. If this selection is also currently empty,
12953                                // then paste the line before the current line of the buffer.
12954                                let column = selection.start.to_point(&snapshot).column as usize;
12955                                let line_start = selection.start - column;
12956                                (line_start..line_start, Cow::Borrowed(to_insert))
12957                            } else {
12958                                let language = snapshot.language_at(selection.head());
12959                                let range = selection.range();
12960                                if let Some(language) = language
12961                                    && language.name() == "Markdown".into()
12962                                {
12963                                    edit_for_markdown_paste(
12964                                        &snapshot,
12965                                        range,
12966                                        to_insert,
12967                                        url::Url::parse(to_insert).ok(),
12968                                    )
12969                                } else {
12970                                    (range, Cow::Borrowed(to_insert))
12971                                }
12972                            };
12973
12974                        edits.push((range, to_insert));
12975                        original_indent_columns.push(original_indent_column);
12976                    }
12977                    drop(snapshot);
12978
12979                    buffer.edit(
12980                        edits,
12981                        if auto_indent_on_paste {
12982                            Some(AutoindentMode::Block {
12983                                original_indent_columns,
12984                            })
12985                        } else {
12986                            None
12987                        },
12988                        cx,
12989                    );
12990                });
12991
12992                let selections = this
12993                    .selections
12994                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12995                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12996            } else {
12997                let url = url::Url::parse(&clipboard_text).ok();
12998
12999                let auto_indent_mode = if !clipboard_text.is_empty() {
13000                    Some(AutoindentMode::Block {
13001                        original_indent_columns: Vec::new(),
13002                    })
13003                } else {
13004                    None
13005                };
13006
13007                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13008                    let snapshot = buffer.snapshot(cx);
13009
13010                    let anchors = old_selections
13011                        .iter()
13012                        .map(|s| {
13013                            let anchor = snapshot.anchor_after(s.head());
13014                            s.map(|_| anchor)
13015                        })
13016                        .collect::<Vec<_>>();
13017
13018                    let mut edits = Vec::new();
13019
13020                    for selection in old_selections.iter() {
13021                        let language = snapshot.language_at(selection.head());
13022                        let range = selection.range();
13023
13024                        let (edit_range, edit_text) = if let Some(language) = language
13025                            && language.name() == "Markdown".into()
13026                        {
13027                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13028                        } else {
13029                            (range, clipboard_text.clone())
13030                        };
13031
13032                        edits.push((edit_range, edit_text));
13033                    }
13034
13035                    drop(snapshot);
13036                    buffer.edit(edits, auto_indent_mode, cx);
13037
13038                    anchors
13039                });
13040
13041                this.change_selections(Default::default(), window, cx, |s| {
13042                    s.select_anchors(selection_anchors);
13043                });
13044            }
13045
13046            //   🤔                 |    ..     | show_in_menu |
13047            // | ..                  |   true        true
13048            // | had_edit_prediction |   false       true
13049
13050            let trigger_in_words =
13051                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13052
13053            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13054        });
13055    }
13056
13057    pub fn diff_clipboard_with_selection(
13058        &mut self,
13059        _: &DiffClipboardWithSelection,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        let selections = self
13064            .selections
13065            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13066
13067        if selections.is_empty() {
13068            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13069            return;
13070        };
13071
13072        let clipboard_text = match cx.read_from_clipboard() {
13073            Some(item) => match item.entries().first() {
13074                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13075                _ => None,
13076            },
13077            None => None,
13078        };
13079
13080        let Some(clipboard_text) = clipboard_text else {
13081            log::warn!("Clipboard doesn't contain text.");
13082            return;
13083        };
13084
13085        window.dispatch_action(
13086            Box::new(DiffClipboardWithSelectionData {
13087                clipboard_text,
13088                editor: cx.entity(),
13089            }),
13090            cx,
13091        );
13092    }
13093
13094    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13096        if let Some(item) = cx.read_from_clipboard() {
13097            let entries = item.entries();
13098
13099            match entries.first() {
13100                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13101                // of all the pasted entries.
13102                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13103                    .do_paste(
13104                        clipboard_string.text(),
13105                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13106                        true,
13107                        window,
13108                        cx,
13109                    ),
13110                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13111            }
13112        }
13113    }
13114
13115    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13116        if self.read_only(cx) {
13117            return;
13118        }
13119
13120        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13121
13122        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13123            if let Some((selections, _)) =
13124                self.selection_history.transaction(transaction_id).cloned()
13125            {
13126                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13127                    s.select_anchors(selections.to_vec());
13128                });
13129            } else {
13130                log::error!(
13131                    "No entry in selection_history found for undo. \
13132                     This may correspond to a bug where undo does not update the selection. \
13133                     If this is occurring, please add details to \
13134                     https://github.com/zed-industries/zed/issues/22692"
13135                );
13136            }
13137            self.request_autoscroll(Autoscroll::fit(), cx);
13138            self.unmark_text(window, cx);
13139            self.refresh_edit_prediction(true, false, window, cx);
13140            cx.emit(EditorEvent::Edited { transaction_id });
13141            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13142        }
13143    }
13144
13145    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13146        if self.read_only(cx) {
13147            return;
13148        }
13149
13150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13151
13152        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13153            if let Some((_, Some(selections))) =
13154                self.selection_history.transaction(transaction_id).cloned()
13155            {
13156                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13157                    s.select_anchors(selections.to_vec());
13158                });
13159            } else {
13160                log::error!(
13161                    "No entry in selection_history found for redo. \
13162                     This may correspond to a bug where undo does not update the selection. \
13163                     If this is occurring, please add details to \
13164                     https://github.com/zed-industries/zed/issues/22692"
13165                );
13166            }
13167            self.request_autoscroll(Autoscroll::fit(), cx);
13168            self.unmark_text(window, cx);
13169            self.refresh_edit_prediction(true, false, window, cx);
13170            cx.emit(EditorEvent::Edited { transaction_id });
13171        }
13172    }
13173
13174    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13175        self.buffer
13176            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13177    }
13178
13179    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13180        self.buffer
13181            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13182    }
13183
13184    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13186        self.change_selections(Default::default(), window, cx, |s| {
13187            s.move_with(|map, selection| {
13188                let cursor = if selection.is_empty() {
13189                    movement::left(map, selection.start)
13190                } else {
13191                    selection.start
13192                };
13193                selection.collapse_to(cursor, SelectionGoal::None);
13194            });
13195        })
13196    }
13197
13198    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13200        self.change_selections(Default::default(), window, cx, |s| {
13201            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13202        })
13203    }
13204
13205    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13207        self.change_selections(Default::default(), window, cx, |s| {
13208            s.move_with(|map, selection| {
13209                let cursor = if selection.is_empty() {
13210                    movement::right(map, selection.end)
13211                } else {
13212                    selection.end
13213                };
13214                selection.collapse_to(cursor, SelectionGoal::None)
13215            });
13216        })
13217    }
13218
13219    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13221        self.change_selections(Default::default(), window, cx, |s| {
13222            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13223        });
13224    }
13225
13226    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13227        if self.take_rename(true, window, cx).is_some() {
13228            return;
13229        }
13230
13231        if self.mode.is_single_line() {
13232            cx.propagate();
13233            return;
13234        }
13235
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13237
13238        let text_layout_details = &self.text_layout_details(window);
13239        let selection_count = self.selections.count();
13240        let first_selection = self.selections.first_anchor();
13241
13242        self.change_selections(Default::default(), window, cx, |s| {
13243            s.move_with(|map, selection| {
13244                if !selection.is_empty() {
13245                    selection.goal = SelectionGoal::None;
13246                }
13247                let (cursor, goal) = movement::up(
13248                    map,
13249                    selection.start,
13250                    selection.goal,
13251                    false,
13252                    text_layout_details,
13253                );
13254                selection.collapse_to(cursor, goal);
13255            });
13256        });
13257
13258        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13259        {
13260            cx.propagate();
13261        }
13262    }
13263
13264    pub fn move_up_by_lines(
13265        &mut self,
13266        action: &MoveUpByLines,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        if self.take_rename(true, window, cx).is_some() {
13271            return;
13272        }
13273
13274        if self.mode.is_single_line() {
13275            cx.propagate();
13276            return;
13277        }
13278
13279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13280
13281        let text_layout_details = &self.text_layout_details(window);
13282
13283        self.change_selections(Default::default(), window, cx, |s| {
13284            s.move_with(|map, selection| {
13285                if !selection.is_empty() {
13286                    selection.goal = SelectionGoal::None;
13287                }
13288                let (cursor, goal) = movement::up_by_rows(
13289                    map,
13290                    selection.start,
13291                    action.lines,
13292                    selection.goal,
13293                    false,
13294                    text_layout_details,
13295                );
13296                selection.collapse_to(cursor, goal);
13297            });
13298        })
13299    }
13300
13301    pub fn move_down_by_lines(
13302        &mut self,
13303        action: &MoveDownByLines,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        if self.take_rename(true, window, cx).is_some() {
13308            return;
13309        }
13310
13311        if self.mode.is_single_line() {
13312            cx.propagate();
13313            return;
13314        }
13315
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317
13318        let text_layout_details = &self.text_layout_details(window);
13319
13320        self.change_selections(Default::default(), window, cx, |s| {
13321            s.move_with(|map, selection| {
13322                if !selection.is_empty() {
13323                    selection.goal = SelectionGoal::None;
13324                }
13325                let (cursor, goal) = movement::down_by_rows(
13326                    map,
13327                    selection.start,
13328                    action.lines,
13329                    selection.goal,
13330                    false,
13331                    text_layout_details,
13332                );
13333                selection.collapse_to(cursor, goal);
13334            });
13335        })
13336    }
13337
13338    pub fn select_down_by_lines(
13339        &mut self,
13340        action: &SelectDownByLines,
13341        window: &mut Window,
13342        cx: &mut Context<Self>,
13343    ) {
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345        let text_layout_details = &self.text_layout_details(window);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_heads_with(|map, head, goal| {
13348                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13349            })
13350        })
13351    }
13352
13353    pub fn select_up_by_lines(
13354        &mut self,
13355        action: &SelectUpByLines,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13360        let text_layout_details = &self.text_layout_details(window);
13361        self.change_selections(Default::default(), window, cx, |s| {
13362            s.move_heads_with(|map, head, goal| {
13363                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13364            })
13365        })
13366    }
13367
13368    pub fn select_page_up(
13369        &mut self,
13370        _: &SelectPageUp,
13371        window: &mut Window,
13372        cx: &mut Context<Self>,
13373    ) {
13374        let Some(row_count) = self.visible_row_count() else {
13375            return;
13376        };
13377
13378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13379
13380        let text_layout_details = &self.text_layout_details(window);
13381
13382        self.change_selections(Default::default(), window, cx, |s| {
13383            s.move_heads_with(|map, head, goal| {
13384                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13385            })
13386        })
13387    }
13388
13389    pub fn move_page_up(
13390        &mut self,
13391        action: &MovePageUp,
13392        window: &mut Window,
13393        cx: &mut Context<Self>,
13394    ) {
13395        if self.take_rename(true, window, cx).is_some() {
13396            return;
13397        }
13398
13399        if self
13400            .context_menu
13401            .borrow_mut()
13402            .as_mut()
13403            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13404            .unwrap_or(false)
13405        {
13406            return;
13407        }
13408
13409        if matches!(self.mode, EditorMode::SingleLine) {
13410            cx.propagate();
13411            return;
13412        }
13413
13414        let Some(row_count) = self.visible_row_count() else {
13415            return;
13416        };
13417
13418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13419
13420        let effects = if action.center_cursor {
13421            SelectionEffects::scroll(Autoscroll::center())
13422        } else {
13423            SelectionEffects::default()
13424        };
13425
13426        let text_layout_details = &self.text_layout_details(window);
13427
13428        self.change_selections(effects, window, cx, |s| {
13429            s.move_with(|map, selection| {
13430                if !selection.is_empty() {
13431                    selection.goal = SelectionGoal::None;
13432                }
13433                let (cursor, goal) = movement::up_by_rows(
13434                    map,
13435                    selection.end,
13436                    row_count,
13437                    selection.goal,
13438                    false,
13439                    text_layout_details,
13440                );
13441                selection.collapse_to(cursor, goal);
13442            });
13443        });
13444    }
13445
13446    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13448        let text_layout_details = &self.text_layout_details(window);
13449        self.change_selections(Default::default(), window, cx, |s| {
13450            s.move_heads_with(|map, head, goal| {
13451                movement::up(map, head, goal, false, text_layout_details)
13452            })
13453        })
13454    }
13455
13456    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13457        self.take_rename(true, window, cx);
13458
13459        if self.mode.is_single_line() {
13460            cx.propagate();
13461            return;
13462        }
13463
13464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13465
13466        let text_layout_details = &self.text_layout_details(window);
13467        let selection_count = self.selections.count();
13468        let first_selection = self.selections.first_anchor();
13469
13470        self.change_selections(Default::default(), window, cx, |s| {
13471            s.move_with(|map, selection| {
13472                if !selection.is_empty() {
13473                    selection.goal = SelectionGoal::None;
13474                }
13475                let (cursor, goal) = movement::down(
13476                    map,
13477                    selection.end,
13478                    selection.goal,
13479                    false,
13480                    text_layout_details,
13481                );
13482                selection.collapse_to(cursor, goal);
13483            });
13484        });
13485
13486        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13487        {
13488            cx.propagate();
13489        }
13490    }
13491
13492    pub fn select_page_down(
13493        &mut self,
13494        _: &SelectPageDown,
13495        window: &mut Window,
13496        cx: &mut Context<Self>,
13497    ) {
13498        let Some(row_count) = self.visible_row_count() else {
13499            return;
13500        };
13501
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503
13504        let text_layout_details = &self.text_layout_details(window);
13505
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_heads_with(|map, head, goal| {
13508                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13509            })
13510        })
13511    }
13512
13513    pub fn move_page_down(
13514        &mut self,
13515        action: &MovePageDown,
13516        window: &mut Window,
13517        cx: &mut Context<Self>,
13518    ) {
13519        if self.take_rename(true, window, cx).is_some() {
13520            return;
13521        }
13522
13523        if self
13524            .context_menu
13525            .borrow_mut()
13526            .as_mut()
13527            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13528            .unwrap_or(false)
13529        {
13530            return;
13531        }
13532
13533        if matches!(self.mode, EditorMode::SingleLine) {
13534            cx.propagate();
13535            return;
13536        }
13537
13538        let Some(row_count) = self.visible_row_count() else {
13539            return;
13540        };
13541
13542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13543
13544        let effects = if action.center_cursor {
13545            SelectionEffects::scroll(Autoscroll::center())
13546        } else {
13547            SelectionEffects::default()
13548        };
13549
13550        let text_layout_details = &self.text_layout_details(window);
13551        self.change_selections(effects, window, cx, |s| {
13552            s.move_with(|map, selection| {
13553                if !selection.is_empty() {
13554                    selection.goal = SelectionGoal::None;
13555                }
13556                let (cursor, goal) = movement::down_by_rows(
13557                    map,
13558                    selection.end,
13559                    row_count,
13560                    selection.goal,
13561                    false,
13562                    text_layout_details,
13563                );
13564                selection.collapse_to(cursor, goal);
13565            });
13566        });
13567    }
13568
13569    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13571        let text_layout_details = &self.text_layout_details(window);
13572        self.change_selections(Default::default(), window, cx, |s| {
13573            s.move_heads_with(|map, head, goal| {
13574                movement::down(map, head, goal, false, text_layout_details)
13575            })
13576        });
13577    }
13578
13579    pub fn context_menu_first(
13580        &mut self,
13581        _: &ContextMenuFirst,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13586            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13587        }
13588    }
13589
13590    pub fn context_menu_prev(
13591        &mut self,
13592        _: &ContextMenuPrevious,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13597            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13598        }
13599    }
13600
13601    pub fn context_menu_next(
13602        &mut self,
13603        _: &ContextMenuNext,
13604        window: &mut Window,
13605        cx: &mut Context<Self>,
13606    ) {
13607        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13608            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13609        }
13610    }
13611
13612    pub fn context_menu_last(
13613        &mut self,
13614        _: &ContextMenuLast,
13615        window: &mut Window,
13616        cx: &mut Context<Self>,
13617    ) {
13618        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13619            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13620        }
13621    }
13622
13623    pub fn signature_help_prev(
13624        &mut self,
13625        _: &SignatureHelpPrevious,
13626        _: &mut Window,
13627        cx: &mut Context<Self>,
13628    ) {
13629        if let Some(popover) = self.signature_help_state.popover_mut() {
13630            if popover.current_signature == 0 {
13631                popover.current_signature = popover.signatures.len() - 1;
13632            } else {
13633                popover.current_signature -= 1;
13634            }
13635            cx.notify();
13636        }
13637    }
13638
13639    pub fn signature_help_next(
13640        &mut self,
13641        _: &SignatureHelpNext,
13642        _: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) {
13645        if let Some(popover) = self.signature_help_state.popover_mut() {
13646            if popover.current_signature + 1 == popover.signatures.len() {
13647                popover.current_signature = 0;
13648            } else {
13649                popover.current_signature += 1;
13650            }
13651            cx.notify();
13652        }
13653    }
13654
13655    pub fn move_to_previous_word_start(
13656        &mut self,
13657        _: &MoveToPreviousWordStart,
13658        window: &mut Window,
13659        cx: &mut Context<Self>,
13660    ) {
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        self.change_selections(Default::default(), window, cx, |s| {
13663            s.move_cursors_with(|map, head, _| {
13664                (
13665                    movement::previous_word_start(map, head),
13666                    SelectionGoal::None,
13667                )
13668            });
13669        })
13670    }
13671
13672    pub fn move_to_previous_subword_start(
13673        &mut self,
13674        _: &MoveToPreviousSubwordStart,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13679        self.change_selections(Default::default(), window, cx, |s| {
13680            s.move_cursors_with(|map, head, _| {
13681                (
13682                    movement::previous_subword_start(map, head),
13683                    SelectionGoal::None,
13684                )
13685            });
13686        })
13687    }
13688
13689    pub fn select_to_previous_word_start(
13690        &mut self,
13691        _: &SelectToPreviousWordStart,
13692        window: &mut Window,
13693        cx: &mut Context<Self>,
13694    ) {
13695        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13696        self.change_selections(Default::default(), window, cx, |s| {
13697            s.move_heads_with(|map, head, _| {
13698                (
13699                    movement::previous_word_start(map, head),
13700                    SelectionGoal::None,
13701                )
13702            });
13703        })
13704    }
13705
13706    pub fn select_to_previous_subword_start(
13707        &mut self,
13708        _: &SelectToPreviousSubwordStart,
13709        window: &mut Window,
13710        cx: &mut Context<Self>,
13711    ) {
13712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13713        self.change_selections(Default::default(), window, cx, |s| {
13714            s.move_heads_with(|map, head, _| {
13715                (
13716                    movement::previous_subword_start(map, head),
13717                    SelectionGoal::None,
13718                )
13719            });
13720        })
13721    }
13722
13723    pub fn delete_to_previous_word_start(
13724        &mut self,
13725        action: &DeleteToPreviousWordStart,
13726        window: &mut Window,
13727        cx: &mut Context<Self>,
13728    ) {
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13730        self.transact(window, cx, |this, window, cx| {
13731            this.select_autoclose_pair(window, cx);
13732            this.change_selections(Default::default(), window, cx, |s| {
13733                s.move_with(|map, selection| {
13734                    if selection.is_empty() {
13735                        let mut cursor = if action.ignore_newlines {
13736                            movement::previous_word_start(map, selection.head())
13737                        } else {
13738                            movement::previous_word_start_or_newline(map, selection.head())
13739                        };
13740                        cursor = movement::adjust_greedy_deletion(
13741                            map,
13742                            selection.head(),
13743                            cursor,
13744                            action.ignore_brackets,
13745                        );
13746                        selection.set_head(cursor, SelectionGoal::None);
13747                    }
13748                });
13749            });
13750            this.insert("", window, cx);
13751        });
13752    }
13753
13754    pub fn delete_to_previous_subword_start(
13755        &mut self,
13756        _: &DeleteToPreviousSubwordStart,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13761        self.transact(window, cx, |this, window, cx| {
13762            this.select_autoclose_pair(window, cx);
13763            this.change_selections(Default::default(), window, cx, |s| {
13764                s.move_with(|map, selection| {
13765                    if selection.is_empty() {
13766                        let mut cursor = movement::previous_subword_start(map, selection.head());
13767                        cursor =
13768                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13769                        selection.set_head(cursor, SelectionGoal::None);
13770                    }
13771                });
13772            });
13773            this.insert("", window, cx);
13774        });
13775    }
13776
13777    pub fn move_to_next_word_end(
13778        &mut self,
13779        _: &MoveToNextWordEnd,
13780        window: &mut Window,
13781        cx: &mut Context<Self>,
13782    ) {
13783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_cursors_with(|map, head, _| {
13786                (movement::next_word_end(map, head), SelectionGoal::None)
13787            });
13788        })
13789    }
13790
13791    pub fn move_to_next_subword_end(
13792        &mut self,
13793        _: &MoveToNextSubwordEnd,
13794        window: &mut Window,
13795        cx: &mut Context<Self>,
13796    ) {
13797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13798        self.change_selections(Default::default(), window, cx, |s| {
13799            s.move_cursors_with(|map, head, _| {
13800                (movement::next_subword_end(map, head), SelectionGoal::None)
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_next_word_end(
13806        &mut self,
13807        _: &SelectToNextWordEnd,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_heads_with(|map, head, _| {
13814                (movement::next_word_end(map, head), SelectionGoal::None)
13815            });
13816        })
13817    }
13818
13819    pub fn select_to_next_subword_end(
13820        &mut self,
13821        _: &SelectToNextSubwordEnd,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13826        self.change_selections(Default::default(), window, cx, |s| {
13827            s.move_heads_with(|map, head, _| {
13828                (movement::next_subword_end(map, head), SelectionGoal::None)
13829            });
13830        })
13831    }
13832
13833    pub fn delete_to_next_word_end(
13834        &mut self,
13835        action: &DeleteToNextWordEnd,
13836        window: &mut Window,
13837        cx: &mut Context<Self>,
13838    ) {
13839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13840        self.transact(window, cx, |this, window, cx| {
13841            this.change_selections(Default::default(), window, cx, |s| {
13842                s.move_with(|map, selection| {
13843                    if selection.is_empty() {
13844                        let mut cursor = if action.ignore_newlines {
13845                            movement::next_word_end(map, selection.head())
13846                        } else {
13847                            movement::next_word_end_or_newline(map, selection.head())
13848                        };
13849                        cursor = movement::adjust_greedy_deletion(
13850                            map,
13851                            selection.head(),
13852                            cursor,
13853                            action.ignore_brackets,
13854                        );
13855                        selection.set_head(cursor, SelectionGoal::None);
13856                    }
13857                });
13858            });
13859            this.insert("", window, cx);
13860        });
13861    }
13862
13863    pub fn delete_to_next_subword_end(
13864        &mut self,
13865        _: &DeleteToNextSubwordEnd,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13870        self.transact(window, cx, |this, window, cx| {
13871            this.change_selections(Default::default(), window, cx, |s| {
13872                s.move_with(|map, selection| {
13873                    if selection.is_empty() {
13874                        let mut cursor = movement::next_subword_end(map, selection.head());
13875                        cursor =
13876                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13877                        selection.set_head(cursor, SelectionGoal::None);
13878                    }
13879                });
13880            });
13881            this.insert("", window, cx);
13882        });
13883    }
13884
13885    pub fn move_to_beginning_of_line(
13886        &mut self,
13887        action: &MoveToBeginningOfLine,
13888        window: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13892        self.change_selections(Default::default(), window, cx, |s| {
13893            s.move_cursors_with(|map, head, _| {
13894                (
13895                    movement::indented_line_beginning(
13896                        map,
13897                        head,
13898                        action.stop_at_soft_wraps,
13899                        action.stop_at_indent,
13900                    ),
13901                    SelectionGoal::None,
13902                )
13903            });
13904        })
13905    }
13906
13907    pub fn select_to_beginning_of_line(
13908        &mut self,
13909        action: &SelectToBeginningOfLine,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) {
13913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13914        self.change_selections(Default::default(), window, cx, |s| {
13915            s.move_heads_with(|map, head, _| {
13916                (
13917                    movement::indented_line_beginning(
13918                        map,
13919                        head,
13920                        action.stop_at_soft_wraps,
13921                        action.stop_at_indent,
13922                    ),
13923                    SelectionGoal::None,
13924                )
13925            });
13926        });
13927    }
13928
13929    pub fn delete_to_beginning_of_line(
13930        &mut self,
13931        action: &DeleteToBeginningOfLine,
13932        window: &mut Window,
13933        cx: &mut Context<Self>,
13934    ) {
13935        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13936        self.transact(window, cx, |this, window, cx| {
13937            this.change_selections(Default::default(), window, cx, |s| {
13938                s.move_with(|_, selection| {
13939                    selection.reversed = true;
13940                });
13941            });
13942
13943            this.select_to_beginning_of_line(
13944                &SelectToBeginningOfLine {
13945                    stop_at_soft_wraps: false,
13946                    stop_at_indent: action.stop_at_indent,
13947                },
13948                window,
13949                cx,
13950            );
13951            this.backspace(&Backspace, window, cx);
13952        });
13953    }
13954
13955    pub fn move_to_end_of_line(
13956        &mut self,
13957        action: &MoveToEndOfLine,
13958        window: &mut Window,
13959        cx: &mut Context<Self>,
13960    ) {
13961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13962        self.change_selections(Default::default(), window, cx, |s| {
13963            s.move_cursors_with(|map, head, _| {
13964                (
13965                    movement::line_end(map, head, action.stop_at_soft_wraps),
13966                    SelectionGoal::None,
13967                )
13968            });
13969        })
13970    }
13971
13972    pub fn select_to_end_of_line(
13973        &mut self,
13974        action: &SelectToEndOfLine,
13975        window: &mut Window,
13976        cx: &mut Context<Self>,
13977    ) {
13978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13979        self.change_selections(Default::default(), window, cx, |s| {
13980            s.move_heads_with(|map, head, _| {
13981                (
13982                    movement::line_end(map, head, action.stop_at_soft_wraps),
13983                    SelectionGoal::None,
13984                )
13985            });
13986        })
13987    }
13988
13989    pub fn delete_to_end_of_line(
13990        &mut self,
13991        _: &DeleteToEndOfLine,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13996        self.transact(window, cx, |this, window, cx| {
13997            this.select_to_end_of_line(
13998                &SelectToEndOfLine {
13999                    stop_at_soft_wraps: false,
14000                },
14001                window,
14002                cx,
14003            );
14004            this.delete(&Delete, window, cx);
14005        });
14006    }
14007
14008    pub fn cut_to_end_of_line(
14009        &mut self,
14010        action: &CutToEndOfLine,
14011        window: &mut Window,
14012        cx: &mut Context<Self>,
14013    ) {
14014        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14015        self.transact(window, cx, |this, window, cx| {
14016            this.select_to_end_of_line(
14017                &SelectToEndOfLine {
14018                    stop_at_soft_wraps: false,
14019                },
14020                window,
14021                cx,
14022            );
14023            if !action.stop_at_newlines {
14024                this.change_selections(Default::default(), window, cx, |s| {
14025                    s.move_with(|_, sel| {
14026                        if sel.is_empty() {
14027                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14028                        }
14029                    });
14030                });
14031            }
14032            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14033            let item = this.cut_common(false, window, cx);
14034            cx.write_to_clipboard(item);
14035        });
14036    }
14037
14038    pub fn move_to_start_of_paragraph(
14039        &mut self,
14040        _: &MoveToStartOfParagraph,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        if matches!(self.mode, EditorMode::SingleLine) {
14045            cx.propagate();
14046            return;
14047        }
14048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14049        self.change_selections(Default::default(), window, cx, |s| {
14050            s.move_with(|map, selection| {
14051                selection.collapse_to(
14052                    movement::start_of_paragraph(map, selection.head(), 1),
14053                    SelectionGoal::None,
14054                )
14055            });
14056        })
14057    }
14058
14059    pub fn move_to_end_of_paragraph(
14060        &mut self,
14061        _: &MoveToEndOfParagraph,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        if matches!(self.mode, EditorMode::SingleLine) {
14066            cx.propagate();
14067            return;
14068        }
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.move_with(|map, selection| {
14072                selection.collapse_to(
14073                    movement::end_of_paragraph(map, selection.head(), 1),
14074                    SelectionGoal::None,
14075                )
14076            });
14077        })
14078    }
14079
14080    pub fn select_to_start_of_paragraph(
14081        &mut self,
14082        _: &SelectToStartOfParagraph,
14083        window: &mut Window,
14084        cx: &mut Context<Self>,
14085    ) {
14086        if matches!(self.mode, EditorMode::SingleLine) {
14087            cx.propagate();
14088            return;
14089        }
14090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14091        self.change_selections(Default::default(), window, cx, |s| {
14092            s.move_heads_with(|map, head, _| {
14093                (
14094                    movement::start_of_paragraph(map, head, 1),
14095                    SelectionGoal::None,
14096                )
14097            });
14098        })
14099    }
14100
14101    pub fn select_to_end_of_paragraph(
14102        &mut self,
14103        _: &SelectToEndOfParagraph,
14104        window: &mut Window,
14105        cx: &mut Context<Self>,
14106    ) {
14107        if matches!(self.mode, EditorMode::SingleLine) {
14108            cx.propagate();
14109            return;
14110        }
14111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14112        self.change_selections(Default::default(), window, cx, |s| {
14113            s.move_heads_with(|map, head, _| {
14114                (
14115                    movement::end_of_paragraph(map, head, 1),
14116                    SelectionGoal::None,
14117                )
14118            });
14119        })
14120    }
14121
14122    pub fn move_to_start_of_excerpt(
14123        &mut self,
14124        _: &MoveToStartOfExcerpt,
14125        window: &mut Window,
14126        cx: &mut Context<Self>,
14127    ) {
14128        if matches!(self.mode, EditorMode::SingleLine) {
14129            cx.propagate();
14130            return;
14131        }
14132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14133        self.change_selections(Default::default(), window, cx, |s| {
14134            s.move_with(|map, selection| {
14135                selection.collapse_to(
14136                    movement::start_of_excerpt(
14137                        map,
14138                        selection.head(),
14139                        workspace::searchable::Direction::Prev,
14140                    ),
14141                    SelectionGoal::None,
14142                )
14143            });
14144        })
14145    }
14146
14147    pub fn move_to_start_of_next_excerpt(
14148        &mut self,
14149        _: &MoveToStartOfNextExcerpt,
14150        window: &mut Window,
14151        cx: &mut Context<Self>,
14152    ) {
14153        if matches!(self.mode, EditorMode::SingleLine) {
14154            cx.propagate();
14155            return;
14156        }
14157
14158        self.change_selections(Default::default(), window, cx, |s| {
14159            s.move_with(|map, selection| {
14160                selection.collapse_to(
14161                    movement::start_of_excerpt(
14162                        map,
14163                        selection.head(),
14164                        workspace::searchable::Direction::Next,
14165                    ),
14166                    SelectionGoal::None,
14167                )
14168            });
14169        })
14170    }
14171
14172    pub fn move_to_end_of_excerpt(
14173        &mut self,
14174        _: &MoveToEndOfExcerpt,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) {
14178        if matches!(self.mode, EditorMode::SingleLine) {
14179            cx.propagate();
14180            return;
14181        }
14182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14183        self.change_selections(Default::default(), window, cx, |s| {
14184            s.move_with(|map, selection| {
14185                selection.collapse_to(
14186                    movement::end_of_excerpt(
14187                        map,
14188                        selection.head(),
14189                        workspace::searchable::Direction::Next,
14190                    ),
14191                    SelectionGoal::None,
14192                )
14193            });
14194        })
14195    }
14196
14197    pub fn move_to_end_of_previous_excerpt(
14198        &mut self,
14199        _: &MoveToEndOfPreviousExcerpt,
14200        window: &mut Window,
14201        cx: &mut Context<Self>,
14202    ) {
14203        if matches!(self.mode, EditorMode::SingleLine) {
14204            cx.propagate();
14205            return;
14206        }
14207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14208        self.change_selections(Default::default(), window, cx, |s| {
14209            s.move_with(|map, selection| {
14210                selection.collapse_to(
14211                    movement::end_of_excerpt(
14212                        map,
14213                        selection.head(),
14214                        workspace::searchable::Direction::Prev,
14215                    ),
14216                    SelectionGoal::None,
14217                )
14218            });
14219        })
14220    }
14221
14222    pub fn select_to_start_of_excerpt(
14223        &mut self,
14224        _: &SelectToStartOfExcerpt,
14225        window: &mut Window,
14226        cx: &mut Context<Self>,
14227    ) {
14228        if matches!(self.mode, EditorMode::SingleLine) {
14229            cx.propagate();
14230            return;
14231        }
14232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14233        self.change_selections(Default::default(), window, cx, |s| {
14234            s.move_heads_with(|map, head, _| {
14235                (
14236                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14237                    SelectionGoal::None,
14238                )
14239            });
14240        })
14241    }
14242
14243    pub fn select_to_start_of_next_excerpt(
14244        &mut self,
14245        _: &SelectToStartOfNextExcerpt,
14246        window: &mut Window,
14247        cx: &mut Context<Self>,
14248    ) {
14249        if matches!(self.mode, EditorMode::SingleLine) {
14250            cx.propagate();
14251            return;
14252        }
14253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14254        self.change_selections(Default::default(), window, cx, |s| {
14255            s.move_heads_with(|map, head, _| {
14256                (
14257                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14258                    SelectionGoal::None,
14259                )
14260            });
14261        })
14262    }
14263
14264    pub fn select_to_end_of_excerpt(
14265        &mut self,
14266        _: &SelectToEndOfExcerpt,
14267        window: &mut Window,
14268        cx: &mut Context<Self>,
14269    ) {
14270        if matches!(self.mode, EditorMode::SingleLine) {
14271            cx.propagate();
14272            return;
14273        }
14274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14275        self.change_selections(Default::default(), window, cx, |s| {
14276            s.move_heads_with(|map, head, _| {
14277                (
14278                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14279                    SelectionGoal::None,
14280                )
14281            });
14282        })
14283    }
14284
14285    pub fn select_to_end_of_previous_excerpt(
14286        &mut self,
14287        _: &SelectToEndOfPreviousExcerpt,
14288        window: &mut Window,
14289        cx: &mut Context<Self>,
14290    ) {
14291        if matches!(self.mode, EditorMode::SingleLine) {
14292            cx.propagate();
14293            return;
14294        }
14295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14296        self.change_selections(Default::default(), window, cx, |s| {
14297            s.move_heads_with(|map, head, _| {
14298                (
14299                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14300                    SelectionGoal::None,
14301                )
14302            });
14303        })
14304    }
14305
14306    pub fn move_to_beginning(
14307        &mut self,
14308        _: &MoveToBeginning,
14309        window: &mut Window,
14310        cx: &mut Context<Self>,
14311    ) {
14312        if matches!(self.mode, EditorMode::SingleLine) {
14313            cx.propagate();
14314            return;
14315        }
14316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14317        self.change_selections(Default::default(), window, cx, |s| {
14318            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14319        });
14320    }
14321
14322    pub fn select_to_beginning(
14323        &mut self,
14324        _: &SelectToBeginning,
14325        window: &mut Window,
14326        cx: &mut Context<Self>,
14327    ) {
14328        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14329        selection.set_head(Point::zero(), SelectionGoal::None);
14330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14331        self.change_selections(Default::default(), window, cx, |s| {
14332            s.select(vec![selection]);
14333        });
14334    }
14335
14336    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14337        if matches!(self.mode, EditorMode::SingleLine) {
14338            cx.propagate();
14339            return;
14340        }
14341        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14342        let cursor = self.buffer.read(cx).read(cx).len();
14343        self.change_selections(Default::default(), window, cx, |s| {
14344            s.select_ranges(vec![cursor..cursor])
14345        });
14346    }
14347
14348    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14349        self.nav_history = nav_history;
14350    }
14351
14352    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14353        self.nav_history.as_ref()
14354    }
14355
14356    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14357        self.push_to_nav_history(
14358            self.selections.newest_anchor().head(),
14359            None,
14360            false,
14361            true,
14362            cx,
14363        );
14364    }
14365
14366    fn push_to_nav_history(
14367        &mut self,
14368        cursor_anchor: Anchor,
14369        new_position: Option<Point>,
14370        is_deactivate: bool,
14371        always: bool,
14372        cx: &mut Context<Self>,
14373    ) {
14374        if let Some(nav_history) = self.nav_history.as_mut() {
14375            let buffer = self.buffer.read(cx).read(cx);
14376            let cursor_position = cursor_anchor.to_point(&buffer);
14377            let scroll_state = self.scroll_manager.anchor();
14378            let scroll_top_row = scroll_state.top_row(&buffer);
14379            drop(buffer);
14380
14381            if let Some(new_position) = new_position {
14382                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14383                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14384                    return;
14385                }
14386            }
14387
14388            nav_history.push(
14389                Some(NavigationData {
14390                    cursor_anchor,
14391                    cursor_position,
14392                    scroll_anchor: scroll_state,
14393                    scroll_top_row,
14394                }),
14395                cx,
14396            );
14397            cx.emit(EditorEvent::PushedToNavHistory {
14398                anchor: cursor_anchor,
14399                is_deactivate,
14400            })
14401        }
14402    }
14403
14404    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14406        let buffer = self.buffer.read(cx).snapshot(cx);
14407        let mut selection = self
14408            .selections
14409            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14410        selection.set_head(buffer.len(), SelectionGoal::None);
14411        self.change_selections(Default::default(), window, cx, |s| {
14412            s.select(vec![selection]);
14413        });
14414    }
14415
14416    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14418        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14419            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14420        });
14421    }
14422
14423    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14425        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14426        let mut selections = self.selections.all::<Point>(&display_map);
14427        let max_point = display_map.buffer_snapshot().max_point();
14428        for selection in &mut selections {
14429            let rows = selection.spanned_rows(true, &display_map);
14430            selection.start = Point::new(rows.start.0, 0);
14431            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14432            selection.reversed = false;
14433        }
14434        self.change_selections(Default::default(), window, cx, |s| {
14435            s.select(selections);
14436        });
14437    }
14438
14439    pub fn split_selection_into_lines(
14440        &mut self,
14441        action: &SplitSelectionIntoLines,
14442        window: &mut Window,
14443        cx: &mut Context<Self>,
14444    ) {
14445        let selections = self
14446            .selections
14447            .all::<Point>(&self.display_snapshot(cx))
14448            .into_iter()
14449            .map(|selection| selection.start..selection.end)
14450            .collect::<Vec<_>>();
14451        self.unfold_ranges(&selections, true, true, cx);
14452
14453        let mut new_selection_ranges = Vec::new();
14454        {
14455            let buffer = self.buffer.read(cx).read(cx);
14456            for selection in selections {
14457                for row in selection.start.row..selection.end.row {
14458                    let line_start = Point::new(row, 0);
14459                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14460
14461                    if action.keep_selections {
14462                        // Keep the selection range for each line
14463                        let selection_start = if row == selection.start.row {
14464                            selection.start
14465                        } else {
14466                            line_start
14467                        };
14468                        new_selection_ranges.push(selection_start..line_end);
14469                    } else {
14470                        // Collapse to cursor at end of line
14471                        new_selection_ranges.push(line_end..line_end);
14472                    }
14473                }
14474
14475                let is_multiline_selection = selection.start.row != selection.end.row;
14476                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14477                // so this action feels more ergonomic when paired with other selection operations
14478                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14479                if !should_skip_last {
14480                    if action.keep_selections {
14481                        if is_multiline_selection {
14482                            let line_start = Point::new(selection.end.row, 0);
14483                            new_selection_ranges.push(line_start..selection.end);
14484                        } else {
14485                            new_selection_ranges.push(selection.start..selection.end);
14486                        }
14487                    } else {
14488                        new_selection_ranges.push(selection.end..selection.end);
14489                    }
14490                }
14491            }
14492        }
14493        self.change_selections(Default::default(), window, cx, |s| {
14494            s.select_ranges(new_selection_ranges);
14495        });
14496    }
14497
14498    pub fn add_selection_above(
14499        &mut self,
14500        action: &AddSelectionAbove,
14501        window: &mut Window,
14502        cx: &mut Context<Self>,
14503    ) {
14504        self.add_selection(true, action.skip_soft_wrap, window, cx);
14505    }
14506
14507    pub fn add_selection_below(
14508        &mut self,
14509        action: &AddSelectionBelow,
14510        window: &mut Window,
14511        cx: &mut Context<Self>,
14512    ) {
14513        self.add_selection(false, action.skip_soft_wrap, window, cx);
14514    }
14515
14516    fn add_selection(
14517        &mut self,
14518        above: bool,
14519        skip_soft_wrap: bool,
14520        window: &mut Window,
14521        cx: &mut Context<Self>,
14522    ) {
14523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14524
14525        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14526        let all_selections = self.selections.all::<Point>(&display_map);
14527        let text_layout_details = self.text_layout_details(window);
14528
14529        let (mut columnar_selections, new_selections_to_columnarize) = {
14530            if let Some(state) = self.add_selections_state.as_ref() {
14531                let columnar_selection_ids: HashSet<_> = state
14532                    .groups
14533                    .iter()
14534                    .flat_map(|group| group.stack.iter())
14535                    .copied()
14536                    .collect();
14537
14538                all_selections
14539                    .into_iter()
14540                    .partition(|s| columnar_selection_ids.contains(&s.id))
14541            } else {
14542                (Vec::new(), all_selections)
14543            }
14544        };
14545
14546        let mut state = self
14547            .add_selections_state
14548            .take()
14549            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14550
14551        for selection in new_selections_to_columnarize {
14552            let range = selection.display_range(&display_map).sorted();
14553            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14554            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14555            let positions = start_x.min(end_x)..start_x.max(end_x);
14556            let mut stack = Vec::new();
14557            for row in range.start.row().0..=range.end.row().0 {
14558                if let Some(selection) = self.selections.build_columnar_selection(
14559                    &display_map,
14560                    DisplayRow(row),
14561                    &positions,
14562                    selection.reversed,
14563                    &text_layout_details,
14564                ) {
14565                    stack.push(selection.id);
14566                    columnar_selections.push(selection);
14567                }
14568            }
14569            if !stack.is_empty() {
14570                if above {
14571                    stack.reverse();
14572                }
14573                state.groups.push(AddSelectionsGroup { above, stack });
14574            }
14575        }
14576
14577        let mut final_selections = Vec::new();
14578        let end_row = if above {
14579            DisplayRow(0)
14580        } else {
14581            display_map.max_point().row()
14582        };
14583
14584        let mut last_added_item_per_group = HashMap::default();
14585        for group in state.groups.iter_mut() {
14586            if let Some(last_id) = group.stack.last() {
14587                last_added_item_per_group.insert(*last_id, group);
14588            }
14589        }
14590
14591        for selection in columnar_selections {
14592            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14593                if above == group.above {
14594                    let range = selection.display_range(&display_map).sorted();
14595                    debug_assert_eq!(range.start.row(), range.end.row());
14596                    let mut row = range.start.row();
14597                    let positions =
14598                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14599                            Pixels::from(start)..Pixels::from(end)
14600                        } else {
14601                            let start_x =
14602                                display_map.x_for_display_point(range.start, &text_layout_details);
14603                            let end_x =
14604                                display_map.x_for_display_point(range.end, &text_layout_details);
14605                            start_x.min(end_x)..start_x.max(end_x)
14606                        };
14607
14608                    let mut maybe_new_selection = None;
14609                    let direction = if above { -1 } else { 1 };
14610
14611                    while row != end_row {
14612                        if skip_soft_wrap {
14613                            row = display_map
14614                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14615                                .row();
14616                        } else if above {
14617                            row.0 -= 1;
14618                        } else {
14619                            row.0 += 1;
14620                        }
14621
14622                        if let Some(new_selection) = self.selections.build_columnar_selection(
14623                            &display_map,
14624                            row,
14625                            &positions,
14626                            selection.reversed,
14627                            &text_layout_details,
14628                        ) {
14629                            maybe_new_selection = Some(new_selection);
14630                            break;
14631                        }
14632                    }
14633
14634                    if let Some(new_selection) = maybe_new_selection {
14635                        group.stack.push(new_selection.id);
14636                        if above {
14637                            final_selections.push(new_selection);
14638                            final_selections.push(selection);
14639                        } else {
14640                            final_selections.push(selection);
14641                            final_selections.push(new_selection);
14642                        }
14643                    } else {
14644                        final_selections.push(selection);
14645                    }
14646                } else {
14647                    group.stack.pop();
14648                }
14649            } else {
14650                final_selections.push(selection);
14651            }
14652        }
14653
14654        self.change_selections(Default::default(), window, cx, |s| {
14655            s.select(final_selections);
14656        });
14657
14658        let final_selection_ids: HashSet<_> = self
14659            .selections
14660            .all::<Point>(&display_map)
14661            .iter()
14662            .map(|s| s.id)
14663            .collect();
14664        state.groups.retain_mut(|group| {
14665            // selections might get merged above so we remove invalid items from stacks
14666            group.stack.retain(|id| final_selection_ids.contains(id));
14667
14668            // single selection in stack can be treated as initial state
14669            group.stack.len() > 1
14670        });
14671
14672        if !state.groups.is_empty() {
14673            self.add_selections_state = Some(state);
14674        }
14675    }
14676
14677    fn select_match_ranges(
14678        &mut self,
14679        range: Range<MultiBufferOffset>,
14680        reversed: bool,
14681        replace_newest: bool,
14682        auto_scroll: Option<Autoscroll>,
14683        window: &mut Window,
14684        cx: &mut Context<Editor>,
14685    ) {
14686        self.unfold_ranges(
14687            std::slice::from_ref(&range),
14688            false,
14689            auto_scroll.is_some(),
14690            cx,
14691        );
14692        let effects = if let Some(scroll) = auto_scroll {
14693            SelectionEffects::scroll(scroll)
14694        } else {
14695            SelectionEffects::no_scroll()
14696        };
14697        self.change_selections(effects, window, cx, |s| {
14698            if replace_newest {
14699                s.delete(s.newest_anchor().id);
14700            }
14701            if reversed {
14702                s.insert_range(range.end..range.start);
14703            } else {
14704                s.insert_range(range);
14705            }
14706        });
14707    }
14708
14709    pub fn select_next_match_internal(
14710        &mut self,
14711        display_map: &DisplaySnapshot,
14712        replace_newest: bool,
14713        autoscroll: Option<Autoscroll>,
14714        window: &mut Window,
14715        cx: &mut Context<Self>,
14716    ) -> Result<()> {
14717        let buffer = display_map.buffer_snapshot();
14718        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14719        if let Some(mut select_next_state) = self.select_next_state.take() {
14720            let query = &select_next_state.query;
14721            if !select_next_state.done {
14722                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14723                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14724                let mut next_selected_range = None;
14725
14726                let bytes_after_last_selection =
14727                    buffer.bytes_in_range(last_selection.end..buffer.len());
14728                let bytes_before_first_selection =
14729                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14730                let query_matches = query
14731                    .stream_find_iter(bytes_after_last_selection)
14732                    .map(|result| (last_selection.end, result))
14733                    .chain(
14734                        query
14735                            .stream_find_iter(bytes_before_first_selection)
14736                            .map(|result| (MultiBufferOffset(0), result)),
14737                    );
14738
14739                for (start_offset, query_match) in query_matches {
14740                    let query_match = query_match.unwrap(); // can only fail due to I/O
14741                    let offset_range =
14742                        start_offset + query_match.start()..start_offset + query_match.end();
14743
14744                    if !select_next_state.wordwise
14745                        || (!buffer.is_inside_word(offset_range.start, None)
14746                            && !buffer.is_inside_word(offset_range.end, None))
14747                    {
14748                        let idx = selections
14749                            .partition_point(|selection| selection.end <= offset_range.start);
14750                        let overlaps = selections
14751                            .get(idx)
14752                            .map_or(false, |selection| selection.start < offset_range.end);
14753
14754                        if !overlaps {
14755                            next_selected_range = Some(offset_range);
14756                            break;
14757                        }
14758                    }
14759                }
14760
14761                if let Some(next_selected_range) = next_selected_range {
14762                    self.select_match_ranges(
14763                        next_selected_range,
14764                        last_selection.reversed,
14765                        replace_newest,
14766                        autoscroll,
14767                        window,
14768                        cx,
14769                    );
14770                } else {
14771                    select_next_state.done = true;
14772                }
14773            }
14774
14775            self.select_next_state = Some(select_next_state);
14776        } else {
14777            let mut only_carets = true;
14778            let mut same_text_selected = true;
14779            let mut selected_text = None;
14780
14781            let mut selections_iter = selections.iter().peekable();
14782            while let Some(selection) = selections_iter.next() {
14783                if selection.start != selection.end {
14784                    only_carets = false;
14785                }
14786
14787                if same_text_selected {
14788                    if selected_text.is_none() {
14789                        selected_text =
14790                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14791                    }
14792
14793                    if let Some(next_selection) = selections_iter.peek() {
14794                        if next_selection.len() == selection.len() {
14795                            let next_selected_text = buffer
14796                                .text_for_range(next_selection.range())
14797                                .collect::<String>();
14798                            if Some(next_selected_text) != selected_text {
14799                                same_text_selected = false;
14800                                selected_text = None;
14801                            }
14802                        } else {
14803                            same_text_selected = false;
14804                            selected_text = None;
14805                        }
14806                    }
14807                }
14808            }
14809
14810            if only_carets {
14811                for selection in &mut selections {
14812                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14813                    selection.start = word_range.start;
14814                    selection.end = word_range.end;
14815                    selection.goal = SelectionGoal::None;
14816                    selection.reversed = false;
14817                    self.select_match_ranges(
14818                        selection.start..selection.end,
14819                        selection.reversed,
14820                        replace_newest,
14821                        autoscroll,
14822                        window,
14823                        cx,
14824                    );
14825                }
14826
14827                if selections.len() == 1 {
14828                    let selection = selections
14829                        .last()
14830                        .expect("ensured that there's only one selection");
14831                    let query = buffer
14832                        .text_for_range(selection.start..selection.end)
14833                        .collect::<String>();
14834                    let is_empty = query.is_empty();
14835                    let select_state = SelectNextState {
14836                        query: self.build_query(&[query], cx)?,
14837                        wordwise: true,
14838                        done: is_empty,
14839                    };
14840                    self.select_next_state = Some(select_state);
14841                } else {
14842                    self.select_next_state = None;
14843                }
14844            } else if let Some(selected_text) = selected_text {
14845                self.select_next_state = Some(SelectNextState {
14846                    query: self.build_query(&[selected_text], cx)?,
14847                    wordwise: false,
14848                    done: false,
14849                });
14850                self.select_next_match_internal(
14851                    display_map,
14852                    replace_newest,
14853                    autoscroll,
14854                    window,
14855                    cx,
14856                )?;
14857            }
14858        }
14859        Ok(())
14860    }
14861
14862    pub fn select_all_matches(
14863        &mut self,
14864        _action: &SelectAllMatches,
14865        window: &mut Window,
14866        cx: &mut Context<Self>,
14867    ) -> Result<()> {
14868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14869
14870        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14871
14872        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14873        let Some(select_next_state) = self.select_next_state.as_mut() else {
14874            return Ok(());
14875        };
14876        if select_next_state.done {
14877            return Ok(());
14878        }
14879
14880        let mut new_selections = Vec::new();
14881
14882        let reversed = self
14883            .selections
14884            .oldest::<MultiBufferOffset>(&display_map)
14885            .reversed;
14886        let buffer = display_map.buffer_snapshot();
14887        let query_matches = select_next_state
14888            .query
14889            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14890
14891        for query_match in query_matches.into_iter() {
14892            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14893            let offset_range = if reversed {
14894                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14895            } else {
14896                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14897            };
14898
14899            if !select_next_state.wordwise
14900                || (!buffer.is_inside_word(offset_range.start, None)
14901                    && !buffer.is_inside_word(offset_range.end, None))
14902            {
14903                new_selections.push(offset_range.start..offset_range.end);
14904            }
14905        }
14906
14907        select_next_state.done = true;
14908
14909        if new_selections.is_empty() {
14910            log::error!("bug: new_selections is empty in select_all_matches");
14911            return Ok(());
14912        }
14913
14914        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14915        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14916            selections.select_ranges(new_selections)
14917        });
14918
14919        Ok(())
14920    }
14921
14922    pub fn select_next(
14923        &mut self,
14924        action: &SelectNext,
14925        window: &mut Window,
14926        cx: &mut Context<Self>,
14927    ) -> Result<()> {
14928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14929        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14930        self.select_next_match_internal(
14931            &display_map,
14932            action.replace_newest,
14933            Some(Autoscroll::newest()),
14934            window,
14935            cx,
14936        )?;
14937        Ok(())
14938    }
14939
14940    pub fn select_previous(
14941        &mut self,
14942        action: &SelectPrevious,
14943        window: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) -> Result<()> {
14946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14947        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14948        let buffer = display_map.buffer_snapshot();
14949        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14950        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14951            let query = &select_prev_state.query;
14952            if !select_prev_state.done {
14953                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14954                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14955                let mut next_selected_range = None;
14956                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14957                let bytes_before_last_selection =
14958                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14959                let bytes_after_first_selection =
14960                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14961                let query_matches = query
14962                    .stream_find_iter(bytes_before_last_selection)
14963                    .map(|result| (last_selection.start, result))
14964                    .chain(
14965                        query
14966                            .stream_find_iter(bytes_after_first_selection)
14967                            .map(|result| (buffer.len(), result)),
14968                    );
14969                for (end_offset, query_match) in query_matches {
14970                    let query_match = query_match.unwrap(); // can only fail due to I/O
14971                    let offset_range =
14972                        end_offset - query_match.end()..end_offset - query_match.start();
14973
14974                    if !select_prev_state.wordwise
14975                        || (!buffer.is_inside_word(offset_range.start, None)
14976                            && !buffer.is_inside_word(offset_range.end, None))
14977                    {
14978                        next_selected_range = Some(offset_range);
14979                        break;
14980                    }
14981                }
14982
14983                if let Some(next_selected_range) = next_selected_range {
14984                    self.select_match_ranges(
14985                        next_selected_range,
14986                        last_selection.reversed,
14987                        action.replace_newest,
14988                        Some(Autoscroll::newest()),
14989                        window,
14990                        cx,
14991                    );
14992                } else {
14993                    select_prev_state.done = true;
14994                }
14995            }
14996
14997            self.select_prev_state = Some(select_prev_state);
14998        } else {
14999            let mut only_carets = true;
15000            let mut same_text_selected = true;
15001            let mut selected_text = None;
15002
15003            let mut selections_iter = selections.iter().peekable();
15004            while let Some(selection) = selections_iter.next() {
15005                if selection.start != selection.end {
15006                    only_carets = false;
15007                }
15008
15009                if same_text_selected {
15010                    if selected_text.is_none() {
15011                        selected_text =
15012                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15013                    }
15014
15015                    if let Some(next_selection) = selections_iter.peek() {
15016                        if next_selection.len() == selection.len() {
15017                            let next_selected_text = buffer
15018                                .text_for_range(next_selection.range())
15019                                .collect::<String>();
15020                            if Some(next_selected_text) != selected_text {
15021                                same_text_selected = false;
15022                                selected_text = None;
15023                            }
15024                        } else {
15025                            same_text_selected = false;
15026                            selected_text = None;
15027                        }
15028                    }
15029                }
15030            }
15031
15032            if only_carets {
15033                for selection in &mut selections {
15034                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15035                    selection.start = word_range.start;
15036                    selection.end = word_range.end;
15037                    selection.goal = SelectionGoal::None;
15038                    selection.reversed = false;
15039                    self.select_match_ranges(
15040                        selection.start..selection.end,
15041                        selection.reversed,
15042                        action.replace_newest,
15043                        Some(Autoscroll::newest()),
15044                        window,
15045                        cx,
15046                    );
15047                }
15048                if selections.len() == 1 {
15049                    let selection = selections
15050                        .last()
15051                        .expect("ensured that there's only one selection");
15052                    let query = buffer
15053                        .text_for_range(selection.start..selection.end)
15054                        .collect::<String>();
15055                    let is_empty = query.is_empty();
15056                    let select_state = SelectNextState {
15057                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15058                        wordwise: true,
15059                        done: is_empty,
15060                    };
15061                    self.select_prev_state = Some(select_state);
15062                } else {
15063                    self.select_prev_state = None;
15064                }
15065            } else if let Some(selected_text) = selected_text {
15066                self.select_prev_state = Some(SelectNextState {
15067                    query: self
15068                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15069                    wordwise: false,
15070                    done: false,
15071                });
15072                self.select_previous(action, window, cx)?;
15073            }
15074        }
15075        Ok(())
15076    }
15077
15078    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15079    /// setting the case sensitivity based on the global
15080    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15081    /// editor's settings.
15082    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15083    where
15084        I: IntoIterator<Item = P>,
15085        P: AsRef<[u8]>,
15086    {
15087        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15088            || EditorSettings::get_global(cx).search.case_sensitive,
15089            |value| value,
15090        );
15091
15092        let mut builder = AhoCorasickBuilder::new();
15093        builder.ascii_case_insensitive(!case_sensitive);
15094        builder.build(patterns)
15095    }
15096
15097    pub fn find_next_match(
15098        &mut self,
15099        _: &FindNextMatch,
15100        window: &mut Window,
15101        cx: &mut Context<Self>,
15102    ) -> Result<()> {
15103        let selections = self.selections.disjoint_anchors_arc();
15104        match selections.first() {
15105            Some(first) if selections.len() >= 2 => {
15106                self.change_selections(Default::default(), window, cx, |s| {
15107                    s.select_ranges([first.range()]);
15108                });
15109            }
15110            _ => self.select_next(
15111                &SelectNext {
15112                    replace_newest: true,
15113                },
15114                window,
15115                cx,
15116            )?,
15117        }
15118        Ok(())
15119    }
15120
15121    pub fn find_previous_match(
15122        &mut self,
15123        _: &FindPreviousMatch,
15124        window: &mut Window,
15125        cx: &mut Context<Self>,
15126    ) -> Result<()> {
15127        let selections = self.selections.disjoint_anchors_arc();
15128        match selections.last() {
15129            Some(last) if selections.len() >= 2 => {
15130                self.change_selections(Default::default(), window, cx, |s| {
15131                    s.select_ranges([last.range()]);
15132                });
15133            }
15134            _ => self.select_previous(
15135                &SelectPrevious {
15136                    replace_newest: true,
15137                },
15138                window,
15139                cx,
15140            )?,
15141        }
15142        Ok(())
15143    }
15144
15145    pub fn toggle_comments(
15146        &mut self,
15147        action: &ToggleComments,
15148        window: &mut Window,
15149        cx: &mut Context<Self>,
15150    ) {
15151        if self.read_only(cx) {
15152            return;
15153        }
15154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15155        let text_layout_details = &self.text_layout_details(window);
15156        self.transact(window, cx, |this, window, cx| {
15157            let mut selections = this
15158                .selections
15159                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15160            let mut edits = Vec::new();
15161            let mut selection_edit_ranges = Vec::new();
15162            let mut last_toggled_row = None;
15163            let snapshot = this.buffer.read(cx).read(cx);
15164            let empty_str: Arc<str> = Arc::default();
15165            let mut suffixes_inserted = Vec::new();
15166            let ignore_indent = action.ignore_indent;
15167
15168            fn comment_prefix_range(
15169                snapshot: &MultiBufferSnapshot,
15170                row: MultiBufferRow,
15171                comment_prefix: &str,
15172                comment_prefix_whitespace: &str,
15173                ignore_indent: bool,
15174            ) -> Range<Point> {
15175                let indent_size = if ignore_indent {
15176                    0
15177                } else {
15178                    snapshot.indent_size_for_line(row).len
15179                };
15180
15181                let start = Point::new(row.0, indent_size);
15182
15183                let mut line_bytes = snapshot
15184                    .bytes_in_range(start..snapshot.max_point())
15185                    .flatten()
15186                    .copied();
15187
15188                // If this line currently begins with the line comment prefix, then record
15189                // the range containing the prefix.
15190                if line_bytes
15191                    .by_ref()
15192                    .take(comment_prefix.len())
15193                    .eq(comment_prefix.bytes())
15194                {
15195                    // Include any whitespace that matches the comment prefix.
15196                    let matching_whitespace_len = line_bytes
15197                        .zip(comment_prefix_whitespace.bytes())
15198                        .take_while(|(a, b)| a == b)
15199                        .count() as u32;
15200                    let end = Point::new(
15201                        start.row,
15202                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15203                    );
15204                    start..end
15205                } else {
15206                    start..start
15207                }
15208            }
15209
15210            fn comment_suffix_range(
15211                snapshot: &MultiBufferSnapshot,
15212                row: MultiBufferRow,
15213                comment_suffix: &str,
15214                comment_suffix_has_leading_space: bool,
15215            ) -> Range<Point> {
15216                let end = Point::new(row.0, snapshot.line_len(row));
15217                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15218
15219                let mut line_end_bytes = snapshot
15220                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15221                    .flatten()
15222                    .copied();
15223
15224                let leading_space_len = if suffix_start_column > 0
15225                    && line_end_bytes.next() == Some(b' ')
15226                    && comment_suffix_has_leading_space
15227                {
15228                    1
15229                } else {
15230                    0
15231                };
15232
15233                // If this line currently begins with the line comment prefix, then record
15234                // the range containing the prefix.
15235                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15236                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15237                    start..end
15238                } else {
15239                    end..end
15240                }
15241            }
15242
15243            // TODO: Handle selections that cross excerpts
15244            for selection in &mut selections {
15245                let start_column = snapshot
15246                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15247                    .len;
15248                let language = if let Some(language) =
15249                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15250                {
15251                    language
15252                } else {
15253                    continue;
15254                };
15255
15256                selection_edit_ranges.clear();
15257
15258                // If multiple selections contain a given row, avoid processing that
15259                // row more than once.
15260                let mut start_row = MultiBufferRow(selection.start.row);
15261                if last_toggled_row == Some(start_row) {
15262                    start_row = start_row.next_row();
15263                }
15264                let end_row =
15265                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15266                        MultiBufferRow(selection.end.row - 1)
15267                    } else {
15268                        MultiBufferRow(selection.end.row)
15269                    };
15270                last_toggled_row = Some(end_row);
15271
15272                if start_row > end_row {
15273                    continue;
15274                }
15275
15276                // If the language has line comments, toggle those.
15277                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15278
15279                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15280                if ignore_indent {
15281                    full_comment_prefixes = full_comment_prefixes
15282                        .into_iter()
15283                        .map(|s| Arc::from(s.trim_end()))
15284                        .collect();
15285                }
15286
15287                if !full_comment_prefixes.is_empty() {
15288                    let first_prefix = full_comment_prefixes
15289                        .first()
15290                        .expect("prefixes is non-empty");
15291                    let prefix_trimmed_lengths = full_comment_prefixes
15292                        .iter()
15293                        .map(|p| p.trim_end_matches(' ').len())
15294                        .collect::<SmallVec<[usize; 4]>>();
15295
15296                    let mut all_selection_lines_are_comments = true;
15297
15298                    for row in start_row.0..=end_row.0 {
15299                        let row = MultiBufferRow(row);
15300                        if start_row < end_row && snapshot.is_line_blank(row) {
15301                            continue;
15302                        }
15303
15304                        let prefix_range = full_comment_prefixes
15305                            .iter()
15306                            .zip(prefix_trimmed_lengths.iter().copied())
15307                            .map(|(prefix, trimmed_prefix_len)| {
15308                                comment_prefix_range(
15309                                    snapshot.deref(),
15310                                    row,
15311                                    &prefix[..trimmed_prefix_len],
15312                                    &prefix[trimmed_prefix_len..],
15313                                    ignore_indent,
15314                                )
15315                            })
15316                            .max_by_key(|range| range.end.column - range.start.column)
15317                            .expect("prefixes is non-empty");
15318
15319                        if prefix_range.is_empty() {
15320                            all_selection_lines_are_comments = false;
15321                        }
15322
15323                        selection_edit_ranges.push(prefix_range);
15324                    }
15325
15326                    if all_selection_lines_are_comments {
15327                        edits.extend(
15328                            selection_edit_ranges
15329                                .iter()
15330                                .cloned()
15331                                .map(|range| (range, empty_str.clone())),
15332                        );
15333                    } else {
15334                        let min_column = selection_edit_ranges
15335                            .iter()
15336                            .map(|range| range.start.column)
15337                            .min()
15338                            .unwrap_or(0);
15339                        edits.extend(selection_edit_ranges.iter().map(|range| {
15340                            let position = Point::new(range.start.row, min_column);
15341                            (position..position, first_prefix.clone())
15342                        }));
15343                    }
15344                } else if let Some(BlockCommentConfig {
15345                    start: full_comment_prefix,
15346                    end: comment_suffix,
15347                    ..
15348                }) = language.block_comment()
15349                {
15350                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15351                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15352                    let prefix_range = comment_prefix_range(
15353                        snapshot.deref(),
15354                        start_row,
15355                        comment_prefix,
15356                        comment_prefix_whitespace,
15357                        ignore_indent,
15358                    );
15359                    let suffix_range = comment_suffix_range(
15360                        snapshot.deref(),
15361                        end_row,
15362                        comment_suffix.trim_start_matches(' '),
15363                        comment_suffix.starts_with(' '),
15364                    );
15365
15366                    if prefix_range.is_empty() || suffix_range.is_empty() {
15367                        edits.push((
15368                            prefix_range.start..prefix_range.start,
15369                            full_comment_prefix.clone(),
15370                        ));
15371                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15372                        suffixes_inserted.push((end_row, comment_suffix.len()));
15373                    } else {
15374                        edits.push((prefix_range, empty_str.clone()));
15375                        edits.push((suffix_range, empty_str.clone()));
15376                    }
15377                } else {
15378                    continue;
15379                }
15380            }
15381
15382            drop(snapshot);
15383            this.buffer.update(cx, |buffer, cx| {
15384                buffer.edit(edits, None, cx);
15385            });
15386
15387            // Adjust selections so that they end before any comment suffixes that
15388            // were inserted.
15389            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15390            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15391            let snapshot = this.buffer.read(cx).read(cx);
15392            for selection in &mut selections {
15393                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15394                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15395                        Ordering::Less => {
15396                            suffixes_inserted.next();
15397                            continue;
15398                        }
15399                        Ordering::Greater => break,
15400                        Ordering::Equal => {
15401                            if selection.end.column == snapshot.line_len(row) {
15402                                if selection.is_empty() {
15403                                    selection.start.column -= suffix_len as u32;
15404                                }
15405                                selection.end.column -= suffix_len as u32;
15406                            }
15407                            break;
15408                        }
15409                    }
15410                }
15411            }
15412
15413            drop(snapshot);
15414            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15415
15416            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15417            let selections_on_single_row = selections.windows(2).all(|selections| {
15418                selections[0].start.row == selections[1].start.row
15419                    && selections[0].end.row == selections[1].end.row
15420                    && selections[0].start.row == selections[0].end.row
15421            });
15422            let selections_selecting = selections
15423                .iter()
15424                .any(|selection| selection.start != selection.end);
15425            let advance_downwards = action.advance_downwards
15426                && selections_on_single_row
15427                && !selections_selecting
15428                && !matches!(this.mode, EditorMode::SingleLine);
15429
15430            if advance_downwards {
15431                let snapshot = this.buffer.read(cx).snapshot(cx);
15432
15433                this.change_selections(Default::default(), window, cx, |s| {
15434                    s.move_cursors_with(|display_snapshot, display_point, _| {
15435                        let mut point = display_point.to_point(display_snapshot);
15436                        point.row += 1;
15437                        point = snapshot.clip_point(point, Bias::Left);
15438                        let display_point = point.to_display_point(display_snapshot);
15439                        let goal = SelectionGoal::HorizontalPosition(
15440                            display_snapshot
15441                                .x_for_display_point(display_point, text_layout_details)
15442                                .into(),
15443                        );
15444                        (display_point, goal)
15445                    })
15446                });
15447            }
15448        });
15449    }
15450
15451    pub fn select_enclosing_symbol(
15452        &mut self,
15453        _: &SelectEnclosingSymbol,
15454        window: &mut Window,
15455        cx: &mut Context<Self>,
15456    ) {
15457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15458
15459        let buffer = self.buffer.read(cx).snapshot(cx);
15460        let old_selections = self
15461            .selections
15462            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15463            .into_boxed_slice();
15464
15465        fn update_selection(
15466            selection: &Selection<MultiBufferOffset>,
15467            buffer_snap: &MultiBufferSnapshot,
15468        ) -> Option<Selection<MultiBufferOffset>> {
15469            let cursor = selection.head();
15470            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15471            for symbol in symbols.iter().rev() {
15472                let start = symbol.range.start.to_offset(buffer_snap);
15473                let end = symbol.range.end.to_offset(buffer_snap);
15474                let new_range = start..end;
15475                if start < selection.start || end > selection.end {
15476                    return Some(Selection {
15477                        id: selection.id,
15478                        start: new_range.start,
15479                        end: new_range.end,
15480                        goal: SelectionGoal::None,
15481                        reversed: selection.reversed,
15482                    });
15483                }
15484            }
15485            None
15486        }
15487
15488        let mut selected_larger_symbol = false;
15489        let new_selections = old_selections
15490            .iter()
15491            .map(|selection| match update_selection(selection, &buffer) {
15492                Some(new_selection) => {
15493                    if new_selection.range() != selection.range() {
15494                        selected_larger_symbol = true;
15495                    }
15496                    new_selection
15497                }
15498                None => selection.clone(),
15499            })
15500            .collect::<Vec<_>>();
15501
15502        if selected_larger_symbol {
15503            self.change_selections(Default::default(), window, cx, |s| {
15504                s.select(new_selections);
15505            });
15506        }
15507    }
15508
15509    pub fn select_larger_syntax_node(
15510        &mut self,
15511        _: &SelectLargerSyntaxNode,
15512        window: &mut Window,
15513        cx: &mut Context<Self>,
15514    ) {
15515        let Some(visible_row_count) = self.visible_row_count() else {
15516            return;
15517        };
15518        let old_selections: Box<[_]> = self
15519            .selections
15520            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15521            .into();
15522        if old_selections.is_empty() {
15523            return;
15524        }
15525
15526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15527
15528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15529        let buffer = self.buffer.read(cx).snapshot(cx);
15530
15531        let mut selected_larger_node = false;
15532        let mut new_selections = old_selections
15533            .iter()
15534            .map(|selection| {
15535                let old_range = selection.start..selection.end;
15536
15537                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15538                    // manually select word at selection
15539                    if ["string_content", "inline"].contains(&node.kind()) {
15540                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15541                        // ignore if word is already selected
15542                        if !word_range.is_empty() && old_range != word_range {
15543                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15544                            // only select word if start and end point belongs to same word
15545                            if word_range == last_word_range {
15546                                selected_larger_node = true;
15547                                return Selection {
15548                                    id: selection.id,
15549                                    start: word_range.start,
15550                                    end: word_range.end,
15551                                    goal: SelectionGoal::None,
15552                                    reversed: selection.reversed,
15553                                };
15554                            }
15555                        }
15556                    }
15557                }
15558
15559                let mut new_range = old_range.clone();
15560                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15561                    new_range = range;
15562                    if !node.is_named() {
15563                        continue;
15564                    }
15565                    if !display_map.intersects_fold(new_range.start)
15566                        && !display_map.intersects_fold(new_range.end)
15567                    {
15568                        break;
15569                    }
15570                }
15571
15572                selected_larger_node |= new_range != old_range;
15573                Selection {
15574                    id: selection.id,
15575                    start: new_range.start,
15576                    end: new_range.end,
15577                    goal: SelectionGoal::None,
15578                    reversed: selection.reversed,
15579                }
15580            })
15581            .collect::<Vec<_>>();
15582
15583        if !selected_larger_node {
15584            return; // don't put this call in the history
15585        }
15586
15587        // scroll based on transformation done to the last selection created by the user
15588        let (last_old, last_new) = old_selections
15589            .last()
15590            .zip(new_selections.last().cloned())
15591            .expect("old_selections isn't empty");
15592
15593        // revert selection
15594        let is_selection_reversed = {
15595            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15596            new_selections.last_mut().expect("checked above").reversed =
15597                should_newest_selection_be_reversed;
15598            should_newest_selection_be_reversed
15599        };
15600
15601        if selected_larger_node {
15602            self.select_syntax_node_history.disable_clearing = true;
15603            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15604                s.select(new_selections.clone());
15605            });
15606            self.select_syntax_node_history.disable_clearing = false;
15607        }
15608
15609        let start_row = last_new.start.to_display_point(&display_map).row().0;
15610        let end_row = last_new.end.to_display_point(&display_map).row().0;
15611        let selection_height = end_row - start_row + 1;
15612        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15613
15614        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15615        let scroll_behavior = if fits_on_the_screen {
15616            self.request_autoscroll(Autoscroll::fit(), cx);
15617            SelectSyntaxNodeScrollBehavior::FitSelection
15618        } else if is_selection_reversed {
15619            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15620            SelectSyntaxNodeScrollBehavior::CursorTop
15621        } else {
15622            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15623            SelectSyntaxNodeScrollBehavior::CursorBottom
15624        };
15625
15626        self.select_syntax_node_history.push((
15627            old_selections,
15628            scroll_behavior,
15629            is_selection_reversed,
15630        ));
15631    }
15632
15633    pub fn select_smaller_syntax_node(
15634        &mut self,
15635        _: &SelectSmallerSyntaxNode,
15636        window: &mut Window,
15637        cx: &mut Context<Self>,
15638    ) {
15639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15640
15641        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15642            self.select_syntax_node_history.pop()
15643        {
15644            if let Some(selection) = selections.last_mut() {
15645                selection.reversed = is_selection_reversed;
15646            }
15647
15648            self.select_syntax_node_history.disable_clearing = true;
15649            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15650                s.select(selections.to_vec());
15651            });
15652            self.select_syntax_node_history.disable_clearing = false;
15653
15654            match scroll_behavior {
15655                SelectSyntaxNodeScrollBehavior::CursorTop => {
15656                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15657                }
15658                SelectSyntaxNodeScrollBehavior::FitSelection => {
15659                    self.request_autoscroll(Autoscroll::fit(), cx);
15660                }
15661                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15662                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15663                }
15664            }
15665        }
15666    }
15667
15668    pub fn unwrap_syntax_node(
15669        &mut self,
15670        _: &UnwrapSyntaxNode,
15671        window: &mut Window,
15672        cx: &mut Context<Self>,
15673    ) {
15674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15675
15676        let buffer = self.buffer.read(cx).snapshot(cx);
15677        let selections = self
15678            .selections
15679            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15680            .into_iter()
15681            // subtracting the offset requires sorting
15682            .sorted_by_key(|i| i.start);
15683
15684        let full_edits = selections
15685            .into_iter()
15686            .filter_map(|selection| {
15687                let child = if selection.is_empty()
15688                    && let Some((_, ancestor_range)) =
15689                        buffer.syntax_ancestor(selection.start..selection.end)
15690                {
15691                    ancestor_range
15692                } else {
15693                    selection.range()
15694                };
15695
15696                let mut parent = child.clone();
15697                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15698                    parent = ancestor_range;
15699                    if parent.start < child.start || parent.end > child.end {
15700                        break;
15701                    }
15702                }
15703
15704                if parent == child {
15705                    return None;
15706                }
15707                let text = buffer.text_for_range(child).collect::<String>();
15708                Some((selection.id, parent, text))
15709            })
15710            .collect::<Vec<_>>();
15711        if full_edits.is_empty() {
15712            return;
15713        }
15714
15715        self.transact(window, cx, |this, window, cx| {
15716            this.buffer.update(cx, |buffer, cx| {
15717                buffer.edit(
15718                    full_edits
15719                        .iter()
15720                        .map(|(_, p, t)| (p.clone(), t.clone()))
15721                        .collect::<Vec<_>>(),
15722                    None,
15723                    cx,
15724                );
15725            });
15726            this.change_selections(Default::default(), window, cx, |s| {
15727                let mut offset = 0;
15728                let mut selections = vec![];
15729                for (id, parent, text) in full_edits {
15730                    let start = parent.start - offset;
15731                    offset += (parent.end - parent.start) - text.len();
15732                    selections.push(Selection {
15733                        id,
15734                        start,
15735                        end: start + text.len(),
15736                        reversed: false,
15737                        goal: Default::default(),
15738                    });
15739                }
15740                s.select(selections);
15741            });
15742        });
15743    }
15744
15745    pub fn select_next_syntax_node(
15746        &mut self,
15747        _: &SelectNextSyntaxNode,
15748        window: &mut Window,
15749        cx: &mut Context<Self>,
15750    ) {
15751        let old_selections: Box<[_]> = self
15752            .selections
15753            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15754            .into();
15755        if old_selections.is_empty() {
15756            return;
15757        }
15758
15759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15760
15761        let buffer = self.buffer.read(cx).snapshot(cx);
15762        let mut selected_sibling = false;
15763
15764        let new_selections = old_selections
15765            .iter()
15766            .map(|selection| {
15767                let old_range = selection.start..selection.end;
15768
15769                let old_range =
15770                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15771                let excerpt = buffer.excerpt_containing(old_range.clone());
15772
15773                if let Some(mut excerpt) = excerpt
15774                    && let Some(node) = excerpt
15775                        .buffer()
15776                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15777                {
15778                    let new_range = excerpt.map_range_from_buffer(
15779                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15780                    );
15781                    selected_sibling = true;
15782                    Selection {
15783                        id: selection.id,
15784                        start: new_range.start,
15785                        end: new_range.end,
15786                        goal: SelectionGoal::None,
15787                        reversed: selection.reversed,
15788                    }
15789                } else {
15790                    selection.clone()
15791                }
15792            })
15793            .collect::<Vec<_>>();
15794
15795        if selected_sibling {
15796            self.change_selections(
15797                SelectionEffects::scroll(Autoscroll::fit()),
15798                window,
15799                cx,
15800                |s| {
15801                    s.select(new_selections);
15802                },
15803            );
15804        }
15805    }
15806
15807    pub fn select_prev_syntax_node(
15808        &mut self,
15809        _: &SelectPreviousSyntaxNode,
15810        window: &mut Window,
15811        cx: &mut Context<Self>,
15812    ) {
15813        let old_selections: Box<[_]> = self
15814            .selections
15815            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15816            .into();
15817        if old_selections.is_empty() {
15818            return;
15819        }
15820
15821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15822
15823        let buffer = self.buffer.read(cx).snapshot(cx);
15824        let mut selected_sibling = false;
15825
15826        let new_selections = old_selections
15827            .iter()
15828            .map(|selection| {
15829                let old_range = selection.start..selection.end;
15830                let old_range =
15831                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15832                let excerpt = buffer.excerpt_containing(old_range.clone());
15833
15834                if let Some(mut excerpt) = excerpt
15835                    && let Some(node) = excerpt
15836                        .buffer()
15837                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15838                {
15839                    let new_range = excerpt.map_range_from_buffer(
15840                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15841                    );
15842                    selected_sibling = true;
15843                    Selection {
15844                        id: selection.id,
15845                        start: new_range.start,
15846                        end: new_range.end,
15847                        goal: SelectionGoal::None,
15848                        reversed: selection.reversed,
15849                    }
15850                } else {
15851                    selection.clone()
15852                }
15853            })
15854            .collect::<Vec<_>>();
15855
15856        if selected_sibling {
15857            self.change_selections(
15858                SelectionEffects::scroll(Autoscroll::fit()),
15859                window,
15860                cx,
15861                |s| {
15862                    s.select(new_selections);
15863                },
15864            );
15865        }
15866    }
15867
15868    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15869        if !EditorSettings::get_global(cx).gutter.runnables {
15870            self.clear_tasks();
15871            return Task::ready(());
15872        }
15873        let project = self.project().map(Entity::downgrade);
15874        let task_sources = self.lsp_task_sources(cx);
15875        let multi_buffer = self.buffer.downgrade();
15876        cx.spawn_in(window, async move |editor, cx| {
15877            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15878            let Some(project) = project.and_then(|p| p.upgrade()) else {
15879                return;
15880            };
15881            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15882                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15883            }) else {
15884                return;
15885            };
15886
15887            let hide_runnables = project
15888                .update(cx, |project, _| project.is_via_collab())
15889                .unwrap_or(true);
15890            if hide_runnables {
15891                return;
15892            }
15893            let new_rows =
15894                cx.background_spawn({
15895                    let snapshot = display_snapshot.clone();
15896                    async move {
15897                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15898                    }
15899                })
15900                    .await;
15901            let Ok(lsp_tasks) =
15902                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15903            else {
15904                return;
15905            };
15906            let lsp_tasks = lsp_tasks.await;
15907
15908            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15909                lsp_tasks
15910                    .into_iter()
15911                    .flat_map(|(kind, tasks)| {
15912                        tasks.into_iter().filter_map(move |(location, task)| {
15913                            Some((kind.clone(), location?, task))
15914                        })
15915                    })
15916                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15917                        let buffer = location.target.buffer;
15918                        let buffer_snapshot = buffer.read(cx).snapshot();
15919                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15920                            |(excerpt_id, snapshot, _)| {
15921                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15922                                    display_snapshot
15923                                        .buffer_snapshot()
15924                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15925                                } else {
15926                                    None
15927                                }
15928                            },
15929                        );
15930                        if let Some(offset) = offset {
15931                            let task_buffer_range =
15932                                location.target.range.to_point(&buffer_snapshot);
15933                            let context_buffer_range =
15934                                task_buffer_range.to_offset(&buffer_snapshot);
15935                            let context_range = BufferOffset(context_buffer_range.start)
15936                                ..BufferOffset(context_buffer_range.end);
15937
15938                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15939                                .or_insert_with(|| RunnableTasks {
15940                                    templates: Vec::new(),
15941                                    offset,
15942                                    column: task_buffer_range.start.column,
15943                                    extra_variables: HashMap::default(),
15944                                    context_range,
15945                                })
15946                                .templates
15947                                .push((kind, task.original_task().clone()));
15948                        }
15949
15950                        acc
15951                    })
15952            }) else {
15953                return;
15954            };
15955
15956            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15957                buffer.language_settings(cx).tasks.prefer_lsp
15958            }) else {
15959                return;
15960            };
15961
15962            let rows = Self::runnable_rows(
15963                project,
15964                display_snapshot,
15965                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15966                new_rows,
15967                cx.clone(),
15968            )
15969            .await;
15970            editor
15971                .update(cx, |editor, _| {
15972                    editor.clear_tasks();
15973                    for (key, mut value) in rows {
15974                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15975                            value.templates.extend(lsp_tasks.templates);
15976                        }
15977
15978                        editor.insert_tasks(key, value);
15979                    }
15980                    for (key, value) in lsp_tasks_by_rows {
15981                        editor.insert_tasks(key, value);
15982                    }
15983                })
15984                .ok();
15985        })
15986    }
15987    fn fetch_runnable_ranges(
15988        snapshot: &DisplaySnapshot,
15989        range: Range<Anchor>,
15990    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15991        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15992    }
15993
15994    fn runnable_rows(
15995        project: Entity<Project>,
15996        snapshot: DisplaySnapshot,
15997        prefer_lsp: bool,
15998        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
15999        cx: AsyncWindowContext,
16000    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16001        cx.spawn(async move |cx| {
16002            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16003            for (run_range, mut runnable) in runnable_ranges {
16004                let Some(tasks) = cx
16005                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16006                    .ok()
16007                else {
16008                    continue;
16009                };
16010                let mut tasks = tasks.await;
16011
16012                if prefer_lsp {
16013                    tasks.retain(|(task_kind, _)| {
16014                        !matches!(task_kind, TaskSourceKind::Language { .. })
16015                    });
16016                }
16017                if tasks.is_empty() {
16018                    continue;
16019                }
16020
16021                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16022                let Some(row) = snapshot
16023                    .buffer_snapshot()
16024                    .buffer_line_for_row(MultiBufferRow(point.row))
16025                    .map(|(_, range)| range.start.row)
16026                else {
16027                    continue;
16028                };
16029
16030                let context_range =
16031                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16032                runnable_rows.push((
16033                    (runnable.buffer_id, row),
16034                    RunnableTasks {
16035                        templates: tasks,
16036                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16037                        context_range,
16038                        column: point.column,
16039                        extra_variables: runnable.extra_captures,
16040                    },
16041                ));
16042            }
16043            runnable_rows
16044        })
16045    }
16046
16047    fn templates_with_tags(
16048        project: &Entity<Project>,
16049        runnable: &mut Runnable,
16050        cx: &mut App,
16051    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16052        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16053            let (worktree_id, file) = project
16054                .buffer_for_id(runnable.buffer, cx)
16055                .and_then(|buffer| buffer.read(cx).file())
16056                .map(|file| (file.worktree_id(cx), file.clone()))
16057                .unzip();
16058
16059            (
16060                project.task_store().read(cx).task_inventory().cloned(),
16061                worktree_id,
16062                file,
16063            )
16064        });
16065
16066        let tags = mem::take(&mut runnable.tags);
16067        let language = runnable.language.clone();
16068        cx.spawn(async move |cx| {
16069            let mut templates_with_tags = Vec::new();
16070            if let Some(inventory) = inventory {
16071                for RunnableTag(tag) in tags {
16072                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16073                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16074                    }) else {
16075                        return templates_with_tags;
16076                    };
16077                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16078                        move |(_, template)| {
16079                            template.tags.iter().any(|source_tag| source_tag == &tag)
16080                        },
16081                    ));
16082                }
16083            }
16084            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16085
16086            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16087                // Strongest source wins; if we have worktree tag binding, prefer that to
16088                // global and language bindings;
16089                // if we have a global binding, prefer that to language binding.
16090                let first_mismatch = templates_with_tags
16091                    .iter()
16092                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16093                if let Some(index) = first_mismatch {
16094                    templates_with_tags.truncate(index);
16095                }
16096            }
16097
16098            templates_with_tags
16099        })
16100    }
16101
16102    pub fn move_to_enclosing_bracket(
16103        &mut self,
16104        _: &MoveToEnclosingBracket,
16105        window: &mut Window,
16106        cx: &mut Context<Self>,
16107    ) {
16108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16109        self.change_selections(Default::default(), window, cx, |s| {
16110            s.move_offsets_with(|snapshot, selection| {
16111                let Some(enclosing_bracket_ranges) =
16112                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16113                else {
16114                    return;
16115                };
16116
16117                let mut best_length = usize::MAX;
16118                let mut best_inside = false;
16119                let mut best_in_bracket_range = false;
16120                let mut best_destination = None;
16121                for (open, close) in enclosing_bracket_ranges {
16122                    let close = close.to_inclusive();
16123                    let length = *close.end() - open.start;
16124                    let inside = selection.start >= open.end && selection.end <= *close.start();
16125                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16126                        || close.contains(&selection.head());
16127
16128                    // If best is next to a bracket and current isn't, skip
16129                    if !in_bracket_range && best_in_bracket_range {
16130                        continue;
16131                    }
16132
16133                    // Prefer smaller lengths unless best is inside and current isn't
16134                    if length > best_length && (best_inside || !inside) {
16135                        continue;
16136                    }
16137
16138                    best_length = length;
16139                    best_inside = inside;
16140                    best_in_bracket_range = in_bracket_range;
16141                    best_destination = Some(
16142                        if close.contains(&selection.start) && close.contains(&selection.end) {
16143                            if inside { open.end } else { open.start }
16144                        } else if inside {
16145                            *close.start()
16146                        } else {
16147                            *close.end()
16148                        },
16149                    );
16150                }
16151
16152                if let Some(destination) = best_destination {
16153                    selection.collapse_to(destination, SelectionGoal::None);
16154                }
16155            })
16156        });
16157    }
16158
16159    pub fn undo_selection(
16160        &mut self,
16161        _: &UndoSelection,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) {
16165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16166        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16167            self.selection_history.mode = SelectionHistoryMode::Undoing;
16168            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16169                this.end_selection(window, cx);
16170                this.change_selections(
16171                    SelectionEffects::scroll(Autoscroll::newest()),
16172                    window,
16173                    cx,
16174                    |s| s.select_anchors(entry.selections.to_vec()),
16175                );
16176            });
16177            self.selection_history.mode = SelectionHistoryMode::Normal;
16178
16179            self.select_next_state = entry.select_next_state;
16180            self.select_prev_state = entry.select_prev_state;
16181            self.add_selections_state = entry.add_selections_state;
16182        }
16183    }
16184
16185    pub fn redo_selection(
16186        &mut self,
16187        _: &RedoSelection,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16192        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16193            self.selection_history.mode = SelectionHistoryMode::Redoing;
16194            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16195                this.end_selection(window, cx);
16196                this.change_selections(
16197                    SelectionEffects::scroll(Autoscroll::newest()),
16198                    window,
16199                    cx,
16200                    |s| s.select_anchors(entry.selections.to_vec()),
16201                );
16202            });
16203            self.selection_history.mode = SelectionHistoryMode::Normal;
16204
16205            self.select_next_state = entry.select_next_state;
16206            self.select_prev_state = entry.select_prev_state;
16207            self.add_selections_state = entry.add_selections_state;
16208        }
16209    }
16210
16211    pub fn expand_excerpts(
16212        &mut self,
16213        action: &ExpandExcerpts,
16214        _: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) {
16217        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16218    }
16219
16220    pub fn expand_excerpts_down(
16221        &mut self,
16222        action: &ExpandExcerptsDown,
16223        _: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) {
16226        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16227    }
16228
16229    pub fn expand_excerpts_up(
16230        &mut self,
16231        action: &ExpandExcerptsUp,
16232        _: &mut Window,
16233        cx: &mut Context<Self>,
16234    ) {
16235        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16236    }
16237
16238    pub fn expand_excerpts_for_direction(
16239        &mut self,
16240        lines: u32,
16241        direction: ExpandExcerptDirection,
16242
16243        cx: &mut Context<Self>,
16244    ) {
16245        let selections = self.selections.disjoint_anchors_arc();
16246
16247        let lines = if lines == 0 {
16248            EditorSettings::get_global(cx).expand_excerpt_lines
16249        } else {
16250            lines
16251        };
16252
16253        self.buffer.update(cx, |buffer, cx| {
16254            let snapshot = buffer.snapshot(cx);
16255            let mut excerpt_ids = selections
16256                .iter()
16257                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16258                .collect::<Vec<_>>();
16259            excerpt_ids.sort();
16260            excerpt_ids.dedup();
16261            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16262        })
16263    }
16264
16265    pub fn expand_excerpt(
16266        &mut self,
16267        excerpt: ExcerptId,
16268        direction: ExpandExcerptDirection,
16269        window: &mut Window,
16270        cx: &mut Context<Self>,
16271    ) {
16272        let current_scroll_position = self.scroll_position(cx);
16273        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16274        let mut scroll = None;
16275
16276        if direction == ExpandExcerptDirection::Down {
16277            let multi_buffer = self.buffer.read(cx);
16278            let snapshot = multi_buffer.snapshot(cx);
16279            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16280                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16281                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16282            {
16283                let buffer_snapshot = buffer.read(cx).snapshot();
16284                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16285                let last_row = buffer_snapshot.max_point().row;
16286                let lines_below = last_row.saturating_sub(excerpt_end_row);
16287                if lines_below >= lines_to_expand {
16288                    scroll = Some(
16289                        current_scroll_position
16290                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16291                    );
16292                }
16293            }
16294        }
16295        if direction == ExpandExcerptDirection::Up
16296            && self
16297                .buffer
16298                .read(cx)
16299                .snapshot(cx)
16300                .excerpt_before(excerpt)
16301                .is_none()
16302        {
16303            scroll = Some(current_scroll_position);
16304        }
16305
16306        self.buffer.update(cx, |buffer, cx| {
16307            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16308        });
16309
16310        if let Some(new_scroll_position) = scroll {
16311            self.set_scroll_position(new_scroll_position, window, cx);
16312        }
16313    }
16314
16315    pub fn go_to_singleton_buffer_point(
16316        &mut self,
16317        point: Point,
16318        window: &mut Window,
16319        cx: &mut Context<Self>,
16320    ) {
16321        self.go_to_singleton_buffer_range(point..point, window, cx);
16322    }
16323
16324    pub fn go_to_singleton_buffer_range(
16325        &mut self,
16326        range: Range<Point>,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) {
16330        let multibuffer = self.buffer().read(cx);
16331        let Some(buffer) = multibuffer.as_singleton() else {
16332            return;
16333        };
16334        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16335            return;
16336        };
16337        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16338            return;
16339        };
16340        self.change_selections(
16341            SelectionEffects::default().nav_history(true),
16342            window,
16343            cx,
16344            |s| s.select_anchor_ranges([start..end]),
16345        );
16346    }
16347
16348    pub fn go_to_diagnostic(
16349        &mut self,
16350        action: &GoToDiagnostic,
16351        window: &mut Window,
16352        cx: &mut Context<Self>,
16353    ) {
16354        if !self.diagnostics_enabled() {
16355            return;
16356        }
16357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16358        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16359    }
16360
16361    pub fn go_to_prev_diagnostic(
16362        &mut self,
16363        action: &GoToPreviousDiagnostic,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) {
16367        if !self.diagnostics_enabled() {
16368            return;
16369        }
16370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16371        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16372    }
16373
16374    pub fn go_to_diagnostic_impl(
16375        &mut self,
16376        direction: Direction,
16377        severity: GoToDiagnosticSeverityFilter,
16378        window: &mut Window,
16379        cx: &mut Context<Self>,
16380    ) {
16381        let buffer = self.buffer.read(cx).snapshot(cx);
16382        let selection = self
16383            .selections
16384            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16385
16386        let mut active_group_id = None;
16387        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16388            && active_group.active_range.start.to_offset(&buffer) == selection.start
16389        {
16390            active_group_id = Some(active_group.group_id);
16391        }
16392
16393        fn filtered<'a>(
16394            severity: GoToDiagnosticSeverityFilter,
16395            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16396        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16397            diagnostics
16398                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16399                .filter(|entry| entry.range.start != entry.range.end)
16400                .filter(|entry| !entry.diagnostic.is_unnecessary)
16401        }
16402
16403        let before = filtered(
16404            severity,
16405            buffer
16406                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16407                .filter(|entry| entry.range.start <= selection.start),
16408        );
16409        let after = filtered(
16410            severity,
16411            buffer
16412                .diagnostics_in_range(selection.start..buffer.len())
16413                .filter(|entry| entry.range.start >= selection.start),
16414        );
16415
16416        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16417        if direction == Direction::Prev {
16418            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16419            {
16420                for diagnostic in prev_diagnostics.into_iter().rev() {
16421                    if diagnostic.range.start != selection.start
16422                        || active_group_id
16423                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16424                    {
16425                        found = Some(diagnostic);
16426                        break 'outer;
16427                    }
16428                }
16429            }
16430        } else {
16431            for diagnostic in after.chain(before) {
16432                if diagnostic.range.start != selection.start
16433                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16434                {
16435                    found = Some(diagnostic);
16436                    break;
16437                }
16438            }
16439        }
16440        let Some(next_diagnostic) = found else {
16441            return;
16442        };
16443
16444        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16445        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16446            return;
16447        };
16448        let snapshot = self.snapshot(window, cx);
16449        if snapshot.intersects_fold(next_diagnostic.range.start) {
16450            self.unfold_ranges(
16451                std::slice::from_ref(&next_diagnostic.range),
16452                true,
16453                false,
16454                cx,
16455            );
16456        }
16457        self.change_selections(Default::default(), window, cx, |s| {
16458            s.select_ranges(vec![
16459                next_diagnostic.range.start..next_diagnostic.range.start,
16460            ])
16461        });
16462        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16463        self.refresh_edit_prediction(false, true, window, cx);
16464    }
16465
16466    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16468        let snapshot = self.snapshot(window, cx);
16469        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16470        self.go_to_hunk_before_or_after_position(
16471            &snapshot,
16472            selection.head(),
16473            Direction::Next,
16474            window,
16475            cx,
16476        );
16477    }
16478
16479    pub fn go_to_hunk_before_or_after_position(
16480        &mut self,
16481        snapshot: &EditorSnapshot,
16482        position: Point,
16483        direction: Direction,
16484        window: &mut Window,
16485        cx: &mut Context<Editor>,
16486    ) {
16487        let row = if direction == Direction::Next {
16488            self.hunk_after_position(snapshot, position)
16489                .map(|hunk| hunk.row_range.start)
16490        } else {
16491            self.hunk_before_position(snapshot, position)
16492        };
16493
16494        if let Some(row) = row {
16495            let destination = Point::new(row.0, 0);
16496            let autoscroll = Autoscroll::center();
16497
16498            self.unfold_ranges(&[destination..destination], false, false, cx);
16499            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16500                s.select_ranges([destination..destination]);
16501            });
16502        }
16503    }
16504
16505    fn hunk_after_position(
16506        &mut self,
16507        snapshot: &EditorSnapshot,
16508        position: Point,
16509    ) -> Option<MultiBufferDiffHunk> {
16510        snapshot
16511            .buffer_snapshot()
16512            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16513            .find(|hunk| hunk.row_range.start.0 > position.row)
16514            .or_else(|| {
16515                snapshot
16516                    .buffer_snapshot()
16517                    .diff_hunks_in_range(Point::zero()..position)
16518                    .find(|hunk| hunk.row_range.end.0 < position.row)
16519            })
16520    }
16521
16522    fn go_to_prev_hunk(
16523        &mut self,
16524        _: &GoToPreviousHunk,
16525        window: &mut Window,
16526        cx: &mut Context<Self>,
16527    ) {
16528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16529        let snapshot = self.snapshot(window, cx);
16530        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16531        self.go_to_hunk_before_or_after_position(
16532            &snapshot,
16533            selection.head(),
16534            Direction::Prev,
16535            window,
16536            cx,
16537        );
16538    }
16539
16540    fn hunk_before_position(
16541        &mut self,
16542        snapshot: &EditorSnapshot,
16543        position: Point,
16544    ) -> Option<MultiBufferRow> {
16545        snapshot
16546            .buffer_snapshot()
16547            .diff_hunk_before(position)
16548            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16549    }
16550
16551    fn go_to_next_change(
16552        &mut self,
16553        _: &GoToNextChange,
16554        window: &mut Window,
16555        cx: &mut Context<Self>,
16556    ) {
16557        if let Some(selections) = self
16558            .change_list
16559            .next_change(1, Direction::Next)
16560            .map(|s| s.to_vec())
16561        {
16562            self.change_selections(Default::default(), window, cx, |s| {
16563                let map = s.display_snapshot();
16564                s.select_display_ranges(selections.iter().map(|a| {
16565                    let point = a.to_display_point(&map);
16566                    point..point
16567                }))
16568            })
16569        }
16570    }
16571
16572    fn go_to_previous_change(
16573        &mut self,
16574        _: &GoToPreviousChange,
16575        window: &mut Window,
16576        cx: &mut Context<Self>,
16577    ) {
16578        if let Some(selections) = self
16579            .change_list
16580            .next_change(1, Direction::Prev)
16581            .map(|s| s.to_vec())
16582        {
16583            self.change_selections(Default::default(), window, cx, |s| {
16584                let map = s.display_snapshot();
16585                s.select_display_ranges(selections.iter().map(|a| {
16586                    let point = a.to_display_point(&map);
16587                    point..point
16588                }))
16589            })
16590        }
16591    }
16592
16593    pub fn go_to_next_document_highlight(
16594        &mut self,
16595        _: &GoToNextDocumentHighlight,
16596        window: &mut Window,
16597        cx: &mut Context<Self>,
16598    ) {
16599        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16600    }
16601
16602    pub fn go_to_prev_document_highlight(
16603        &mut self,
16604        _: &GoToPreviousDocumentHighlight,
16605        window: &mut Window,
16606        cx: &mut Context<Self>,
16607    ) {
16608        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16609    }
16610
16611    pub fn go_to_document_highlight_before_or_after_position(
16612        &mut self,
16613        direction: Direction,
16614        window: &mut Window,
16615        cx: &mut Context<Editor>,
16616    ) {
16617        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16618        let snapshot = self.snapshot(window, cx);
16619        let buffer = &snapshot.buffer_snapshot();
16620        let position = self
16621            .selections
16622            .newest::<Point>(&snapshot.display_snapshot)
16623            .head();
16624        let anchor_position = buffer.anchor_after(position);
16625
16626        // Get all document highlights (both read and write)
16627        let mut all_highlights = Vec::new();
16628
16629        if let Some((_, read_highlights)) = self
16630            .background_highlights
16631            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16632        {
16633            all_highlights.extend(read_highlights.iter());
16634        }
16635
16636        if let Some((_, write_highlights)) = self
16637            .background_highlights
16638            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16639        {
16640            all_highlights.extend(write_highlights.iter());
16641        }
16642
16643        if all_highlights.is_empty() {
16644            return;
16645        }
16646
16647        // Sort highlights by position
16648        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16649
16650        let target_highlight = match direction {
16651            Direction::Next => {
16652                // Find the first highlight after the current position
16653                all_highlights
16654                    .iter()
16655                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16656            }
16657            Direction::Prev => {
16658                // Find the last highlight before the current position
16659                all_highlights
16660                    .iter()
16661                    .rev()
16662                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16663            }
16664        };
16665
16666        if let Some(highlight) = target_highlight {
16667            let destination = highlight.start.to_point(buffer);
16668            let autoscroll = Autoscroll::center();
16669
16670            self.unfold_ranges(&[destination..destination], false, false, cx);
16671            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16672                s.select_ranges([destination..destination]);
16673            });
16674        }
16675    }
16676
16677    fn go_to_line<T: 'static>(
16678        &mut self,
16679        position: Anchor,
16680        highlight_color: Option<Hsla>,
16681        window: &mut Window,
16682        cx: &mut Context<Self>,
16683    ) {
16684        let snapshot = self.snapshot(window, cx).display_snapshot;
16685        let position = position.to_point(&snapshot.buffer_snapshot());
16686        let start = snapshot
16687            .buffer_snapshot()
16688            .clip_point(Point::new(position.row, 0), Bias::Left);
16689        let end = start + Point::new(1, 0);
16690        let start = snapshot.buffer_snapshot().anchor_before(start);
16691        let end = snapshot.buffer_snapshot().anchor_before(end);
16692
16693        self.highlight_rows::<T>(
16694            start..end,
16695            highlight_color
16696                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16697            Default::default(),
16698            cx,
16699        );
16700
16701        if self.buffer.read(cx).is_singleton() {
16702            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16703        }
16704    }
16705
16706    pub fn go_to_definition(
16707        &mut self,
16708        _: &GoToDefinition,
16709        window: &mut Window,
16710        cx: &mut Context<Self>,
16711    ) -> Task<Result<Navigated>> {
16712        let definition =
16713            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16714        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16715        cx.spawn_in(window, async move |editor, cx| {
16716            if definition.await? == Navigated::Yes {
16717                return Ok(Navigated::Yes);
16718            }
16719            match fallback_strategy {
16720                GoToDefinitionFallback::None => Ok(Navigated::No),
16721                GoToDefinitionFallback::FindAllReferences => {
16722                    match editor.update_in(cx, |editor, window, cx| {
16723                        editor.find_all_references(&FindAllReferences, window, cx)
16724                    })? {
16725                        Some(references) => references.await,
16726                        None => Ok(Navigated::No),
16727                    }
16728                }
16729            }
16730        })
16731    }
16732
16733    pub fn go_to_declaration(
16734        &mut self,
16735        _: &GoToDeclaration,
16736        window: &mut Window,
16737        cx: &mut Context<Self>,
16738    ) -> Task<Result<Navigated>> {
16739        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16740    }
16741
16742    pub fn go_to_declaration_split(
16743        &mut self,
16744        _: &GoToDeclaration,
16745        window: &mut Window,
16746        cx: &mut Context<Self>,
16747    ) -> Task<Result<Navigated>> {
16748        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16749    }
16750
16751    pub fn go_to_implementation(
16752        &mut self,
16753        _: &GoToImplementation,
16754        window: &mut Window,
16755        cx: &mut Context<Self>,
16756    ) -> Task<Result<Navigated>> {
16757        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16758    }
16759
16760    pub fn go_to_implementation_split(
16761        &mut self,
16762        _: &GoToImplementationSplit,
16763        window: &mut Window,
16764        cx: &mut Context<Self>,
16765    ) -> Task<Result<Navigated>> {
16766        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16767    }
16768
16769    pub fn go_to_type_definition(
16770        &mut self,
16771        _: &GoToTypeDefinition,
16772        window: &mut Window,
16773        cx: &mut Context<Self>,
16774    ) -> Task<Result<Navigated>> {
16775        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16776    }
16777
16778    pub fn go_to_definition_split(
16779        &mut self,
16780        _: &GoToDefinitionSplit,
16781        window: &mut Window,
16782        cx: &mut Context<Self>,
16783    ) -> Task<Result<Navigated>> {
16784        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16785    }
16786
16787    pub fn go_to_type_definition_split(
16788        &mut self,
16789        _: &GoToTypeDefinitionSplit,
16790        window: &mut Window,
16791        cx: &mut Context<Self>,
16792    ) -> Task<Result<Navigated>> {
16793        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16794    }
16795
16796    fn go_to_definition_of_kind(
16797        &mut self,
16798        kind: GotoDefinitionKind,
16799        split: bool,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) -> Task<Result<Navigated>> {
16803        let Some(provider) = self.semantics_provider.clone() else {
16804            return Task::ready(Ok(Navigated::No));
16805        };
16806        let head = self
16807            .selections
16808            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16809            .head();
16810        let buffer = self.buffer.read(cx);
16811        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16812            return Task::ready(Ok(Navigated::No));
16813        };
16814        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16815            return Task::ready(Ok(Navigated::No));
16816        };
16817
16818        cx.spawn_in(window, async move |editor, cx| {
16819            let Some(definitions) = definitions.await? else {
16820                return Ok(Navigated::No);
16821            };
16822            let navigated = editor
16823                .update_in(cx, |editor, window, cx| {
16824                    editor.navigate_to_hover_links(
16825                        Some(kind),
16826                        definitions
16827                            .into_iter()
16828                            .filter(|location| {
16829                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16830                            })
16831                            .map(HoverLink::Text)
16832                            .collect::<Vec<_>>(),
16833                        split,
16834                        window,
16835                        cx,
16836                    )
16837                })?
16838                .await?;
16839            anyhow::Ok(navigated)
16840        })
16841    }
16842
16843    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16844        let selection = self.selections.newest_anchor();
16845        let head = selection.head();
16846        let tail = selection.tail();
16847
16848        let Some((buffer, start_position)) =
16849            self.buffer.read(cx).text_anchor_for_position(head, cx)
16850        else {
16851            return;
16852        };
16853
16854        let end_position = if head != tail {
16855            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16856                return;
16857            };
16858            Some(pos)
16859        } else {
16860            None
16861        };
16862
16863        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16864            let url = if let Some(end_pos) = end_position {
16865                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16866            } else {
16867                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16868            };
16869
16870            if let Some(url) = url {
16871                cx.update(|window, cx| {
16872                    if parse_zed_link(&url, cx).is_some() {
16873                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16874                    } else {
16875                        cx.open_url(&url);
16876                    }
16877                })?;
16878            }
16879
16880            anyhow::Ok(())
16881        });
16882
16883        url_finder.detach();
16884    }
16885
16886    pub fn open_selected_filename(
16887        &mut self,
16888        _: &OpenSelectedFilename,
16889        window: &mut Window,
16890        cx: &mut Context<Self>,
16891    ) {
16892        let Some(workspace) = self.workspace() else {
16893            return;
16894        };
16895
16896        let position = self.selections.newest_anchor().head();
16897
16898        let Some((buffer, buffer_position)) =
16899            self.buffer.read(cx).text_anchor_for_position(position, cx)
16900        else {
16901            return;
16902        };
16903
16904        let project = self.project.clone();
16905
16906        cx.spawn_in(window, async move |_, cx| {
16907            let result = find_file(&buffer, project, buffer_position, cx).await;
16908
16909            if let Some((_, path)) = result {
16910                workspace
16911                    .update_in(cx, |workspace, window, cx| {
16912                        workspace.open_resolved_path(path, window, cx)
16913                    })?
16914                    .await?;
16915            }
16916            anyhow::Ok(())
16917        })
16918        .detach();
16919    }
16920
16921    pub(crate) fn navigate_to_hover_links(
16922        &mut self,
16923        kind: Option<GotoDefinitionKind>,
16924        definitions: Vec<HoverLink>,
16925        split: bool,
16926        window: &mut Window,
16927        cx: &mut Context<Editor>,
16928    ) -> Task<Result<Navigated>> {
16929        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16930        let mut first_url_or_file = None;
16931        let definitions: Vec<_> = definitions
16932            .into_iter()
16933            .filter_map(|def| match def {
16934                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16935                HoverLink::InlayHint(lsp_location, server_id) => {
16936                    let computation =
16937                        self.compute_target_location(lsp_location, server_id, window, cx);
16938                    Some(cx.background_spawn(computation))
16939                }
16940                HoverLink::Url(url) => {
16941                    first_url_or_file = Some(Either::Left(url));
16942                    None
16943                }
16944                HoverLink::File(path) => {
16945                    first_url_or_file = Some(Either::Right(path));
16946                    None
16947                }
16948            })
16949            .collect();
16950
16951        let workspace = self.workspace();
16952
16953        cx.spawn_in(window, async move |editor, cx| {
16954            let locations: Vec<Location> = future::join_all(definitions)
16955                .await
16956                .into_iter()
16957                .filter_map(|location| location.transpose())
16958                .collect::<Result<_>>()
16959                .context("location tasks")?;
16960            let mut locations = cx.update(|_, cx| {
16961                locations
16962                    .into_iter()
16963                    .map(|location| {
16964                        let buffer = location.buffer.read(cx);
16965                        (location.buffer, location.range.to_point(buffer))
16966                    })
16967                    .into_group_map()
16968            })?;
16969            let mut num_locations = 0;
16970            for ranges in locations.values_mut() {
16971                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16972                ranges.dedup();
16973                num_locations += ranges.len();
16974            }
16975
16976            if num_locations > 1 {
16977                let Some(workspace) = workspace else {
16978                    return Ok(Navigated::No);
16979                };
16980
16981                let tab_kind = match kind {
16982                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16983                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16984                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16985                    Some(GotoDefinitionKind::Type) => "Types",
16986                };
16987                let title = editor
16988                    .update_in(cx, |_, _, cx| {
16989                        let target = locations
16990                            .iter()
16991                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16992                            .map(|(buffer, location)| {
16993                                buffer
16994                                    .read(cx)
16995                                    .text_for_range(location.clone())
16996                                    .collect::<String>()
16997                            })
16998                            .filter(|text| !text.contains('\n'))
16999                            .unique()
17000                            .take(3)
17001                            .join(", ");
17002                        if target.is_empty() {
17003                            tab_kind.to_owned()
17004                        } else {
17005                            format!("{tab_kind} for {target}")
17006                        }
17007                    })
17008                    .context("buffer title")?;
17009
17010                let opened = workspace
17011                    .update_in(cx, |workspace, window, cx| {
17012                        Self::open_locations_in_multibuffer(
17013                            workspace,
17014                            locations,
17015                            title,
17016                            split,
17017                            MultibufferSelectionMode::First,
17018                            window,
17019                            cx,
17020                        )
17021                    })
17022                    .is_ok();
17023
17024                anyhow::Ok(Navigated::from_bool(opened))
17025            } else if num_locations == 0 {
17026                // If there is one url or file, open it directly
17027                match first_url_or_file {
17028                    Some(Either::Left(url)) => {
17029                        cx.update(|_, cx| cx.open_url(&url))?;
17030                        Ok(Navigated::Yes)
17031                    }
17032                    Some(Either::Right(path)) => {
17033                        let Some(workspace) = workspace else {
17034                            return Ok(Navigated::No);
17035                        };
17036
17037                        workspace
17038                            .update_in(cx, |workspace, window, cx| {
17039                                workspace.open_resolved_path(path, window, cx)
17040                            })?
17041                            .await?;
17042                        Ok(Navigated::Yes)
17043                    }
17044                    None => Ok(Navigated::No),
17045                }
17046            } else {
17047                let Some(workspace) = workspace else {
17048                    return Ok(Navigated::No);
17049                };
17050
17051                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17052                let target_range = target_ranges.first().unwrap().clone();
17053
17054                editor.update_in(cx, |editor, window, cx| {
17055                    let range = target_range.to_point(target_buffer.read(cx));
17056                    let range = editor.range_for_match(&range);
17057                    let range = collapse_multiline_range(range);
17058
17059                    if !split
17060                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17061                    {
17062                        editor.go_to_singleton_buffer_range(range, window, cx);
17063                    } else {
17064                        let pane = workspace.read(cx).active_pane().clone();
17065                        window.defer(cx, move |window, cx| {
17066                            let target_editor: Entity<Self> =
17067                                workspace.update(cx, |workspace, cx| {
17068                                    let pane = if split {
17069                                        workspace.adjacent_pane(window, cx)
17070                                    } else {
17071                                        workspace.active_pane().clone()
17072                                    };
17073
17074                                    workspace.open_project_item(
17075                                        pane,
17076                                        target_buffer.clone(),
17077                                        true,
17078                                        true,
17079                                        window,
17080                                        cx,
17081                                    )
17082                                });
17083                            target_editor.update(cx, |target_editor, cx| {
17084                                // When selecting a definition in a different buffer, disable the nav history
17085                                // to avoid creating a history entry at the previous cursor location.
17086                                pane.update(cx, |pane, _| pane.disable_history());
17087                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17088                                pane.update(cx, |pane, _| pane.enable_history());
17089                            });
17090                        });
17091                    }
17092                    Navigated::Yes
17093                })
17094            }
17095        })
17096    }
17097
17098    fn compute_target_location(
17099        &self,
17100        lsp_location: lsp::Location,
17101        server_id: LanguageServerId,
17102        window: &mut Window,
17103        cx: &mut Context<Self>,
17104    ) -> Task<anyhow::Result<Option<Location>>> {
17105        let Some(project) = self.project.clone() else {
17106            return Task::ready(Ok(None));
17107        };
17108
17109        cx.spawn_in(window, async move |editor, cx| {
17110            let location_task = editor.update(cx, |_, cx| {
17111                project.update(cx, |project, cx| {
17112                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17113                })
17114            })?;
17115            let location = Some({
17116                let target_buffer_handle = location_task.await.context("open local buffer")?;
17117                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17118                    let target_start = target_buffer
17119                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17120                    let target_end = target_buffer
17121                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17122                    target_buffer.anchor_after(target_start)
17123                        ..target_buffer.anchor_before(target_end)
17124                })?;
17125                Location {
17126                    buffer: target_buffer_handle,
17127                    range,
17128                }
17129            });
17130            Ok(location)
17131        })
17132    }
17133
17134    fn go_to_next_reference(
17135        &mut self,
17136        _: &GoToNextReference,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) {
17140        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17141        if let Some(task) = task {
17142            task.detach();
17143        };
17144    }
17145
17146    fn go_to_prev_reference(
17147        &mut self,
17148        _: &GoToPreviousReference,
17149        window: &mut Window,
17150        cx: &mut Context<Self>,
17151    ) {
17152        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17153        if let Some(task) = task {
17154            task.detach();
17155        };
17156    }
17157
17158    pub fn go_to_reference_before_or_after_position(
17159        &mut self,
17160        direction: Direction,
17161        count: usize,
17162        window: &mut Window,
17163        cx: &mut Context<Self>,
17164    ) -> Option<Task<Result<()>>> {
17165        let selection = self.selections.newest_anchor();
17166        let head = selection.head();
17167
17168        let multi_buffer = self.buffer.read(cx);
17169
17170        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17171        let workspace = self.workspace()?;
17172        let project = workspace.read(cx).project().clone();
17173        let references =
17174            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17175        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17176            let Some(locations) = references.await? else {
17177                return Ok(());
17178            };
17179
17180            if locations.is_empty() {
17181                // totally normal - the cursor may be on something which is not
17182                // a symbol (e.g. a keyword)
17183                log::info!("no references found under cursor");
17184                return Ok(());
17185            }
17186
17187            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17188
17189            let (locations, current_location_index) =
17190                multi_buffer.update(cx, |multi_buffer, cx| {
17191                    let mut locations = locations
17192                        .into_iter()
17193                        .filter_map(|loc| {
17194                            let start = multi_buffer.buffer_anchor_to_anchor(
17195                                &loc.buffer,
17196                                loc.range.start,
17197                                cx,
17198                            )?;
17199                            let end = multi_buffer.buffer_anchor_to_anchor(
17200                                &loc.buffer,
17201                                loc.range.end,
17202                                cx,
17203                            )?;
17204                            Some(start..end)
17205                        })
17206                        .collect::<Vec<_>>();
17207
17208                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17209                    // There is an O(n) implementation, but given this list will be
17210                    // small (usually <100 items), the extra O(log(n)) factor isn't
17211                    // worth the (surprisingly large amount of) extra complexity.
17212                    locations
17213                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17214
17215                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17216
17217                    let current_location_index = locations.iter().position(|loc| {
17218                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17219                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17220                    });
17221
17222                    (locations, current_location_index)
17223                })?;
17224
17225            let Some(current_location_index) = current_location_index else {
17226                // This indicates something has gone wrong, because we already
17227                // handle the "no references" case above
17228                log::error!(
17229                    "failed to find current reference under cursor. Total references: {}",
17230                    locations.len()
17231                );
17232                return Ok(());
17233            };
17234
17235            let destination_location_index = match direction {
17236                Direction::Next => (current_location_index + count) % locations.len(),
17237                Direction::Prev => {
17238                    (current_location_index + locations.len() - count % locations.len())
17239                        % locations.len()
17240                }
17241            };
17242
17243            // TODO(cameron): is this needed?
17244            // the thinking is to avoid "jumping to the current location" (avoid
17245            // polluting "jumplist" in vim terms)
17246            if current_location_index == destination_location_index {
17247                return Ok(());
17248            }
17249
17250            let Range { start, end } = locations[destination_location_index];
17251
17252            editor.update_in(cx, |editor, window, cx| {
17253                let effects = SelectionEffects::default();
17254
17255                editor.unfold_ranges(&[start..end], false, false, cx);
17256                editor.change_selections(effects, window, cx, |s| {
17257                    s.select_ranges([start..start]);
17258                });
17259            })?;
17260
17261            Ok(())
17262        }))
17263    }
17264
17265    pub fn find_all_references(
17266        &mut self,
17267        _: &FindAllReferences,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270    ) -> Option<Task<Result<Navigated>>> {
17271        let selection = self
17272            .selections
17273            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17274        let multi_buffer = self.buffer.read(cx);
17275        let head = selection.head();
17276
17277        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17278        let head_anchor = multi_buffer_snapshot.anchor_at(
17279            head,
17280            if head < selection.tail() {
17281                Bias::Right
17282            } else {
17283                Bias::Left
17284            },
17285        );
17286
17287        match self
17288            .find_all_references_task_sources
17289            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17290        {
17291            Ok(_) => {
17292                log::info!(
17293                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17294                );
17295                return None;
17296            }
17297            Err(i) => {
17298                self.find_all_references_task_sources.insert(i, head_anchor);
17299            }
17300        }
17301
17302        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17303        let workspace = self.workspace()?;
17304        let project = workspace.read(cx).project().clone();
17305        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17306        Some(cx.spawn_in(window, async move |editor, cx| {
17307            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17308                if let Ok(i) = editor
17309                    .find_all_references_task_sources
17310                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17311                {
17312                    editor.find_all_references_task_sources.remove(i);
17313                }
17314            });
17315
17316            let Some(locations) = references.await? else {
17317                return anyhow::Ok(Navigated::No);
17318            };
17319            let mut locations = cx.update(|_, cx| {
17320                locations
17321                    .into_iter()
17322                    .map(|location| {
17323                        let buffer = location.buffer.read(cx);
17324                        (location.buffer, location.range.to_point(buffer))
17325                    })
17326                    .into_group_map()
17327            })?;
17328            if locations.is_empty() {
17329                return anyhow::Ok(Navigated::No);
17330            }
17331            for ranges in locations.values_mut() {
17332                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17333                ranges.dedup();
17334            }
17335
17336            workspace.update_in(cx, |workspace, window, cx| {
17337                let target = locations
17338                    .iter()
17339                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17340                    .map(|(buffer, location)| {
17341                        buffer
17342                            .read(cx)
17343                            .text_for_range(location.clone())
17344                            .collect::<String>()
17345                    })
17346                    .filter(|text| !text.contains('\n'))
17347                    .unique()
17348                    .take(3)
17349                    .join(", ");
17350                let title = if target.is_empty() {
17351                    "References".to_owned()
17352                } else {
17353                    format!("References to {target}")
17354                };
17355                Self::open_locations_in_multibuffer(
17356                    workspace,
17357                    locations,
17358                    title,
17359                    false,
17360                    MultibufferSelectionMode::First,
17361                    window,
17362                    cx,
17363                );
17364                Navigated::Yes
17365            })
17366        }))
17367    }
17368
17369    /// Opens a multibuffer with the given project locations in it
17370    pub fn open_locations_in_multibuffer(
17371        workspace: &mut Workspace,
17372        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17373        title: String,
17374        split: bool,
17375        multibuffer_selection_mode: MultibufferSelectionMode,
17376        window: &mut Window,
17377        cx: &mut Context<Workspace>,
17378    ) {
17379        if locations.is_empty() {
17380            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17381            return;
17382        }
17383
17384        let capability = workspace.project().read(cx).capability();
17385        let mut ranges = <Vec<Range<Anchor>>>::new();
17386
17387        // a key to find existing multibuffer editors with the same set of locations
17388        // to prevent us from opening more and more multibuffer tabs for searches and the like
17389        let mut key = (title.clone(), vec![]);
17390        let excerpt_buffer = cx.new(|cx| {
17391            let key = &mut key.1;
17392            let mut multibuffer = MultiBuffer::new(capability);
17393            for (buffer, mut ranges_for_buffer) in locations {
17394                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17395                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17396                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17397                    PathKey::for_buffer(&buffer, cx),
17398                    buffer.clone(),
17399                    ranges_for_buffer,
17400                    multibuffer_context_lines(cx),
17401                    cx,
17402                );
17403                ranges.extend(new_ranges)
17404            }
17405
17406            multibuffer.with_title(title)
17407        });
17408        let existing = workspace.active_pane().update(cx, |pane, cx| {
17409            pane.items()
17410                .filter_map(|item| item.downcast::<Editor>())
17411                .find(|editor| {
17412                    editor
17413                        .read(cx)
17414                        .lookup_key
17415                        .as_ref()
17416                        .and_then(|it| {
17417                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17418                        })
17419                        .is_some_and(|it| *it == key)
17420                })
17421        });
17422        let editor = existing.unwrap_or_else(|| {
17423            cx.new(|cx| {
17424                let mut editor = Editor::for_multibuffer(
17425                    excerpt_buffer,
17426                    Some(workspace.project().clone()),
17427                    window,
17428                    cx,
17429                );
17430                editor.lookup_key = Some(Box::new(key));
17431                editor
17432            })
17433        });
17434        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17435            MultibufferSelectionMode::First => {
17436                if let Some(first_range) = ranges.first() {
17437                    editor.change_selections(
17438                        SelectionEffects::no_scroll(),
17439                        window,
17440                        cx,
17441                        |selections| {
17442                            selections.clear_disjoint();
17443                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17444                        },
17445                    );
17446                }
17447                editor.highlight_background::<Self>(
17448                    &ranges,
17449                    |theme| theme.colors().editor_highlighted_line_background,
17450                    cx,
17451                );
17452            }
17453            MultibufferSelectionMode::All => {
17454                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17455                    selections.clear_disjoint();
17456                    selections.select_anchor_ranges(ranges);
17457                });
17458            }
17459        });
17460
17461        let item = Box::new(editor);
17462        let item_id = item.item_id();
17463
17464        if split {
17465            let pane = workspace.adjacent_pane(window, cx);
17466            workspace.add_item(pane, item, None, true, true, window, cx);
17467        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17468            let (preview_item_id, preview_item_idx) =
17469                workspace.active_pane().read_with(cx, |pane, _| {
17470                    (pane.preview_item_id(), pane.preview_item_idx())
17471                });
17472
17473            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17474
17475            if let Some(preview_item_id) = preview_item_id {
17476                workspace.active_pane().update(cx, |pane, cx| {
17477                    pane.remove_item(preview_item_id, false, false, window, cx);
17478                });
17479            }
17480        } else {
17481            workspace.add_item_to_active_pane(item, None, true, window, cx);
17482        }
17483        workspace.active_pane().update(cx, |pane, cx| {
17484            pane.set_preview_item_id(Some(item_id), cx);
17485        });
17486    }
17487
17488    pub fn rename(
17489        &mut self,
17490        _: &Rename,
17491        window: &mut Window,
17492        cx: &mut Context<Self>,
17493    ) -> Option<Task<Result<()>>> {
17494        use language::ToOffset as _;
17495
17496        let provider = self.semantics_provider.clone()?;
17497        let selection = self.selections.newest_anchor().clone();
17498        let (cursor_buffer, cursor_buffer_position) = self
17499            .buffer
17500            .read(cx)
17501            .text_anchor_for_position(selection.head(), cx)?;
17502        let (tail_buffer, cursor_buffer_position_end) = self
17503            .buffer
17504            .read(cx)
17505            .text_anchor_for_position(selection.tail(), cx)?;
17506        if tail_buffer != cursor_buffer {
17507            return None;
17508        }
17509
17510        let snapshot = cursor_buffer.read(cx).snapshot();
17511        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17512        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17513        let prepare_rename = provider
17514            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17515            .unwrap_or_else(|| Task::ready(Ok(None)));
17516        drop(snapshot);
17517
17518        Some(cx.spawn_in(window, async move |this, cx| {
17519            let rename_range = if let Some(range) = prepare_rename.await? {
17520                Some(range)
17521            } else {
17522                this.update(cx, |this, cx| {
17523                    let buffer = this.buffer.read(cx).snapshot(cx);
17524                    let mut buffer_highlights = this
17525                        .document_highlights_for_position(selection.head(), &buffer)
17526                        .filter(|highlight| {
17527                            highlight.start.excerpt_id == selection.head().excerpt_id
17528                                && highlight.end.excerpt_id == selection.head().excerpt_id
17529                        });
17530                    buffer_highlights
17531                        .next()
17532                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17533                })?
17534            };
17535            if let Some(rename_range) = rename_range {
17536                this.update_in(cx, |this, window, cx| {
17537                    let snapshot = cursor_buffer.read(cx).snapshot();
17538                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17539                    let cursor_offset_in_rename_range =
17540                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17541                    let cursor_offset_in_rename_range_end =
17542                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17543
17544                    this.take_rename(false, window, cx);
17545                    let buffer = this.buffer.read(cx).read(cx);
17546                    let cursor_offset = selection.head().to_offset(&buffer);
17547                    let rename_start =
17548                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17549                    let rename_end = rename_start + rename_buffer_range.len();
17550                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17551                    let mut old_highlight_id = None;
17552                    let old_name: Arc<str> = buffer
17553                        .chunks(rename_start..rename_end, true)
17554                        .map(|chunk| {
17555                            if old_highlight_id.is_none() {
17556                                old_highlight_id = chunk.syntax_highlight_id;
17557                            }
17558                            chunk.text
17559                        })
17560                        .collect::<String>()
17561                        .into();
17562
17563                    drop(buffer);
17564
17565                    // Position the selection in the rename editor so that it matches the current selection.
17566                    this.show_local_selections = false;
17567                    let rename_editor = cx.new(|cx| {
17568                        let mut editor = Editor::single_line(window, cx);
17569                        editor.buffer.update(cx, |buffer, cx| {
17570                            buffer.edit(
17571                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17572                                None,
17573                                cx,
17574                            )
17575                        });
17576                        let cursor_offset_in_rename_range =
17577                            MultiBufferOffset(cursor_offset_in_rename_range);
17578                        let cursor_offset_in_rename_range_end =
17579                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17580                        let rename_selection_range = match cursor_offset_in_rename_range
17581                            .cmp(&cursor_offset_in_rename_range_end)
17582                        {
17583                            Ordering::Equal => {
17584                                editor.select_all(&SelectAll, window, cx);
17585                                return editor;
17586                            }
17587                            Ordering::Less => {
17588                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17589                            }
17590                            Ordering::Greater => {
17591                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17592                            }
17593                        };
17594                        if rename_selection_range.end.0 > old_name.len() {
17595                            editor.select_all(&SelectAll, window, cx);
17596                        } else {
17597                            editor.change_selections(Default::default(), window, cx, |s| {
17598                                s.select_ranges([rename_selection_range]);
17599                            });
17600                        }
17601                        editor
17602                    });
17603                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17604                        if e == &EditorEvent::Focused {
17605                            cx.emit(EditorEvent::FocusedIn)
17606                        }
17607                    })
17608                    .detach();
17609
17610                    let write_highlights =
17611                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17612                    let read_highlights =
17613                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17614                    let ranges = write_highlights
17615                        .iter()
17616                        .flat_map(|(_, ranges)| ranges.iter())
17617                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17618                        .cloned()
17619                        .collect();
17620
17621                    this.highlight_text::<Rename>(
17622                        ranges,
17623                        HighlightStyle {
17624                            fade_out: Some(0.6),
17625                            ..Default::default()
17626                        },
17627                        cx,
17628                    );
17629                    let rename_focus_handle = rename_editor.focus_handle(cx);
17630                    window.focus(&rename_focus_handle);
17631                    let block_id = this.insert_blocks(
17632                        [BlockProperties {
17633                            style: BlockStyle::Flex,
17634                            placement: BlockPlacement::Below(range.start),
17635                            height: Some(1),
17636                            render: Arc::new({
17637                                let rename_editor = rename_editor.clone();
17638                                move |cx: &mut BlockContext| {
17639                                    let mut text_style = cx.editor_style.text.clone();
17640                                    if let Some(highlight_style) = old_highlight_id
17641                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17642                                    {
17643                                        text_style = text_style.highlight(highlight_style);
17644                                    }
17645                                    div()
17646                                        .block_mouse_except_scroll()
17647                                        .pl(cx.anchor_x)
17648                                        .child(EditorElement::new(
17649                                            &rename_editor,
17650                                            EditorStyle {
17651                                                background: cx.theme().system().transparent,
17652                                                local_player: cx.editor_style.local_player,
17653                                                text: text_style,
17654                                                scrollbar_width: cx.editor_style.scrollbar_width,
17655                                                syntax: cx.editor_style.syntax.clone(),
17656                                                status: cx.editor_style.status.clone(),
17657                                                inlay_hints_style: HighlightStyle {
17658                                                    font_weight: Some(FontWeight::BOLD),
17659                                                    ..make_inlay_hints_style(cx.app)
17660                                                },
17661                                                edit_prediction_styles: make_suggestion_styles(
17662                                                    cx.app,
17663                                                ),
17664                                                ..EditorStyle::default()
17665                                            },
17666                                        ))
17667                                        .into_any_element()
17668                                }
17669                            }),
17670                            priority: 0,
17671                        }],
17672                        Some(Autoscroll::fit()),
17673                        cx,
17674                    )[0];
17675                    this.pending_rename = Some(RenameState {
17676                        range,
17677                        old_name,
17678                        editor: rename_editor,
17679                        block_id,
17680                    });
17681                })?;
17682            }
17683
17684            Ok(())
17685        }))
17686    }
17687
17688    pub fn confirm_rename(
17689        &mut self,
17690        _: &ConfirmRename,
17691        window: &mut Window,
17692        cx: &mut Context<Self>,
17693    ) -> Option<Task<Result<()>>> {
17694        let rename = self.take_rename(false, window, cx)?;
17695        let workspace = self.workspace()?.downgrade();
17696        let (buffer, start) = self
17697            .buffer
17698            .read(cx)
17699            .text_anchor_for_position(rename.range.start, cx)?;
17700        let (end_buffer, _) = self
17701            .buffer
17702            .read(cx)
17703            .text_anchor_for_position(rename.range.end, cx)?;
17704        if buffer != end_buffer {
17705            return None;
17706        }
17707
17708        let old_name = rename.old_name;
17709        let new_name = rename.editor.read(cx).text(cx);
17710
17711        let rename = self.semantics_provider.as_ref()?.perform_rename(
17712            &buffer,
17713            start,
17714            new_name.clone(),
17715            cx,
17716        )?;
17717
17718        Some(cx.spawn_in(window, async move |editor, cx| {
17719            let project_transaction = rename.await?;
17720            Self::open_project_transaction(
17721                &editor,
17722                workspace,
17723                project_transaction,
17724                format!("Rename: {}{}", old_name, new_name),
17725                cx,
17726            )
17727            .await?;
17728
17729            editor.update(cx, |editor, cx| {
17730                editor.refresh_document_highlights(cx);
17731            })?;
17732            Ok(())
17733        }))
17734    }
17735
17736    fn take_rename(
17737        &mut self,
17738        moving_cursor: bool,
17739        window: &mut Window,
17740        cx: &mut Context<Self>,
17741    ) -> Option<RenameState> {
17742        let rename = self.pending_rename.take()?;
17743        if rename.editor.focus_handle(cx).is_focused(window) {
17744            window.focus(&self.focus_handle);
17745        }
17746
17747        self.remove_blocks(
17748            [rename.block_id].into_iter().collect(),
17749            Some(Autoscroll::fit()),
17750            cx,
17751        );
17752        self.clear_highlights::<Rename>(cx);
17753        self.show_local_selections = true;
17754
17755        if moving_cursor {
17756            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17757                editor
17758                    .selections
17759                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17760                    .head()
17761            });
17762
17763            // Update the selection to match the position of the selection inside
17764            // the rename editor.
17765            let snapshot = self.buffer.read(cx).read(cx);
17766            let rename_range = rename.range.to_offset(&snapshot);
17767            let cursor_in_editor = snapshot
17768                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17769                .min(rename_range.end);
17770            drop(snapshot);
17771
17772            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17773                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17774            });
17775        } else {
17776            self.refresh_document_highlights(cx);
17777        }
17778
17779        Some(rename)
17780    }
17781
17782    pub fn pending_rename(&self) -> Option<&RenameState> {
17783        self.pending_rename.as_ref()
17784    }
17785
17786    fn format(
17787        &mut self,
17788        _: &Format,
17789        window: &mut Window,
17790        cx: &mut Context<Self>,
17791    ) -> Option<Task<Result<()>>> {
17792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17793
17794        let project = match &self.project {
17795            Some(project) => project.clone(),
17796            None => return None,
17797        };
17798
17799        Some(self.perform_format(
17800            project,
17801            FormatTrigger::Manual,
17802            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17803            window,
17804            cx,
17805        ))
17806    }
17807
17808    fn format_selections(
17809        &mut self,
17810        _: &FormatSelections,
17811        window: &mut Window,
17812        cx: &mut Context<Self>,
17813    ) -> Option<Task<Result<()>>> {
17814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17815
17816        let project = match &self.project {
17817            Some(project) => project.clone(),
17818            None => return None,
17819        };
17820
17821        let ranges = self
17822            .selections
17823            .all_adjusted(&self.display_snapshot(cx))
17824            .into_iter()
17825            .map(|selection| selection.range())
17826            .collect_vec();
17827
17828        Some(self.perform_format(
17829            project,
17830            FormatTrigger::Manual,
17831            FormatTarget::Ranges(ranges),
17832            window,
17833            cx,
17834        ))
17835    }
17836
17837    fn perform_format(
17838        &mut self,
17839        project: Entity<Project>,
17840        trigger: FormatTrigger,
17841        target: FormatTarget,
17842        window: &mut Window,
17843        cx: &mut Context<Self>,
17844    ) -> Task<Result<()>> {
17845        let buffer = self.buffer.clone();
17846        let (buffers, target) = match target {
17847            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17848            FormatTarget::Ranges(selection_ranges) => {
17849                let multi_buffer = buffer.read(cx);
17850                let snapshot = multi_buffer.read(cx);
17851                let mut buffers = HashSet::default();
17852                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17853                    BTreeMap::new();
17854                for selection_range in selection_ranges {
17855                    for (buffer, buffer_range, _) in
17856                        snapshot.range_to_buffer_ranges(selection_range)
17857                    {
17858                        let buffer_id = buffer.remote_id();
17859                        let start = buffer.anchor_before(buffer_range.start);
17860                        let end = buffer.anchor_after(buffer_range.end);
17861                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17862                        buffer_id_to_ranges
17863                            .entry(buffer_id)
17864                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17865                            .or_insert_with(|| vec![start..end]);
17866                    }
17867                }
17868                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17869            }
17870        };
17871
17872        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17873        let selections_prev = transaction_id_prev
17874            .and_then(|transaction_id_prev| {
17875                // default to selections as they were after the last edit, if we have them,
17876                // instead of how they are now.
17877                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17878                // will take you back to where you made the last edit, instead of staying where you scrolled
17879                self.selection_history
17880                    .transaction(transaction_id_prev)
17881                    .map(|t| t.0.clone())
17882            })
17883            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17884
17885        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17886        let format = project.update(cx, |project, cx| {
17887            project.format(buffers, target, true, trigger, cx)
17888        });
17889
17890        cx.spawn_in(window, async move |editor, cx| {
17891            let transaction = futures::select_biased! {
17892                transaction = format.log_err().fuse() => transaction,
17893                () = timeout => {
17894                    log::warn!("timed out waiting for formatting");
17895                    None
17896                }
17897            };
17898
17899            buffer
17900                .update(cx, |buffer, cx| {
17901                    if let Some(transaction) = transaction
17902                        && !buffer.is_singleton()
17903                    {
17904                        buffer.push_transaction(&transaction.0, cx);
17905                    }
17906                    cx.notify();
17907                })
17908                .ok();
17909
17910            if let Some(transaction_id_now) =
17911                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17912            {
17913                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17914                if has_new_transaction {
17915                    _ = editor.update(cx, |editor, _| {
17916                        editor
17917                            .selection_history
17918                            .insert_transaction(transaction_id_now, selections_prev);
17919                    });
17920                }
17921            }
17922
17923            Ok(())
17924        })
17925    }
17926
17927    fn organize_imports(
17928        &mut self,
17929        _: &OrganizeImports,
17930        window: &mut Window,
17931        cx: &mut Context<Self>,
17932    ) -> Option<Task<Result<()>>> {
17933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17934        let project = match &self.project {
17935            Some(project) => project.clone(),
17936            None => return None,
17937        };
17938        Some(self.perform_code_action_kind(
17939            project,
17940            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17941            window,
17942            cx,
17943        ))
17944    }
17945
17946    fn perform_code_action_kind(
17947        &mut self,
17948        project: Entity<Project>,
17949        kind: CodeActionKind,
17950        window: &mut Window,
17951        cx: &mut Context<Self>,
17952    ) -> Task<Result<()>> {
17953        let buffer = self.buffer.clone();
17954        let buffers = buffer.read(cx).all_buffers();
17955        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17956        let apply_action = project.update(cx, |project, cx| {
17957            project.apply_code_action_kind(buffers, kind, true, cx)
17958        });
17959        cx.spawn_in(window, async move |_, cx| {
17960            let transaction = futures::select_biased! {
17961                () = timeout => {
17962                    log::warn!("timed out waiting for executing code action");
17963                    None
17964                }
17965                transaction = apply_action.log_err().fuse() => transaction,
17966            };
17967            buffer
17968                .update(cx, |buffer, cx| {
17969                    // check if we need this
17970                    if let Some(transaction) = transaction
17971                        && !buffer.is_singleton()
17972                    {
17973                        buffer.push_transaction(&transaction.0, cx);
17974                    }
17975                    cx.notify();
17976                })
17977                .ok();
17978            Ok(())
17979        })
17980    }
17981
17982    pub fn restart_language_server(
17983        &mut self,
17984        _: &RestartLanguageServer,
17985        _: &mut Window,
17986        cx: &mut Context<Self>,
17987    ) {
17988        if let Some(project) = self.project.clone() {
17989            self.buffer.update(cx, |multi_buffer, cx| {
17990                project.update(cx, |project, cx| {
17991                    project.restart_language_servers_for_buffers(
17992                        multi_buffer.all_buffers().into_iter().collect(),
17993                        HashSet::default(),
17994                        cx,
17995                    );
17996                });
17997            })
17998        }
17999    }
18000
18001    pub fn stop_language_server(
18002        &mut self,
18003        _: &StopLanguageServer,
18004        _: &mut Window,
18005        cx: &mut Context<Self>,
18006    ) {
18007        if let Some(project) = self.project.clone() {
18008            self.buffer.update(cx, |multi_buffer, cx| {
18009                project.update(cx, |project, cx| {
18010                    project.stop_language_servers_for_buffers(
18011                        multi_buffer.all_buffers().into_iter().collect(),
18012                        HashSet::default(),
18013                        cx,
18014                    );
18015                });
18016            });
18017            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18018        }
18019    }
18020
18021    fn cancel_language_server_work(
18022        workspace: &mut Workspace,
18023        _: &actions::CancelLanguageServerWork,
18024        _: &mut Window,
18025        cx: &mut Context<Workspace>,
18026    ) {
18027        let project = workspace.project();
18028        let buffers = workspace
18029            .active_item(cx)
18030            .and_then(|item| item.act_as::<Editor>(cx))
18031            .map_or(HashSet::default(), |editor| {
18032                editor.read(cx).buffer.read(cx).all_buffers()
18033            });
18034        project.update(cx, |project, cx| {
18035            project.cancel_language_server_work_for_buffers(buffers, cx);
18036        });
18037    }
18038
18039    fn show_character_palette(
18040        &mut self,
18041        _: &ShowCharacterPalette,
18042        window: &mut Window,
18043        _: &mut Context<Self>,
18044    ) {
18045        window.show_character_palette();
18046    }
18047
18048    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18049        if !self.diagnostics_enabled() {
18050            return;
18051        }
18052
18053        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18054            let buffer = self.buffer.read(cx).snapshot(cx);
18055            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18056            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18057            let is_valid = buffer
18058                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18059                .any(|entry| {
18060                    entry.diagnostic.is_primary
18061                        && !entry.range.is_empty()
18062                        && entry.range.start == primary_range_start
18063                        && entry.diagnostic.message == active_diagnostics.active_message
18064                });
18065
18066            if !is_valid {
18067                self.dismiss_diagnostics(cx);
18068            }
18069        }
18070    }
18071
18072    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18073        match &self.active_diagnostics {
18074            ActiveDiagnostic::Group(group) => Some(group),
18075            _ => None,
18076        }
18077    }
18078
18079    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18080        if !self.diagnostics_enabled() {
18081            return;
18082        }
18083        self.dismiss_diagnostics(cx);
18084        self.active_diagnostics = ActiveDiagnostic::All;
18085    }
18086
18087    fn activate_diagnostics(
18088        &mut self,
18089        buffer_id: BufferId,
18090        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18095            return;
18096        }
18097        self.dismiss_diagnostics(cx);
18098        let snapshot = self.snapshot(window, cx);
18099        let buffer = self.buffer.read(cx).snapshot(cx);
18100        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18101            return;
18102        };
18103
18104        let diagnostic_group = buffer
18105            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18106            .collect::<Vec<_>>();
18107
18108        let language_registry = self
18109            .project()
18110            .map(|project| project.read(cx).languages().clone());
18111
18112        let blocks = renderer.render_group(
18113            diagnostic_group,
18114            buffer_id,
18115            snapshot,
18116            cx.weak_entity(),
18117            language_registry,
18118            cx,
18119        );
18120
18121        let blocks = self.display_map.update(cx, |display_map, cx| {
18122            display_map.insert_blocks(blocks, cx).into_iter().collect()
18123        });
18124        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18125            active_range: buffer.anchor_before(diagnostic.range.start)
18126                ..buffer.anchor_after(diagnostic.range.end),
18127            active_message: diagnostic.diagnostic.message.clone(),
18128            group_id: diagnostic.diagnostic.group_id,
18129            blocks,
18130        });
18131        cx.notify();
18132    }
18133
18134    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18135        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18136            return;
18137        };
18138
18139        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18140        if let ActiveDiagnostic::Group(group) = prev {
18141            self.display_map.update(cx, |display_map, cx| {
18142                display_map.remove_blocks(group.blocks, cx);
18143            });
18144            cx.notify();
18145        }
18146    }
18147
18148    /// Disable inline diagnostics rendering for this editor.
18149    pub fn disable_inline_diagnostics(&mut self) {
18150        self.inline_diagnostics_enabled = false;
18151        self.inline_diagnostics_update = Task::ready(());
18152        self.inline_diagnostics.clear();
18153    }
18154
18155    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18156        self.diagnostics_enabled = false;
18157        self.dismiss_diagnostics(cx);
18158        self.inline_diagnostics_update = Task::ready(());
18159        self.inline_diagnostics.clear();
18160    }
18161
18162    pub fn disable_word_completions(&mut self) {
18163        self.word_completions_enabled = false;
18164    }
18165
18166    pub fn diagnostics_enabled(&self) -> bool {
18167        self.diagnostics_enabled && self.mode.is_full()
18168    }
18169
18170    pub fn inline_diagnostics_enabled(&self) -> bool {
18171        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18172    }
18173
18174    pub fn show_inline_diagnostics(&self) -> bool {
18175        self.show_inline_diagnostics
18176    }
18177
18178    pub fn toggle_inline_diagnostics(
18179        &mut self,
18180        _: &ToggleInlineDiagnostics,
18181        window: &mut Window,
18182        cx: &mut Context<Editor>,
18183    ) {
18184        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18185        self.refresh_inline_diagnostics(false, window, cx);
18186    }
18187
18188    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18189        self.diagnostics_max_severity = severity;
18190        self.display_map.update(cx, |display_map, _| {
18191            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18192        });
18193    }
18194
18195    pub fn toggle_diagnostics(
18196        &mut self,
18197        _: &ToggleDiagnostics,
18198        window: &mut Window,
18199        cx: &mut Context<Editor>,
18200    ) {
18201        if !self.diagnostics_enabled() {
18202            return;
18203        }
18204
18205        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18206            EditorSettings::get_global(cx)
18207                .diagnostics_max_severity
18208                .filter(|severity| severity != &DiagnosticSeverity::Off)
18209                .unwrap_or(DiagnosticSeverity::Hint)
18210        } else {
18211            DiagnosticSeverity::Off
18212        };
18213        self.set_max_diagnostics_severity(new_severity, cx);
18214        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18215            self.active_diagnostics = ActiveDiagnostic::None;
18216            self.inline_diagnostics_update = Task::ready(());
18217            self.inline_diagnostics.clear();
18218        } else {
18219            self.refresh_inline_diagnostics(false, window, cx);
18220        }
18221
18222        cx.notify();
18223    }
18224
18225    pub fn toggle_minimap(
18226        &mut self,
18227        _: &ToggleMinimap,
18228        window: &mut Window,
18229        cx: &mut Context<Editor>,
18230    ) {
18231        if self.supports_minimap(cx) {
18232            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18233        }
18234    }
18235
18236    fn refresh_inline_diagnostics(
18237        &mut self,
18238        debounce: bool,
18239        window: &mut Window,
18240        cx: &mut Context<Self>,
18241    ) {
18242        let max_severity = ProjectSettings::get_global(cx)
18243            .diagnostics
18244            .inline
18245            .max_severity
18246            .unwrap_or(self.diagnostics_max_severity);
18247
18248        if !self.inline_diagnostics_enabled()
18249            || !self.diagnostics_enabled()
18250            || !self.show_inline_diagnostics
18251            || max_severity == DiagnosticSeverity::Off
18252        {
18253            self.inline_diagnostics_update = Task::ready(());
18254            self.inline_diagnostics.clear();
18255            return;
18256        }
18257
18258        let debounce_ms = ProjectSettings::get_global(cx)
18259            .diagnostics
18260            .inline
18261            .update_debounce_ms;
18262        let debounce = if debounce && debounce_ms > 0 {
18263            Some(Duration::from_millis(debounce_ms))
18264        } else {
18265            None
18266        };
18267        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18268            if let Some(debounce) = debounce {
18269                cx.background_executor().timer(debounce).await;
18270            }
18271            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18272                editor
18273                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18274                    .ok()
18275            }) else {
18276                return;
18277            };
18278
18279            let new_inline_diagnostics = cx
18280                .background_spawn(async move {
18281                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18282                    for diagnostic_entry in
18283                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18284                    {
18285                        let message = diagnostic_entry
18286                            .diagnostic
18287                            .message
18288                            .split_once('\n')
18289                            .map(|(line, _)| line)
18290                            .map(SharedString::new)
18291                            .unwrap_or_else(|| {
18292                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18293                            });
18294                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18295                        let (Ok(i) | Err(i)) = inline_diagnostics
18296                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18297                        inline_diagnostics.insert(
18298                            i,
18299                            (
18300                                start_anchor,
18301                                InlineDiagnostic {
18302                                    message,
18303                                    group_id: diagnostic_entry.diagnostic.group_id,
18304                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18305                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18306                                    severity: diagnostic_entry.diagnostic.severity,
18307                                },
18308                            ),
18309                        );
18310                    }
18311                    inline_diagnostics
18312                })
18313                .await;
18314
18315            editor
18316                .update(cx, |editor, cx| {
18317                    editor.inline_diagnostics = new_inline_diagnostics;
18318                    cx.notify();
18319                })
18320                .ok();
18321        });
18322    }
18323
18324    fn pull_diagnostics(
18325        &mut self,
18326        buffer_id: Option<BufferId>,
18327        window: &Window,
18328        cx: &mut Context<Self>,
18329    ) -> Option<()> {
18330        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18331            return None;
18332        }
18333        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18334            .diagnostics
18335            .lsp_pull_diagnostics;
18336        if !pull_diagnostics_settings.enabled {
18337            return None;
18338        }
18339        let project = self.project()?.downgrade();
18340        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18341        let mut buffers = self.buffer.read(cx).all_buffers();
18342        buffers.retain(|buffer| {
18343            let buffer_id_to_retain = buffer.read(cx).remote_id();
18344            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18345                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18346        });
18347        if buffers.is_empty() {
18348            self.pull_diagnostics_task = Task::ready(());
18349            return None;
18350        }
18351
18352        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18353            cx.background_executor().timer(debounce).await;
18354
18355            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18356                buffers
18357                    .into_iter()
18358                    .filter_map(|buffer| {
18359                        project
18360                            .update(cx, |project, cx| {
18361                                project.lsp_store().update(cx, |lsp_store, cx| {
18362                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18363                                })
18364                            })
18365                            .ok()
18366                    })
18367                    .collect::<FuturesUnordered<_>>()
18368            }) else {
18369                return;
18370            };
18371
18372            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18373                match pull_task {
18374                    Ok(()) => {
18375                        if editor
18376                            .update_in(cx, |editor, window, cx| {
18377                                editor.update_diagnostics_state(window, cx);
18378                            })
18379                            .is_err()
18380                        {
18381                            return;
18382                        }
18383                    }
18384                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18385                }
18386            }
18387        });
18388
18389        Some(())
18390    }
18391
18392    pub fn set_selections_from_remote(
18393        &mut self,
18394        selections: Vec<Selection<Anchor>>,
18395        pending_selection: Option<Selection<Anchor>>,
18396        window: &mut Window,
18397        cx: &mut Context<Self>,
18398    ) {
18399        let old_cursor_position = self.selections.newest_anchor().head();
18400        self.selections
18401            .change_with(&self.display_snapshot(cx), |s| {
18402                s.select_anchors(selections);
18403                if let Some(pending_selection) = pending_selection {
18404                    s.set_pending(pending_selection, SelectMode::Character);
18405                } else {
18406                    s.clear_pending();
18407                }
18408            });
18409        self.selections_did_change(
18410            false,
18411            &old_cursor_position,
18412            SelectionEffects::default(),
18413            window,
18414            cx,
18415        );
18416    }
18417
18418    pub fn transact(
18419        &mut self,
18420        window: &mut Window,
18421        cx: &mut Context<Self>,
18422        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18423    ) -> Option<TransactionId> {
18424        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18425            this.start_transaction_at(Instant::now(), window, cx);
18426            update(this, window, cx);
18427            this.end_transaction_at(Instant::now(), cx)
18428        })
18429    }
18430
18431    pub fn start_transaction_at(
18432        &mut self,
18433        now: Instant,
18434        window: &mut Window,
18435        cx: &mut Context<Self>,
18436    ) -> Option<TransactionId> {
18437        self.end_selection(window, cx);
18438        if let Some(tx_id) = self
18439            .buffer
18440            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18441        {
18442            self.selection_history
18443                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18444            cx.emit(EditorEvent::TransactionBegun {
18445                transaction_id: tx_id,
18446            });
18447            Some(tx_id)
18448        } else {
18449            None
18450        }
18451    }
18452
18453    pub fn end_transaction_at(
18454        &mut self,
18455        now: Instant,
18456        cx: &mut Context<Self>,
18457    ) -> Option<TransactionId> {
18458        if let Some(transaction_id) = self
18459            .buffer
18460            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18461        {
18462            if let Some((_, end_selections)) =
18463                self.selection_history.transaction_mut(transaction_id)
18464            {
18465                *end_selections = Some(self.selections.disjoint_anchors_arc());
18466            } else {
18467                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18468            }
18469
18470            cx.emit(EditorEvent::Edited { transaction_id });
18471            Some(transaction_id)
18472        } else {
18473            None
18474        }
18475    }
18476
18477    pub fn modify_transaction_selection_history(
18478        &mut self,
18479        transaction_id: TransactionId,
18480        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18481    ) -> bool {
18482        self.selection_history
18483            .transaction_mut(transaction_id)
18484            .map(modify)
18485            .is_some()
18486    }
18487
18488    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18489        if self.selection_mark_mode {
18490            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18491                s.move_with(|_, sel| {
18492                    sel.collapse_to(sel.head(), SelectionGoal::None);
18493                });
18494            })
18495        }
18496        self.selection_mark_mode = true;
18497        cx.notify();
18498    }
18499
18500    pub fn swap_selection_ends(
18501        &mut self,
18502        _: &actions::SwapSelectionEnds,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) {
18506        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18507            s.move_with(|_, sel| {
18508                if sel.start != sel.end {
18509                    sel.reversed = !sel.reversed
18510                }
18511            });
18512        });
18513        self.request_autoscroll(Autoscroll::newest(), cx);
18514        cx.notify();
18515    }
18516
18517    pub fn toggle_focus(
18518        workspace: &mut Workspace,
18519        _: &actions::ToggleFocus,
18520        window: &mut Window,
18521        cx: &mut Context<Workspace>,
18522    ) {
18523        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18524            return;
18525        };
18526        workspace.activate_item(&item, true, true, window, cx);
18527    }
18528
18529    pub fn toggle_fold(
18530        &mut self,
18531        _: &actions::ToggleFold,
18532        window: &mut Window,
18533        cx: &mut Context<Self>,
18534    ) {
18535        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18536            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18537            let selection = self.selections.newest::<Point>(&display_map);
18538
18539            let range = if selection.is_empty() {
18540                let point = selection.head().to_display_point(&display_map);
18541                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18542                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18543                    .to_point(&display_map);
18544                start..end
18545            } else {
18546                selection.range()
18547            };
18548            if display_map.folds_in_range(range).next().is_some() {
18549                self.unfold_lines(&Default::default(), window, cx)
18550            } else {
18551                self.fold(&Default::default(), window, cx)
18552            }
18553        } else {
18554            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18555            let buffer_ids: HashSet<_> = self
18556                .selections
18557                .disjoint_anchor_ranges()
18558                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18559                .collect();
18560
18561            let should_unfold = buffer_ids
18562                .iter()
18563                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18564
18565            for buffer_id in buffer_ids {
18566                if should_unfold {
18567                    self.unfold_buffer(buffer_id, cx);
18568                } else {
18569                    self.fold_buffer(buffer_id, cx);
18570                }
18571            }
18572        }
18573    }
18574
18575    pub fn toggle_fold_recursive(
18576        &mut self,
18577        _: &actions::ToggleFoldRecursive,
18578        window: &mut Window,
18579        cx: &mut Context<Self>,
18580    ) {
18581        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18582
18583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18584        let range = if selection.is_empty() {
18585            let point = selection.head().to_display_point(&display_map);
18586            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18587            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18588                .to_point(&display_map);
18589            start..end
18590        } else {
18591            selection.range()
18592        };
18593        if display_map.folds_in_range(range).next().is_some() {
18594            self.unfold_recursive(&Default::default(), window, cx)
18595        } else {
18596            self.fold_recursive(&Default::default(), window, cx)
18597        }
18598    }
18599
18600    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18601        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18602            let mut to_fold = Vec::new();
18603            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18604            let selections = self.selections.all_adjusted(&display_map);
18605
18606            for selection in selections {
18607                let range = selection.range().sorted();
18608                let buffer_start_row = range.start.row;
18609
18610                if range.start.row != range.end.row {
18611                    let mut found = false;
18612                    let mut row = range.start.row;
18613                    while row <= range.end.row {
18614                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18615                        {
18616                            found = true;
18617                            row = crease.range().end.row + 1;
18618                            to_fold.push(crease);
18619                        } else {
18620                            row += 1
18621                        }
18622                    }
18623                    if found {
18624                        continue;
18625                    }
18626                }
18627
18628                for row in (0..=range.start.row).rev() {
18629                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18630                        && crease.range().end.row >= buffer_start_row
18631                    {
18632                        to_fold.push(crease);
18633                        if row <= range.start.row {
18634                            break;
18635                        }
18636                    }
18637                }
18638            }
18639
18640            self.fold_creases(to_fold, true, window, cx);
18641        } else {
18642            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18643            let buffer_ids = self
18644                .selections
18645                .disjoint_anchor_ranges()
18646                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18647                .collect::<HashSet<_>>();
18648            for buffer_id in buffer_ids {
18649                self.fold_buffer(buffer_id, cx);
18650            }
18651        }
18652    }
18653
18654    pub fn toggle_fold_all(
18655        &mut self,
18656        _: &actions::ToggleFoldAll,
18657        window: &mut Window,
18658        cx: &mut Context<Self>,
18659    ) {
18660        if self.buffer.read(cx).is_singleton() {
18661            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18662            let has_folds = display_map
18663                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18664                .next()
18665                .is_some();
18666
18667            if has_folds {
18668                self.unfold_all(&actions::UnfoldAll, window, cx);
18669            } else {
18670                self.fold_all(&actions::FoldAll, window, cx);
18671            }
18672        } else {
18673            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18674            let should_unfold = buffer_ids
18675                .iter()
18676                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18677
18678            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18679                editor
18680                    .update_in(cx, |editor, _, cx| {
18681                        for buffer_id in buffer_ids {
18682                            if should_unfold {
18683                                editor.unfold_buffer(buffer_id, cx);
18684                            } else {
18685                                editor.fold_buffer(buffer_id, cx);
18686                            }
18687                        }
18688                    })
18689                    .ok();
18690            });
18691        }
18692    }
18693
18694    fn fold_at_level(
18695        &mut self,
18696        fold_at: &FoldAtLevel,
18697        window: &mut Window,
18698        cx: &mut Context<Self>,
18699    ) {
18700        if !self.buffer.read(cx).is_singleton() {
18701            return;
18702        }
18703
18704        let fold_at_level = fold_at.0;
18705        let snapshot = self.buffer.read(cx).snapshot(cx);
18706        let mut to_fold = Vec::new();
18707        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18708
18709        let row_ranges_to_keep: Vec<Range<u32>> = self
18710            .selections
18711            .all::<Point>(&self.display_snapshot(cx))
18712            .into_iter()
18713            .map(|sel| sel.start.row..sel.end.row)
18714            .collect();
18715
18716        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18717            while start_row < end_row {
18718                match self
18719                    .snapshot(window, cx)
18720                    .crease_for_buffer_row(MultiBufferRow(start_row))
18721                {
18722                    Some(crease) => {
18723                        let nested_start_row = crease.range().start.row + 1;
18724                        let nested_end_row = crease.range().end.row;
18725
18726                        if current_level < fold_at_level {
18727                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18728                        } else if current_level == fold_at_level {
18729                            // Fold iff there is no selection completely contained within the fold region
18730                            if !row_ranges_to_keep.iter().any(|selection| {
18731                                selection.end >= nested_start_row
18732                                    && selection.start <= nested_end_row
18733                            }) {
18734                                to_fold.push(crease);
18735                            }
18736                        }
18737
18738                        start_row = nested_end_row + 1;
18739                    }
18740                    None => start_row += 1,
18741                }
18742            }
18743        }
18744
18745        self.fold_creases(to_fold, true, window, cx);
18746    }
18747
18748    pub fn fold_at_level_1(
18749        &mut self,
18750        _: &actions::FoldAtLevel1,
18751        window: &mut Window,
18752        cx: &mut Context<Self>,
18753    ) {
18754        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18755    }
18756
18757    pub fn fold_at_level_2(
18758        &mut self,
18759        _: &actions::FoldAtLevel2,
18760        window: &mut Window,
18761        cx: &mut Context<Self>,
18762    ) {
18763        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18764    }
18765
18766    pub fn fold_at_level_3(
18767        &mut self,
18768        _: &actions::FoldAtLevel3,
18769        window: &mut Window,
18770        cx: &mut Context<Self>,
18771    ) {
18772        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18773    }
18774
18775    pub fn fold_at_level_4(
18776        &mut self,
18777        _: &actions::FoldAtLevel4,
18778        window: &mut Window,
18779        cx: &mut Context<Self>,
18780    ) {
18781        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18782    }
18783
18784    pub fn fold_at_level_5(
18785        &mut self,
18786        _: &actions::FoldAtLevel5,
18787        window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18791    }
18792
18793    pub fn fold_at_level_6(
18794        &mut self,
18795        _: &actions::FoldAtLevel6,
18796        window: &mut Window,
18797        cx: &mut Context<Self>,
18798    ) {
18799        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18800    }
18801
18802    pub fn fold_at_level_7(
18803        &mut self,
18804        _: &actions::FoldAtLevel7,
18805        window: &mut Window,
18806        cx: &mut Context<Self>,
18807    ) {
18808        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18809    }
18810
18811    pub fn fold_at_level_8(
18812        &mut self,
18813        _: &actions::FoldAtLevel8,
18814        window: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) {
18817        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18818    }
18819
18820    pub fn fold_at_level_9(
18821        &mut self,
18822        _: &actions::FoldAtLevel9,
18823        window: &mut Window,
18824        cx: &mut Context<Self>,
18825    ) {
18826        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18827    }
18828
18829    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18830        if self.buffer.read(cx).is_singleton() {
18831            let mut fold_ranges = Vec::new();
18832            let snapshot = self.buffer.read(cx).snapshot(cx);
18833
18834            for row in 0..snapshot.max_row().0 {
18835                if let Some(foldable_range) = self
18836                    .snapshot(window, cx)
18837                    .crease_for_buffer_row(MultiBufferRow(row))
18838                {
18839                    fold_ranges.push(foldable_range);
18840                }
18841            }
18842
18843            self.fold_creases(fold_ranges, true, window, cx);
18844        } else {
18845            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18846                editor
18847                    .update_in(cx, |editor, _, cx| {
18848                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18849                            editor.fold_buffer(buffer_id, cx);
18850                        }
18851                    })
18852                    .ok();
18853            });
18854        }
18855    }
18856
18857    pub fn fold_function_bodies(
18858        &mut self,
18859        _: &actions::FoldFunctionBodies,
18860        window: &mut Window,
18861        cx: &mut Context<Self>,
18862    ) {
18863        let snapshot = self.buffer.read(cx).snapshot(cx);
18864
18865        let ranges = snapshot
18866            .text_object_ranges(
18867                MultiBufferOffset(0)..snapshot.len(),
18868                TreeSitterOptions::default(),
18869            )
18870            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18871            .collect::<Vec<_>>();
18872
18873        let creases = ranges
18874            .into_iter()
18875            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18876            .collect();
18877
18878        self.fold_creases(creases, true, window, cx);
18879    }
18880
18881    pub fn fold_recursive(
18882        &mut self,
18883        _: &actions::FoldRecursive,
18884        window: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) {
18887        let mut to_fold = Vec::new();
18888        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18889        let selections = self.selections.all_adjusted(&display_map);
18890
18891        for selection in selections {
18892            let range = selection.range().sorted();
18893            let buffer_start_row = range.start.row;
18894
18895            if range.start.row != range.end.row {
18896                let mut found = false;
18897                for row in range.start.row..=range.end.row {
18898                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18899                        found = true;
18900                        to_fold.push(crease);
18901                    }
18902                }
18903                if found {
18904                    continue;
18905                }
18906            }
18907
18908            for row in (0..=range.start.row).rev() {
18909                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18910                    if crease.range().end.row >= buffer_start_row {
18911                        to_fold.push(crease);
18912                    } else {
18913                        break;
18914                    }
18915                }
18916            }
18917        }
18918
18919        self.fold_creases(to_fold, true, window, cx);
18920    }
18921
18922    pub fn fold_at(
18923        &mut self,
18924        buffer_row: MultiBufferRow,
18925        window: &mut Window,
18926        cx: &mut Context<Self>,
18927    ) {
18928        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18929
18930        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18931            let autoscroll = self
18932                .selections
18933                .all::<Point>(&display_map)
18934                .iter()
18935                .any(|selection| crease.range().overlaps(&selection.range()));
18936
18937            self.fold_creases(vec![crease], autoscroll, window, cx);
18938        }
18939    }
18940
18941    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18942        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18943            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18944            let buffer = display_map.buffer_snapshot();
18945            let selections = self.selections.all::<Point>(&display_map);
18946            let ranges = selections
18947                .iter()
18948                .map(|s| {
18949                    let range = s.display_range(&display_map).sorted();
18950                    let mut start = range.start.to_point(&display_map);
18951                    let mut end = range.end.to_point(&display_map);
18952                    start.column = 0;
18953                    end.column = buffer.line_len(MultiBufferRow(end.row));
18954                    start..end
18955                })
18956                .collect::<Vec<_>>();
18957
18958            self.unfold_ranges(&ranges, true, true, cx);
18959        } else {
18960            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18961            let buffer_ids = self
18962                .selections
18963                .disjoint_anchor_ranges()
18964                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18965                .collect::<HashSet<_>>();
18966            for buffer_id in buffer_ids {
18967                self.unfold_buffer(buffer_id, cx);
18968            }
18969        }
18970    }
18971
18972    pub fn unfold_recursive(
18973        &mut self,
18974        _: &UnfoldRecursive,
18975        _window: &mut Window,
18976        cx: &mut Context<Self>,
18977    ) {
18978        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18979        let selections = self.selections.all::<Point>(&display_map);
18980        let ranges = selections
18981            .iter()
18982            .map(|s| {
18983                let mut range = s.display_range(&display_map).sorted();
18984                *range.start.column_mut() = 0;
18985                *range.end.column_mut() = display_map.line_len(range.end.row());
18986                let start = range.start.to_point(&display_map);
18987                let end = range.end.to_point(&display_map);
18988                start..end
18989            })
18990            .collect::<Vec<_>>();
18991
18992        self.unfold_ranges(&ranges, true, true, cx);
18993    }
18994
18995    pub fn unfold_at(
18996        &mut self,
18997        buffer_row: MultiBufferRow,
18998        _window: &mut Window,
18999        cx: &mut Context<Self>,
19000    ) {
19001        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19002
19003        let intersection_range = Point::new(buffer_row.0, 0)
19004            ..Point::new(
19005                buffer_row.0,
19006                display_map.buffer_snapshot().line_len(buffer_row),
19007            );
19008
19009        let autoscroll = self
19010            .selections
19011            .all::<Point>(&display_map)
19012            .iter()
19013            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19014
19015        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19016    }
19017
19018    pub fn unfold_all(
19019        &mut self,
19020        _: &actions::UnfoldAll,
19021        _window: &mut Window,
19022        cx: &mut Context<Self>,
19023    ) {
19024        if self.buffer.read(cx).is_singleton() {
19025            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19026            self.unfold_ranges(
19027                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19028                true,
19029                true,
19030                cx,
19031            );
19032        } else {
19033            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19034                editor
19035                    .update(cx, |editor, cx| {
19036                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19037                            editor.unfold_buffer(buffer_id, cx);
19038                        }
19039                    })
19040                    .ok();
19041            });
19042        }
19043    }
19044
19045    pub fn fold_selected_ranges(
19046        &mut self,
19047        _: &FoldSelectedRanges,
19048        window: &mut Window,
19049        cx: &mut Context<Self>,
19050    ) {
19051        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19052        let selections = self.selections.all_adjusted(&display_map);
19053        let ranges = selections
19054            .into_iter()
19055            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19056            .collect::<Vec<_>>();
19057        self.fold_creases(ranges, true, window, cx);
19058    }
19059
19060    pub fn fold_ranges<T: ToOffset + Clone>(
19061        &mut self,
19062        ranges: Vec<Range<T>>,
19063        auto_scroll: bool,
19064        window: &mut Window,
19065        cx: &mut Context<Self>,
19066    ) {
19067        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19068        let ranges = ranges
19069            .into_iter()
19070            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19071            .collect::<Vec<_>>();
19072        self.fold_creases(ranges, auto_scroll, window, cx);
19073    }
19074
19075    pub fn fold_creases<T: ToOffset + Clone>(
19076        &mut self,
19077        creases: Vec<Crease<T>>,
19078        auto_scroll: bool,
19079        _window: &mut Window,
19080        cx: &mut Context<Self>,
19081    ) {
19082        if creases.is_empty() {
19083            return;
19084        }
19085
19086        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19087
19088        if auto_scroll {
19089            self.request_autoscroll(Autoscroll::fit(), cx);
19090        }
19091
19092        cx.notify();
19093
19094        self.scrollbar_marker_state.dirty = true;
19095        self.folds_did_change(cx);
19096    }
19097
19098    /// Removes any folds whose ranges intersect any of the given ranges.
19099    pub fn unfold_ranges<T: ToOffset + Clone>(
19100        &mut self,
19101        ranges: &[Range<T>],
19102        inclusive: bool,
19103        auto_scroll: bool,
19104        cx: &mut Context<Self>,
19105    ) {
19106        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19107            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19108        });
19109        self.folds_did_change(cx);
19110    }
19111
19112    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19113        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19114            return;
19115        }
19116
19117        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19118        self.display_map.update(cx, |display_map, cx| {
19119            display_map.fold_buffers([buffer_id], cx)
19120        });
19121
19122        let snapshot = self.display_snapshot(cx);
19123        self.selections.change_with(&snapshot, |selections| {
19124            selections.remove_selections_from_buffer(buffer_id);
19125        });
19126
19127        cx.emit(EditorEvent::BufferFoldToggled {
19128            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19129            folded: true,
19130        });
19131        cx.notify();
19132    }
19133
19134    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19135        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19136            return;
19137        }
19138        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19139        self.display_map.update(cx, |display_map, cx| {
19140            display_map.unfold_buffers([buffer_id], cx);
19141        });
19142        cx.emit(EditorEvent::BufferFoldToggled {
19143            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19144            folded: false,
19145        });
19146        cx.notify();
19147    }
19148
19149    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19150        self.display_map.read(cx).is_buffer_folded(buffer)
19151    }
19152
19153    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19154        self.display_map.read(cx).folded_buffers()
19155    }
19156
19157    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19158        self.display_map.update(cx, |display_map, cx| {
19159            display_map.disable_header_for_buffer(buffer_id, cx);
19160        });
19161        cx.notify();
19162    }
19163
19164    /// Removes any folds with the given ranges.
19165    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19166        &mut self,
19167        ranges: &[Range<T>],
19168        type_id: TypeId,
19169        auto_scroll: bool,
19170        cx: &mut Context<Self>,
19171    ) {
19172        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19173            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19174        });
19175        self.folds_did_change(cx);
19176    }
19177
19178    fn remove_folds_with<T: ToOffset + Clone>(
19179        &mut self,
19180        ranges: &[Range<T>],
19181        auto_scroll: bool,
19182        cx: &mut Context<Self>,
19183        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19184    ) {
19185        if ranges.is_empty() {
19186            return;
19187        }
19188
19189        let mut buffers_affected = HashSet::default();
19190        let multi_buffer = self.buffer().read(cx);
19191        for range in ranges {
19192            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19193                buffers_affected.insert(buffer.read(cx).remote_id());
19194            };
19195        }
19196
19197        self.display_map.update(cx, update);
19198
19199        if auto_scroll {
19200            self.request_autoscroll(Autoscroll::fit(), cx);
19201        }
19202
19203        cx.notify();
19204        self.scrollbar_marker_state.dirty = true;
19205        self.active_indent_guides_state.dirty = true;
19206    }
19207
19208    pub fn update_renderer_widths(
19209        &mut self,
19210        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19211        cx: &mut Context<Self>,
19212    ) -> bool {
19213        self.display_map
19214            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19215    }
19216
19217    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19218        self.display_map.read(cx).fold_placeholder.clone()
19219    }
19220
19221    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19222        self.use_base_text_line_numbers = show;
19223    }
19224
19225    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19226        self.buffer.update(cx, |buffer, cx| {
19227            buffer.set_all_diff_hunks_expanded(cx);
19228        });
19229    }
19230
19231    pub fn expand_all_diff_hunks(
19232        &mut self,
19233        _: &ExpandAllDiffHunks,
19234        _window: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        self.buffer.update(cx, |buffer, cx| {
19238            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19239        });
19240    }
19241
19242    pub fn collapse_all_diff_hunks(
19243        &mut self,
19244        _: &CollapseAllDiffHunks,
19245        _window: &mut Window,
19246        cx: &mut Context<Self>,
19247    ) {
19248        self.buffer.update(cx, |buffer, cx| {
19249            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19250        });
19251    }
19252
19253    pub fn toggle_selected_diff_hunks(
19254        &mut self,
19255        _: &ToggleSelectedDiffHunks,
19256        _window: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        let ranges: Vec<_> = self
19260            .selections
19261            .disjoint_anchors()
19262            .iter()
19263            .map(|s| s.range())
19264            .collect();
19265        self.toggle_diff_hunks_in_ranges(ranges, cx);
19266    }
19267
19268    pub fn diff_hunks_in_ranges<'a>(
19269        &'a self,
19270        ranges: &'a [Range<Anchor>],
19271        buffer: &'a MultiBufferSnapshot,
19272    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19273        ranges.iter().flat_map(move |range| {
19274            let end_excerpt_id = range.end.excerpt_id;
19275            let range = range.to_point(buffer);
19276            let mut peek_end = range.end;
19277            if range.end.row < buffer.max_row().0 {
19278                peek_end = Point::new(range.end.row + 1, 0);
19279            }
19280            buffer
19281                .diff_hunks_in_range(range.start..peek_end)
19282                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19283        })
19284    }
19285
19286    pub fn has_stageable_diff_hunks_in_ranges(
19287        &self,
19288        ranges: &[Range<Anchor>],
19289        snapshot: &MultiBufferSnapshot,
19290    ) -> bool {
19291        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19292        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19293    }
19294
19295    pub fn toggle_staged_selected_diff_hunks(
19296        &mut self,
19297        _: &::git::ToggleStaged,
19298        _: &mut Window,
19299        cx: &mut Context<Self>,
19300    ) {
19301        let snapshot = self.buffer.read(cx).snapshot(cx);
19302        let ranges: Vec<_> = self
19303            .selections
19304            .disjoint_anchors()
19305            .iter()
19306            .map(|s| s.range())
19307            .collect();
19308        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19309        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19310    }
19311
19312    pub fn set_render_diff_hunk_controls(
19313        &mut self,
19314        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19315        cx: &mut Context<Self>,
19316    ) {
19317        self.render_diff_hunk_controls = render_diff_hunk_controls;
19318        cx.notify();
19319    }
19320
19321    pub fn stage_and_next(
19322        &mut self,
19323        _: &::git::StageAndNext,
19324        window: &mut Window,
19325        cx: &mut Context<Self>,
19326    ) {
19327        self.do_stage_or_unstage_and_next(true, window, cx);
19328    }
19329
19330    pub fn unstage_and_next(
19331        &mut self,
19332        _: &::git::UnstageAndNext,
19333        window: &mut Window,
19334        cx: &mut Context<Self>,
19335    ) {
19336        self.do_stage_or_unstage_and_next(false, window, cx);
19337    }
19338
19339    pub fn stage_or_unstage_diff_hunks(
19340        &mut self,
19341        stage: bool,
19342        ranges: Vec<Range<Anchor>>,
19343        cx: &mut Context<Self>,
19344    ) {
19345        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19346        cx.spawn(async move |this, cx| {
19347            task.await?;
19348            this.update(cx, |this, cx| {
19349                let snapshot = this.buffer.read(cx).snapshot(cx);
19350                let chunk_by = this
19351                    .diff_hunks_in_ranges(&ranges, &snapshot)
19352                    .chunk_by(|hunk| hunk.buffer_id);
19353                for (buffer_id, hunks) in &chunk_by {
19354                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19355                }
19356            })
19357        })
19358        .detach_and_log_err(cx);
19359    }
19360
19361    fn save_buffers_for_ranges_if_needed(
19362        &mut self,
19363        ranges: &[Range<Anchor>],
19364        cx: &mut Context<Editor>,
19365    ) -> Task<Result<()>> {
19366        let multibuffer = self.buffer.read(cx);
19367        let snapshot = multibuffer.read(cx);
19368        let buffer_ids: HashSet<_> = ranges
19369            .iter()
19370            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19371            .collect();
19372        drop(snapshot);
19373
19374        let mut buffers = HashSet::default();
19375        for buffer_id in buffer_ids {
19376            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19377                let buffer = buffer_entity.read(cx);
19378                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19379                {
19380                    buffers.insert(buffer_entity);
19381                }
19382            }
19383        }
19384
19385        if let Some(project) = &self.project {
19386            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19387        } else {
19388            Task::ready(Ok(()))
19389        }
19390    }
19391
19392    fn do_stage_or_unstage_and_next(
19393        &mut self,
19394        stage: bool,
19395        window: &mut Window,
19396        cx: &mut Context<Self>,
19397    ) {
19398        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19399
19400        if ranges.iter().any(|range| range.start != range.end) {
19401            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19402            return;
19403        }
19404
19405        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19406        let snapshot = self.snapshot(window, cx);
19407        let position = self
19408            .selections
19409            .newest::<Point>(&snapshot.display_snapshot)
19410            .head();
19411        let mut row = snapshot
19412            .buffer_snapshot()
19413            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19414            .find(|hunk| hunk.row_range.start.0 > position.row)
19415            .map(|hunk| hunk.row_range.start);
19416
19417        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19418        // Outside of the project diff editor, wrap around to the beginning.
19419        if !all_diff_hunks_expanded {
19420            row = row.or_else(|| {
19421                snapshot
19422                    .buffer_snapshot()
19423                    .diff_hunks_in_range(Point::zero()..position)
19424                    .find(|hunk| hunk.row_range.end.0 < position.row)
19425                    .map(|hunk| hunk.row_range.start)
19426            });
19427        }
19428
19429        if let Some(row) = row {
19430            let destination = Point::new(row.0, 0);
19431            let autoscroll = Autoscroll::center();
19432
19433            self.unfold_ranges(&[destination..destination], false, false, cx);
19434            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19435                s.select_ranges([destination..destination]);
19436            });
19437        }
19438    }
19439
19440    fn do_stage_or_unstage(
19441        &self,
19442        stage: bool,
19443        buffer_id: BufferId,
19444        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19445        cx: &mut App,
19446    ) -> Option<()> {
19447        let project = self.project()?;
19448        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19449        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19450        let buffer_snapshot = buffer.read(cx).snapshot();
19451        let file_exists = buffer_snapshot
19452            .file()
19453            .is_some_and(|file| file.disk_state().exists());
19454        diff.update(cx, |diff, cx| {
19455            diff.stage_or_unstage_hunks(
19456                stage,
19457                &hunks
19458                    .map(|hunk| buffer_diff::DiffHunk {
19459                        buffer_range: hunk.buffer_range,
19460                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19461                            ..hunk.diff_base_byte_range.end.0,
19462                        secondary_status: hunk.secondary_status,
19463                        range: Point::zero()..Point::zero(), // unused
19464                    })
19465                    .collect::<Vec<_>>(),
19466                &buffer_snapshot,
19467                file_exists,
19468                cx,
19469            )
19470        });
19471        None
19472    }
19473
19474    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19475        let ranges: Vec<_> = self
19476            .selections
19477            .disjoint_anchors()
19478            .iter()
19479            .map(|s| s.range())
19480            .collect();
19481        self.buffer
19482            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19483    }
19484
19485    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19486        self.buffer.update(cx, |buffer, cx| {
19487            let ranges = vec![Anchor::min()..Anchor::max()];
19488            if !buffer.all_diff_hunks_expanded()
19489                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19490            {
19491                buffer.collapse_diff_hunks(ranges, cx);
19492                true
19493            } else {
19494                false
19495            }
19496        })
19497    }
19498
19499    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19500        if self.buffer.read(cx).all_diff_hunks_expanded() {
19501            return true;
19502        }
19503        let ranges = vec![Anchor::min()..Anchor::max()];
19504        self.buffer
19505            .read(cx)
19506            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19507    }
19508
19509    fn toggle_diff_hunks_in_ranges(
19510        &mut self,
19511        ranges: Vec<Range<Anchor>>,
19512        cx: &mut Context<Editor>,
19513    ) {
19514        self.buffer.update(cx, |buffer, cx| {
19515            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19516            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19517        })
19518    }
19519
19520    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19521        self.buffer.update(cx, |buffer, cx| {
19522            let snapshot = buffer.snapshot(cx);
19523            let excerpt_id = range.end.excerpt_id;
19524            let point_range = range.to_point(&snapshot);
19525            let expand = !buffer.single_hunk_is_expanded(range, cx);
19526            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19527        })
19528    }
19529
19530    pub(crate) fn apply_all_diff_hunks(
19531        &mut self,
19532        _: &ApplyAllDiffHunks,
19533        window: &mut Window,
19534        cx: &mut Context<Self>,
19535    ) {
19536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19537
19538        let buffers = self.buffer.read(cx).all_buffers();
19539        for branch_buffer in buffers {
19540            branch_buffer.update(cx, |branch_buffer, cx| {
19541                branch_buffer.merge_into_base(Vec::new(), cx);
19542            });
19543        }
19544
19545        if let Some(project) = self.project.clone() {
19546            self.save(
19547                SaveOptions {
19548                    format: true,
19549                    autosave: false,
19550                },
19551                project,
19552                window,
19553                cx,
19554            )
19555            .detach_and_log_err(cx);
19556        }
19557    }
19558
19559    pub(crate) fn apply_selected_diff_hunks(
19560        &mut self,
19561        _: &ApplyDiffHunk,
19562        window: &mut Window,
19563        cx: &mut Context<Self>,
19564    ) {
19565        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19566        let snapshot = self.snapshot(window, cx);
19567        let hunks = snapshot.hunks_for_ranges(
19568            self.selections
19569                .all(&snapshot.display_snapshot)
19570                .into_iter()
19571                .map(|selection| selection.range()),
19572        );
19573        let mut ranges_by_buffer = HashMap::default();
19574        self.transact(window, cx, |editor, _window, cx| {
19575            for hunk in hunks {
19576                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19577                    ranges_by_buffer
19578                        .entry(buffer.clone())
19579                        .or_insert_with(Vec::new)
19580                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19581                }
19582            }
19583
19584            for (buffer, ranges) in ranges_by_buffer {
19585                buffer.update(cx, |buffer, cx| {
19586                    buffer.merge_into_base(ranges, cx);
19587                });
19588            }
19589        });
19590
19591        if let Some(project) = self.project.clone() {
19592            self.save(
19593                SaveOptions {
19594                    format: true,
19595                    autosave: false,
19596                },
19597                project,
19598                window,
19599                cx,
19600            )
19601            .detach_and_log_err(cx);
19602        }
19603    }
19604
19605    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19606        if hovered != self.gutter_hovered {
19607            self.gutter_hovered = hovered;
19608            cx.notify();
19609        }
19610    }
19611
19612    pub fn insert_blocks(
19613        &mut self,
19614        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19615        autoscroll: Option<Autoscroll>,
19616        cx: &mut Context<Self>,
19617    ) -> Vec<CustomBlockId> {
19618        let blocks = self
19619            .display_map
19620            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19621        if let Some(autoscroll) = autoscroll {
19622            self.request_autoscroll(autoscroll, cx);
19623        }
19624        cx.notify();
19625        blocks
19626    }
19627
19628    pub fn resize_blocks(
19629        &mut self,
19630        heights: HashMap<CustomBlockId, u32>,
19631        autoscroll: Option<Autoscroll>,
19632        cx: &mut Context<Self>,
19633    ) {
19634        self.display_map
19635            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19636        if let Some(autoscroll) = autoscroll {
19637            self.request_autoscroll(autoscroll, cx);
19638        }
19639        cx.notify();
19640    }
19641
19642    pub fn replace_blocks(
19643        &mut self,
19644        renderers: HashMap<CustomBlockId, RenderBlock>,
19645        autoscroll: Option<Autoscroll>,
19646        cx: &mut Context<Self>,
19647    ) {
19648        self.display_map
19649            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19650        if let Some(autoscroll) = autoscroll {
19651            self.request_autoscroll(autoscroll, cx);
19652        }
19653        cx.notify();
19654    }
19655
19656    pub fn remove_blocks(
19657        &mut self,
19658        block_ids: HashSet<CustomBlockId>,
19659        autoscroll: Option<Autoscroll>,
19660        cx: &mut Context<Self>,
19661    ) {
19662        self.display_map.update(cx, |display_map, cx| {
19663            display_map.remove_blocks(block_ids, cx)
19664        });
19665        if let Some(autoscroll) = autoscroll {
19666            self.request_autoscroll(autoscroll, cx);
19667        }
19668        cx.notify();
19669    }
19670
19671    pub fn row_for_block(
19672        &self,
19673        block_id: CustomBlockId,
19674        cx: &mut Context<Self>,
19675    ) -> Option<DisplayRow> {
19676        self.display_map
19677            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19678    }
19679
19680    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19681        self.focused_block = Some(focused_block);
19682    }
19683
19684    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19685        self.focused_block.take()
19686    }
19687
19688    pub fn insert_creases(
19689        &mut self,
19690        creases: impl IntoIterator<Item = Crease<Anchor>>,
19691        cx: &mut Context<Self>,
19692    ) -> Vec<CreaseId> {
19693        self.display_map
19694            .update(cx, |map, cx| map.insert_creases(creases, cx))
19695    }
19696
19697    pub fn remove_creases(
19698        &mut self,
19699        ids: impl IntoIterator<Item = CreaseId>,
19700        cx: &mut Context<Self>,
19701    ) -> Vec<(CreaseId, Range<Anchor>)> {
19702        self.display_map
19703            .update(cx, |map, cx| map.remove_creases(ids, cx))
19704    }
19705
19706    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19707        self.display_map
19708            .update(cx, |map, cx| map.snapshot(cx))
19709            .longest_row()
19710    }
19711
19712    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19713        self.display_map
19714            .update(cx, |map, cx| map.snapshot(cx))
19715            .max_point()
19716    }
19717
19718    pub fn text(&self, cx: &App) -> String {
19719        self.buffer.read(cx).read(cx).text()
19720    }
19721
19722    pub fn is_empty(&self, cx: &App) -> bool {
19723        self.buffer.read(cx).read(cx).is_empty()
19724    }
19725
19726    pub fn text_option(&self, cx: &App) -> Option<String> {
19727        let text = self.text(cx);
19728        let text = text.trim();
19729
19730        if text.is_empty() {
19731            return None;
19732        }
19733
19734        Some(text.to_string())
19735    }
19736
19737    pub fn set_text(
19738        &mut self,
19739        text: impl Into<Arc<str>>,
19740        window: &mut Window,
19741        cx: &mut Context<Self>,
19742    ) {
19743        self.transact(window, cx, |this, _, cx| {
19744            this.buffer
19745                .read(cx)
19746                .as_singleton()
19747                .expect("you can only call set_text on editors for singleton buffers")
19748                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19749        });
19750    }
19751
19752    pub fn display_text(&self, cx: &mut App) -> String {
19753        self.display_map
19754            .update(cx, |map, cx| map.snapshot(cx))
19755            .text()
19756    }
19757
19758    fn create_minimap(
19759        &self,
19760        minimap_settings: MinimapSettings,
19761        window: &mut Window,
19762        cx: &mut Context<Self>,
19763    ) -> Option<Entity<Self>> {
19764        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19765            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19766    }
19767
19768    fn initialize_new_minimap(
19769        &self,
19770        minimap_settings: MinimapSettings,
19771        window: &mut Window,
19772        cx: &mut Context<Self>,
19773    ) -> Entity<Self> {
19774        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19775
19776        let mut minimap = Editor::new_internal(
19777            EditorMode::Minimap {
19778                parent: cx.weak_entity(),
19779            },
19780            self.buffer.clone(),
19781            None,
19782            Some(self.display_map.clone()),
19783            window,
19784            cx,
19785        );
19786        minimap.scroll_manager.clone_state(&self.scroll_manager);
19787        minimap.set_text_style_refinement(TextStyleRefinement {
19788            font_size: Some(MINIMAP_FONT_SIZE),
19789            font_weight: Some(MINIMAP_FONT_WEIGHT),
19790            ..Default::default()
19791        });
19792        minimap.update_minimap_configuration(minimap_settings, cx);
19793        cx.new(|_| minimap)
19794    }
19795
19796    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19797        let current_line_highlight = minimap_settings
19798            .current_line_highlight
19799            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19800        self.set_current_line_highlight(Some(current_line_highlight));
19801    }
19802
19803    pub fn minimap(&self) -> Option<&Entity<Self>> {
19804        self.minimap
19805            .as_ref()
19806            .filter(|_| self.minimap_visibility.visible())
19807    }
19808
19809    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19810        let mut wrap_guides = smallvec![];
19811
19812        if self.show_wrap_guides == Some(false) {
19813            return wrap_guides;
19814        }
19815
19816        let settings = self.buffer.read(cx).language_settings(cx);
19817        if settings.show_wrap_guides {
19818            match self.soft_wrap_mode(cx) {
19819                SoftWrap::Column(soft_wrap) => {
19820                    wrap_guides.push((soft_wrap as usize, true));
19821                }
19822                SoftWrap::Bounded(soft_wrap) => {
19823                    wrap_guides.push((soft_wrap as usize, true));
19824                }
19825                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19826            }
19827            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19828        }
19829
19830        wrap_guides
19831    }
19832
19833    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19834        let settings = self.buffer.read(cx).language_settings(cx);
19835        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19836        match mode {
19837            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19838                SoftWrap::None
19839            }
19840            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19841            language_settings::SoftWrap::PreferredLineLength => {
19842                SoftWrap::Column(settings.preferred_line_length)
19843            }
19844            language_settings::SoftWrap::Bounded => {
19845                SoftWrap::Bounded(settings.preferred_line_length)
19846            }
19847        }
19848    }
19849
19850    pub fn set_soft_wrap_mode(
19851        &mut self,
19852        mode: language_settings::SoftWrap,
19853
19854        cx: &mut Context<Self>,
19855    ) {
19856        self.soft_wrap_mode_override = Some(mode);
19857        cx.notify();
19858    }
19859
19860    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19861        self.hard_wrap = hard_wrap;
19862        cx.notify();
19863    }
19864
19865    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19866        self.text_style_refinement = Some(style);
19867    }
19868
19869    /// called by the Element so we know what style we were most recently rendered with.
19870    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19871        // We intentionally do not inform the display map about the minimap style
19872        // so that wrapping is not recalculated and stays consistent for the editor
19873        // and its linked minimap.
19874        if !self.mode.is_minimap() {
19875            let font = style.text.font();
19876            let font_size = style.text.font_size.to_pixels(window.rem_size());
19877            let display_map = self
19878                .placeholder_display_map
19879                .as_ref()
19880                .filter(|_| self.is_empty(cx))
19881                .unwrap_or(&self.display_map);
19882
19883            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19884        }
19885        self.style = Some(style);
19886    }
19887
19888    pub fn style(&self) -> Option<&EditorStyle> {
19889        self.style.as_ref()
19890    }
19891
19892    // Called by the element. This method is not designed to be called outside of the editor
19893    // element's layout code because it does not notify when rewrapping is computed synchronously.
19894    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19895        if self.is_empty(cx) {
19896            self.placeholder_display_map
19897                .as_ref()
19898                .map_or(false, |display_map| {
19899                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19900                })
19901        } else {
19902            self.display_map
19903                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19904        }
19905    }
19906
19907    pub fn set_soft_wrap(&mut self) {
19908        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19909    }
19910
19911    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19912        if self.soft_wrap_mode_override.is_some() {
19913            self.soft_wrap_mode_override.take();
19914        } else {
19915            let soft_wrap = match self.soft_wrap_mode(cx) {
19916                SoftWrap::GitDiff => return,
19917                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19918                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19919                    language_settings::SoftWrap::None
19920                }
19921            };
19922            self.soft_wrap_mode_override = Some(soft_wrap);
19923        }
19924        cx.notify();
19925    }
19926
19927    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19928        let Some(workspace) = self.workspace() else {
19929            return;
19930        };
19931        let fs = workspace.read(cx).app_state().fs.clone();
19932        let current_show = TabBarSettings::get_global(cx).show;
19933        update_settings_file(fs, cx, move |setting, _| {
19934            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19935        });
19936    }
19937
19938    pub fn toggle_indent_guides(
19939        &mut self,
19940        _: &ToggleIndentGuides,
19941        _: &mut Window,
19942        cx: &mut Context<Self>,
19943    ) {
19944        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19945            self.buffer
19946                .read(cx)
19947                .language_settings(cx)
19948                .indent_guides
19949                .enabled
19950        });
19951        self.show_indent_guides = Some(!currently_enabled);
19952        cx.notify();
19953    }
19954
19955    fn should_show_indent_guides(&self) -> Option<bool> {
19956        self.show_indent_guides
19957    }
19958
19959    pub fn toggle_line_numbers(
19960        &mut self,
19961        _: &ToggleLineNumbers,
19962        _: &mut Window,
19963        cx: &mut Context<Self>,
19964    ) {
19965        let mut editor_settings = EditorSettings::get_global(cx).clone();
19966        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19967        EditorSettings::override_global(editor_settings, cx);
19968    }
19969
19970    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19971        if let Some(show_line_numbers) = self.show_line_numbers {
19972            return show_line_numbers;
19973        }
19974        EditorSettings::get_global(cx).gutter.line_numbers
19975    }
19976
19977    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19978        match (
19979            self.use_relative_line_numbers,
19980            EditorSettings::get_global(cx).relative_line_numbers,
19981        ) {
19982            (None, setting) => setting,
19983            (Some(false), _) => RelativeLineNumbers::Disabled,
19984            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19985            (Some(true), _) => RelativeLineNumbers::Enabled,
19986        }
19987    }
19988
19989    pub fn toggle_relative_line_numbers(
19990        &mut self,
19991        _: &ToggleRelativeLineNumbers,
19992        _: &mut Window,
19993        cx: &mut Context<Self>,
19994    ) {
19995        let is_relative = self.relative_line_numbers(cx);
19996        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19997    }
19998
19999    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20000        self.use_relative_line_numbers = is_relative;
20001        cx.notify();
20002    }
20003
20004    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20005        self.show_gutter = show_gutter;
20006        cx.notify();
20007    }
20008
20009    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20010        self.show_scrollbars = ScrollbarAxes {
20011            horizontal: show,
20012            vertical: show,
20013        };
20014        cx.notify();
20015    }
20016
20017    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20018        self.show_scrollbars.vertical = show;
20019        cx.notify();
20020    }
20021
20022    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20023        self.show_scrollbars.horizontal = show;
20024        cx.notify();
20025    }
20026
20027    pub fn set_minimap_visibility(
20028        &mut self,
20029        minimap_visibility: MinimapVisibility,
20030        window: &mut Window,
20031        cx: &mut Context<Self>,
20032    ) {
20033        if self.minimap_visibility != minimap_visibility {
20034            if minimap_visibility.visible() && self.minimap.is_none() {
20035                let minimap_settings = EditorSettings::get_global(cx).minimap;
20036                self.minimap =
20037                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20038            }
20039            self.minimap_visibility = minimap_visibility;
20040            cx.notify();
20041        }
20042    }
20043
20044    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20045        self.set_show_scrollbars(false, cx);
20046        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20047    }
20048
20049    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20050        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20051    }
20052
20053    /// Normally the text in full mode and auto height editors is padded on the
20054    /// left side by roughly half a character width for improved hit testing.
20055    ///
20056    /// Use this method to disable this for cases where this is not wanted (e.g.
20057    /// if you want to align the editor text with some other text above or below)
20058    /// or if you want to add this padding to single-line editors.
20059    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20060        self.offset_content = offset_content;
20061        cx.notify();
20062    }
20063
20064    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20065        self.show_line_numbers = Some(show_line_numbers);
20066        cx.notify();
20067    }
20068
20069    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20070        self.disable_expand_excerpt_buttons = true;
20071        cx.notify();
20072    }
20073
20074    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20075        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20076        cx.notify();
20077    }
20078
20079    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20080        self.show_code_actions = Some(show_code_actions);
20081        cx.notify();
20082    }
20083
20084    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20085        self.show_runnables = Some(show_runnables);
20086        cx.notify();
20087    }
20088
20089    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20090        self.show_breakpoints = Some(show_breakpoints);
20091        cx.notify();
20092    }
20093
20094    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20095        if self.display_map.read(cx).masked != masked {
20096            self.display_map.update(cx, |map, _| map.masked = masked);
20097        }
20098        cx.notify()
20099    }
20100
20101    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20102        self.show_wrap_guides = Some(show_wrap_guides);
20103        cx.notify();
20104    }
20105
20106    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20107        self.show_indent_guides = Some(show_indent_guides);
20108        cx.notify();
20109    }
20110
20111    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20112        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20113            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20114                && let Some(dir) = file.abs_path(cx).parent()
20115            {
20116                return Some(dir.to_owned());
20117            }
20118        }
20119
20120        None
20121    }
20122
20123    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20124        self.active_excerpt(cx)?
20125            .1
20126            .read(cx)
20127            .file()
20128            .and_then(|f| f.as_local())
20129    }
20130
20131    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20132        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20133            let buffer = buffer.read(cx);
20134            if let Some(project_path) = buffer.project_path(cx) {
20135                let project = self.project()?.read(cx);
20136                project.absolute_path(&project_path, cx)
20137            } else {
20138                buffer
20139                    .file()
20140                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20141            }
20142        })
20143    }
20144
20145    pub fn reveal_in_finder(
20146        &mut self,
20147        _: &RevealInFileManager,
20148        _window: &mut Window,
20149        cx: &mut Context<Self>,
20150    ) {
20151        if let Some(target) = self.target_file(cx) {
20152            cx.reveal_path(&target.abs_path(cx));
20153        }
20154    }
20155
20156    pub fn copy_path(
20157        &mut self,
20158        _: &zed_actions::workspace::CopyPath,
20159        _window: &mut Window,
20160        cx: &mut Context<Self>,
20161    ) {
20162        if let Some(path) = self.target_file_abs_path(cx)
20163            && let Some(path) = path.to_str()
20164        {
20165            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20166        } else {
20167            cx.propagate();
20168        }
20169    }
20170
20171    pub fn copy_relative_path(
20172        &mut self,
20173        _: &zed_actions::workspace::CopyRelativePath,
20174        _window: &mut Window,
20175        cx: &mut Context<Self>,
20176    ) {
20177        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20178            let project = self.project()?.read(cx);
20179            let path = buffer.read(cx).file()?.path();
20180            let path = path.display(project.path_style(cx));
20181            Some(path)
20182        }) {
20183            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20184        } else {
20185            cx.propagate();
20186        }
20187    }
20188
20189    /// Returns the project path for the editor's buffer, if any buffer is
20190    /// opened in the editor.
20191    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20192        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20193            buffer.read(cx).project_path(cx)
20194        } else {
20195            None
20196        }
20197    }
20198
20199    // Returns true if the editor handled a go-to-line request
20200    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20201        maybe!({
20202            let breakpoint_store = self.breakpoint_store.as_ref()?;
20203
20204            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20205            else {
20206                self.clear_row_highlights::<ActiveDebugLine>();
20207                return None;
20208            };
20209
20210            let position = active_stack_frame.position;
20211            let buffer_id = position.buffer_id?;
20212            let snapshot = self
20213                .project
20214                .as_ref()?
20215                .read(cx)
20216                .buffer_for_id(buffer_id, cx)?
20217                .read(cx)
20218                .snapshot();
20219
20220            let mut handled = false;
20221            for (id, ExcerptRange { context, .. }) in
20222                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20223            {
20224                if context.start.cmp(&position, &snapshot).is_ge()
20225                    || context.end.cmp(&position, &snapshot).is_lt()
20226                {
20227                    continue;
20228                }
20229                let snapshot = self.buffer.read(cx).snapshot(cx);
20230                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20231
20232                handled = true;
20233                self.clear_row_highlights::<ActiveDebugLine>();
20234
20235                self.go_to_line::<ActiveDebugLine>(
20236                    multibuffer_anchor,
20237                    Some(cx.theme().colors().editor_debugger_active_line_background),
20238                    window,
20239                    cx,
20240                );
20241
20242                cx.notify();
20243            }
20244
20245            handled.then_some(())
20246        })
20247        .is_some()
20248    }
20249
20250    pub fn copy_file_name_without_extension(
20251        &mut self,
20252        _: &CopyFileNameWithoutExtension,
20253        _: &mut Window,
20254        cx: &mut Context<Self>,
20255    ) {
20256        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20257            let file = buffer.read(cx).file()?;
20258            file.path().file_stem()
20259        }) {
20260            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20261        }
20262    }
20263
20264    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20265        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20266            let file = buffer.read(cx).file()?;
20267            Some(file.file_name(cx))
20268        }) {
20269            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20270        }
20271    }
20272
20273    pub fn toggle_git_blame(
20274        &mut self,
20275        _: &::git::Blame,
20276        window: &mut Window,
20277        cx: &mut Context<Self>,
20278    ) {
20279        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20280
20281        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20282            self.start_git_blame(true, window, cx);
20283        }
20284
20285        cx.notify();
20286    }
20287
20288    pub fn toggle_git_blame_inline(
20289        &mut self,
20290        _: &ToggleGitBlameInline,
20291        window: &mut Window,
20292        cx: &mut Context<Self>,
20293    ) {
20294        self.toggle_git_blame_inline_internal(true, window, cx);
20295        cx.notify();
20296    }
20297
20298    pub fn open_git_blame_commit(
20299        &mut self,
20300        _: &OpenGitBlameCommit,
20301        window: &mut Window,
20302        cx: &mut Context<Self>,
20303    ) {
20304        self.open_git_blame_commit_internal(window, cx);
20305    }
20306
20307    fn open_git_blame_commit_internal(
20308        &mut self,
20309        window: &mut Window,
20310        cx: &mut Context<Self>,
20311    ) -> Option<()> {
20312        let blame = self.blame.as_ref()?;
20313        let snapshot = self.snapshot(window, cx);
20314        let cursor = self
20315            .selections
20316            .newest::<Point>(&snapshot.display_snapshot)
20317            .head();
20318        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20319        let (_, blame_entry) = blame
20320            .update(cx, |blame, cx| {
20321                blame
20322                    .blame_for_rows(
20323                        &[RowInfo {
20324                            buffer_id: Some(buffer.remote_id()),
20325                            buffer_row: Some(point.row),
20326                            ..Default::default()
20327                        }],
20328                        cx,
20329                    )
20330                    .next()
20331            })
20332            .flatten()?;
20333        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20334        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20335        let workspace = self.workspace()?.downgrade();
20336        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20337        None
20338    }
20339
20340    pub fn git_blame_inline_enabled(&self) -> bool {
20341        self.git_blame_inline_enabled
20342    }
20343
20344    pub fn toggle_selection_menu(
20345        &mut self,
20346        _: &ToggleSelectionMenu,
20347        _: &mut Window,
20348        cx: &mut Context<Self>,
20349    ) {
20350        self.show_selection_menu = self
20351            .show_selection_menu
20352            .map(|show_selections_menu| !show_selections_menu)
20353            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20354
20355        cx.notify();
20356    }
20357
20358    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20359        self.show_selection_menu
20360            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20361    }
20362
20363    fn start_git_blame(
20364        &mut self,
20365        user_triggered: bool,
20366        window: &mut Window,
20367        cx: &mut Context<Self>,
20368    ) {
20369        if let Some(project) = self.project() {
20370            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20371                && buffer.read(cx).file().is_none()
20372            {
20373                return;
20374            }
20375
20376            let focused = self.focus_handle(cx).contains_focused(window, cx);
20377
20378            let project = project.clone();
20379            let blame = cx
20380                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20381            self.blame_subscription =
20382                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20383            self.blame = Some(blame);
20384        }
20385    }
20386
20387    fn toggle_git_blame_inline_internal(
20388        &mut self,
20389        user_triggered: bool,
20390        window: &mut Window,
20391        cx: &mut Context<Self>,
20392    ) {
20393        if self.git_blame_inline_enabled {
20394            self.git_blame_inline_enabled = false;
20395            self.show_git_blame_inline = false;
20396            self.show_git_blame_inline_delay_task.take();
20397        } else {
20398            self.git_blame_inline_enabled = true;
20399            self.start_git_blame_inline(user_triggered, window, cx);
20400        }
20401
20402        cx.notify();
20403    }
20404
20405    fn start_git_blame_inline(
20406        &mut self,
20407        user_triggered: bool,
20408        window: &mut Window,
20409        cx: &mut Context<Self>,
20410    ) {
20411        self.start_git_blame(user_triggered, window, cx);
20412
20413        if ProjectSettings::get_global(cx)
20414            .git
20415            .inline_blame_delay()
20416            .is_some()
20417        {
20418            self.start_inline_blame_timer(window, cx);
20419        } else {
20420            self.show_git_blame_inline = true
20421        }
20422    }
20423
20424    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20425        self.blame.as_ref()
20426    }
20427
20428    pub fn show_git_blame_gutter(&self) -> bool {
20429        self.show_git_blame_gutter
20430    }
20431
20432    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20433        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20434    }
20435
20436    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20437        self.show_git_blame_inline
20438            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20439            && !self.newest_selection_head_on_empty_line(cx)
20440            && self.has_blame_entries(cx)
20441    }
20442
20443    fn has_blame_entries(&self, cx: &App) -> bool {
20444        self.blame()
20445            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20446    }
20447
20448    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20449        let cursor_anchor = self.selections.newest_anchor().head();
20450
20451        let snapshot = self.buffer.read(cx).snapshot(cx);
20452        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20453
20454        snapshot.line_len(buffer_row) == 0
20455    }
20456
20457    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20458        let buffer_and_selection = maybe!({
20459            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20460            let selection_range = selection.range();
20461
20462            let multi_buffer = self.buffer().read(cx);
20463            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20464            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20465
20466            let (buffer, range, _) = if selection.reversed {
20467                buffer_ranges.first()
20468            } else {
20469                buffer_ranges.last()
20470            }?;
20471
20472            let selection = text::ToPoint::to_point(&range.start, buffer).row
20473                ..text::ToPoint::to_point(&range.end, buffer).row;
20474            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20475        });
20476
20477        let Some((buffer, selection)) = buffer_and_selection else {
20478            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20479        };
20480
20481        let Some(project) = self.project() else {
20482            return Task::ready(Err(anyhow!("editor does not have project")));
20483        };
20484
20485        project.update(cx, |project, cx| {
20486            project.get_permalink_to_line(&buffer, selection, cx)
20487        })
20488    }
20489
20490    pub fn copy_permalink_to_line(
20491        &mut self,
20492        _: &CopyPermalinkToLine,
20493        window: &mut Window,
20494        cx: &mut Context<Self>,
20495    ) {
20496        let permalink_task = self.get_permalink_to_line(cx);
20497        let workspace = self.workspace();
20498
20499        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20500            Ok(permalink) => {
20501                cx.update(|_, cx| {
20502                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20503                })
20504                .ok();
20505            }
20506            Err(err) => {
20507                let message = format!("Failed to copy permalink: {err}");
20508
20509                anyhow::Result::<()>::Err(err).log_err();
20510
20511                if let Some(workspace) = workspace {
20512                    workspace
20513                        .update_in(cx, |workspace, _, cx| {
20514                            struct CopyPermalinkToLine;
20515
20516                            workspace.show_toast(
20517                                Toast::new(
20518                                    NotificationId::unique::<CopyPermalinkToLine>(),
20519                                    message,
20520                                ),
20521                                cx,
20522                            )
20523                        })
20524                        .ok();
20525                }
20526            }
20527        })
20528        .detach();
20529    }
20530
20531    pub fn copy_file_location(
20532        &mut self,
20533        _: &CopyFileLocation,
20534        _: &mut Window,
20535        cx: &mut Context<Self>,
20536    ) {
20537        let selection = self
20538            .selections
20539            .newest::<Point>(&self.display_snapshot(cx))
20540            .start
20541            .row
20542            + 1;
20543        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20544            let project = self.project()?.read(cx);
20545            let file = buffer.read(cx).file()?;
20546            let path = file.path().display(project.path_style(cx));
20547
20548            Some(format!("{path}:{selection}"))
20549        }) {
20550            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20551        }
20552    }
20553
20554    pub fn open_permalink_to_line(
20555        &mut self,
20556        _: &OpenPermalinkToLine,
20557        window: &mut Window,
20558        cx: &mut Context<Self>,
20559    ) {
20560        let permalink_task = self.get_permalink_to_line(cx);
20561        let workspace = self.workspace();
20562
20563        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20564            Ok(permalink) => {
20565                cx.update(|_, cx| {
20566                    cx.open_url(permalink.as_ref());
20567                })
20568                .ok();
20569            }
20570            Err(err) => {
20571                let message = format!("Failed to open permalink: {err}");
20572
20573                anyhow::Result::<()>::Err(err).log_err();
20574
20575                if let Some(workspace) = workspace {
20576                    workspace
20577                        .update(cx, |workspace, cx| {
20578                            struct OpenPermalinkToLine;
20579
20580                            workspace.show_toast(
20581                                Toast::new(
20582                                    NotificationId::unique::<OpenPermalinkToLine>(),
20583                                    message,
20584                                ),
20585                                cx,
20586                            )
20587                        })
20588                        .ok();
20589                }
20590            }
20591        })
20592        .detach();
20593    }
20594
20595    pub fn insert_uuid_v4(
20596        &mut self,
20597        _: &InsertUuidV4,
20598        window: &mut Window,
20599        cx: &mut Context<Self>,
20600    ) {
20601        self.insert_uuid(UuidVersion::V4, window, cx);
20602    }
20603
20604    pub fn insert_uuid_v7(
20605        &mut self,
20606        _: &InsertUuidV7,
20607        window: &mut Window,
20608        cx: &mut Context<Self>,
20609    ) {
20610        self.insert_uuid(UuidVersion::V7, window, cx);
20611    }
20612
20613    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20615        self.transact(window, cx, |this, window, cx| {
20616            let edits = this
20617                .selections
20618                .all::<Point>(&this.display_snapshot(cx))
20619                .into_iter()
20620                .map(|selection| {
20621                    let uuid = match version {
20622                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20623                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20624                    };
20625
20626                    (selection.range(), uuid.to_string())
20627                });
20628            this.edit(edits, cx);
20629            this.refresh_edit_prediction(true, false, window, cx);
20630        });
20631    }
20632
20633    pub fn open_selections_in_multibuffer(
20634        &mut self,
20635        _: &OpenSelectionsInMultibuffer,
20636        window: &mut Window,
20637        cx: &mut Context<Self>,
20638    ) {
20639        let multibuffer = self.buffer.read(cx);
20640
20641        let Some(buffer) = multibuffer.as_singleton() else {
20642            return;
20643        };
20644
20645        let Some(workspace) = self.workspace() else {
20646            return;
20647        };
20648
20649        let title = multibuffer.title(cx).to_string();
20650
20651        let locations = self
20652            .selections
20653            .all_anchors(&self.display_snapshot(cx))
20654            .iter()
20655            .map(|selection| {
20656                (
20657                    buffer.clone(),
20658                    (selection.start.text_anchor..selection.end.text_anchor)
20659                        .to_point(buffer.read(cx)),
20660                )
20661            })
20662            .into_group_map();
20663
20664        cx.spawn_in(window, async move |_, cx| {
20665            workspace.update_in(cx, |workspace, window, cx| {
20666                Self::open_locations_in_multibuffer(
20667                    workspace,
20668                    locations,
20669                    format!("Selections for '{title}'"),
20670                    false,
20671                    MultibufferSelectionMode::All,
20672                    window,
20673                    cx,
20674                );
20675            })
20676        })
20677        .detach();
20678    }
20679
20680    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20681    /// last highlight added will be used.
20682    ///
20683    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20684    pub fn highlight_rows<T: 'static>(
20685        &mut self,
20686        range: Range<Anchor>,
20687        color: Hsla,
20688        options: RowHighlightOptions,
20689        cx: &mut Context<Self>,
20690    ) {
20691        let snapshot = self.buffer().read(cx).snapshot(cx);
20692        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20693        let ix = row_highlights.binary_search_by(|highlight| {
20694            Ordering::Equal
20695                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20696                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20697        });
20698
20699        if let Err(mut ix) = ix {
20700            let index = post_inc(&mut self.highlight_order);
20701
20702            // If this range intersects with the preceding highlight, then merge it with
20703            // the preceding highlight. Otherwise insert a new highlight.
20704            let mut merged = false;
20705            if ix > 0 {
20706                let prev_highlight = &mut row_highlights[ix - 1];
20707                if prev_highlight
20708                    .range
20709                    .end
20710                    .cmp(&range.start, &snapshot)
20711                    .is_ge()
20712                {
20713                    ix -= 1;
20714                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20715                        prev_highlight.range.end = range.end;
20716                    }
20717                    merged = true;
20718                    prev_highlight.index = index;
20719                    prev_highlight.color = color;
20720                    prev_highlight.options = options;
20721                }
20722            }
20723
20724            if !merged {
20725                row_highlights.insert(
20726                    ix,
20727                    RowHighlight {
20728                        range,
20729                        index,
20730                        color,
20731                        options,
20732                        type_id: TypeId::of::<T>(),
20733                    },
20734                );
20735            }
20736
20737            // If any of the following highlights intersect with this one, merge them.
20738            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20739                let highlight = &row_highlights[ix];
20740                if next_highlight
20741                    .range
20742                    .start
20743                    .cmp(&highlight.range.end, &snapshot)
20744                    .is_le()
20745                {
20746                    if next_highlight
20747                        .range
20748                        .end
20749                        .cmp(&highlight.range.end, &snapshot)
20750                        .is_gt()
20751                    {
20752                        row_highlights[ix].range.end = next_highlight.range.end;
20753                    }
20754                    row_highlights.remove(ix + 1);
20755                } else {
20756                    break;
20757                }
20758            }
20759        }
20760    }
20761
20762    /// Remove any highlighted row ranges of the given type that intersect the
20763    /// given ranges.
20764    pub fn remove_highlighted_rows<T: 'static>(
20765        &mut self,
20766        ranges_to_remove: Vec<Range<Anchor>>,
20767        cx: &mut Context<Self>,
20768    ) {
20769        let snapshot = self.buffer().read(cx).snapshot(cx);
20770        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20771        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20772        row_highlights.retain(|highlight| {
20773            while let Some(range_to_remove) = ranges_to_remove.peek() {
20774                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20775                    Ordering::Less | Ordering::Equal => {
20776                        ranges_to_remove.next();
20777                    }
20778                    Ordering::Greater => {
20779                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20780                            Ordering::Less | Ordering::Equal => {
20781                                return false;
20782                            }
20783                            Ordering::Greater => break,
20784                        }
20785                    }
20786                }
20787            }
20788
20789            true
20790        })
20791    }
20792
20793    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20794    pub fn clear_row_highlights<T: 'static>(&mut self) {
20795        self.highlighted_rows.remove(&TypeId::of::<T>());
20796    }
20797
20798    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20799    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20800        self.highlighted_rows
20801            .get(&TypeId::of::<T>())
20802            .map_or(&[] as &[_], |vec| vec.as_slice())
20803            .iter()
20804            .map(|highlight| (highlight.range.clone(), highlight.color))
20805    }
20806
20807    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20808    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20809    /// Allows to ignore certain kinds of highlights.
20810    pub fn highlighted_display_rows(
20811        &self,
20812        window: &mut Window,
20813        cx: &mut App,
20814    ) -> BTreeMap<DisplayRow, LineHighlight> {
20815        let snapshot = self.snapshot(window, cx);
20816        let mut used_highlight_orders = HashMap::default();
20817        self.highlighted_rows
20818            .iter()
20819            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20820            .fold(
20821                BTreeMap::<DisplayRow, LineHighlight>::new(),
20822                |mut unique_rows, highlight| {
20823                    let start = highlight.range.start.to_display_point(&snapshot);
20824                    let end = highlight.range.end.to_display_point(&snapshot);
20825                    let start_row = start.row().0;
20826                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20827                    {
20828                        end.row().0.saturating_sub(1)
20829                    } else {
20830                        end.row().0
20831                    };
20832                    for row in start_row..=end_row {
20833                        let used_index =
20834                            used_highlight_orders.entry(row).or_insert(highlight.index);
20835                        if highlight.index >= *used_index {
20836                            *used_index = highlight.index;
20837                            unique_rows.insert(
20838                                DisplayRow(row),
20839                                LineHighlight {
20840                                    include_gutter: highlight.options.include_gutter,
20841                                    border: None,
20842                                    background: highlight.color.into(),
20843                                    type_id: Some(highlight.type_id),
20844                                },
20845                            );
20846                        }
20847                    }
20848                    unique_rows
20849                },
20850            )
20851    }
20852
20853    pub fn highlighted_display_row_for_autoscroll(
20854        &self,
20855        snapshot: &DisplaySnapshot,
20856    ) -> Option<DisplayRow> {
20857        self.highlighted_rows
20858            .values()
20859            .flat_map(|highlighted_rows| highlighted_rows.iter())
20860            .filter_map(|highlight| {
20861                if highlight.options.autoscroll {
20862                    Some(highlight.range.start.to_display_point(snapshot).row())
20863                } else {
20864                    None
20865                }
20866            })
20867            .min()
20868    }
20869
20870    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20871        self.highlight_background::<SearchWithinRange>(
20872            ranges,
20873            |colors| colors.colors().editor_document_highlight_read_background,
20874            cx,
20875        )
20876    }
20877
20878    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20879        self.breadcrumb_header = Some(new_header);
20880    }
20881
20882    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20883        self.clear_background_highlights::<SearchWithinRange>(cx);
20884    }
20885
20886    pub fn highlight_background<T: 'static>(
20887        &mut self,
20888        ranges: &[Range<Anchor>],
20889        color_fetcher: fn(&Theme) -> Hsla,
20890        cx: &mut Context<Self>,
20891    ) {
20892        self.background_highlights.insert(
20893            HighlightKey::Type(TypeId::of::<T>()),
20894            (color_fetcher, Arc::from(ranges)),
20895        );
20896        self.scrollbar_marker_state.dirty = true;
20897        cx.notify();
20898    }
20899
20900    pub fn highlight_background_key<T: 'static>(
20901        &mut self,
20902        key: usize,
20903        ranges: &[Range<Anchor>],
20904        color_fetcher: fn(&Theme) -> Hsla,
20905        cx: &mut Context<Self>,
20906    ) {
20907        self.background_highlights.insert(
20908            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20909            (color_fetcher, Arc::from(ranges)),
20910        );
20911        self.scrollbar_marker_state.dirty = true;
20912        cx.notify();
20913    }
20914
20915    pub fn clear_background_highlights<T: 'static>(
20916        &mut self,
20917        cx: &mut Context<Self>,
20918    ) -> Option<BackgroundHighlight> {
20919        let text_highlights = self
20920            .background_highlights
20921            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20922        if !text_highlights.1.is_empty() {
20923            self.scrollbar_marker_state.dirty = true;
20924            cx.notify();
20925        }
20926        Some(text_highlights)
20927    }
20928
20929    pub fn highlight_gutter<T: 'static>(
20930        &mut self,
20931        ranges: impl Into<Vec<Range<Anchor>>>,
20932        color_fetcher: fn(&App) -> Hsla,
20933        cx: &mut Context<Self>,
20934    ) {
20935        self.gutter_highlights
20936            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20937        cx.notify();
20938    }
20939
20940    pub fn clear_gutter_highlights<T: 'static>(
20941        &mut self,
20942        cx: &mut Context<Self>,
20943    ) -> Option<GutterHighlight> {
20944        cx.notify();
20945        self.gutter_highlights.remove(&TypeId::of::<T>())
20946    }
20947
20948    pub fn insert_gutter_highlight<T: 'static>(
20949        &mut self,
20950        range: Range<Anchor>,
20951        color_fetcher: fn(&App) -> Hsla,
20952        cx: &mut Context<Self>,
20953    ) {
20954        let snapshot = self.buffer().read(cx).snapshot(cx);
20955        let mut highlights = self
20956            .gutter_highlights
20957            .remove(&TypeId::of::<T>())
20958            .map(|(_, highlights)| highlights)
20959            .unwrap_or_default();
20960        let ix = highlights.binary_search_by(|highlight| {
20961            Ordering::Equal
20962                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20963                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20964        });
20965        if let Err(ix) = ix {
20966            highlights.insert(ix, range);
20967        }
20968        self.gutter_highlights
20969            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20970    }
20971
20972    pub fn remove_gutter_highlights<T: 'static>(
20973        &mut self,
20974        ranges_to_remove: Vec<Range<Anchor>>,
20975        cx: &mut Context<Self>,
20976    ) {
20977        let snapshot = self.buffer().read(cx).snapshot(cx);
20978        let Some((color_fetcher, mut gutter_highlights)) =
20979            self.gutter_highlights.remove(&TypeId::of::<T>())
20980        else {
20981            return;
20982        };
20983        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20984        gutter_highlights.retain(|highlight| {
20985            while let Some(range_to_remove) = ranges_to_remove.peek() {
20986                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20987                    Ordering::Less | Ordering::Equal => {
20988                        ranges_to_remove.next();
20989                    }
20990                    Ordering::Greater => {
20991                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20992                            Ordering::Less | Ordering::Equal => {
20993                                return false;
20994                            }
20995                            Ordering::Greater => break,
20996                        }
20997                    }
20998                }
20999            }
21000
21001            true
21002        });
21003        self.gutter_highlights
21004            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21005    }
21006
21007    #[cfg(feature = "test-support")]
21008    pub fn all_text_highlights(
21009        &self,
21010        window: &mut Window,
21011        cx: &mut Context<Self>,
21012    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21013        let snapshot = self.snapshot(window, cx);
21014        self.display_map.update(cx, |display_map, _| {
21015            display_map
21016                .all_text_highlights()
21017                .map(|highlight| {
21018                    let (style, ranges) = highlight.as_ref();
21019                    (
21020                        *style,
21021                        ranges
21022                            .iter()
21023                            .map(|range| range.clone().to_display_points(&snapshot))
21024                            .collect(),
21025                    )
21026                })
21027                .collect()
21028        })
21029    }
21030
21031    #[cfg(feature = "test-support")]
21032    pub fn all_text_background_highlights(
21033        &self,
21034        window: &mut Window,
21035        cx: &mut Context<Self>,
21036    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21037        let snapshot = self.snapshot(window, cx);
21038        let buffer = &snapshot.buffer_snapshot();
21039        let start = buffer.anchor_before(MultiBufferOffset(0));
21040        let end = buffer.anchor_after(buffer.len());
21041        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21042    }
21043
21044    #[cfg(any(test, feature = "test-support"))]
21045    pub fn sorted_background_highlights_in_range(
21046        &self,
21047        search_range: Range<Anchor>,
21048        display_snapshot: &DisplaySnapshot,
21049        theme: &Theme,
21050    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21051        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21052        res.sort_by(|a, b| {
21053            a.0.start
21054                .cmp(&b.0.start)
21055                .then_with(|| a.0.end.cmp(&b.0.end))
21056                .then_with(|| a.1.cmp(&b.1))
21057        });
21058        res
21059    }
21060
21061    #[cfg(feature = "test-support")]
21062    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21063        let snapshot = self.buffer().read(cx).snapshot(cx);
21064
21065        let highlights = self
21066            .background_highlights
21067            .get(&HighlightKey::Type(TypeId::of::<
21068                items::BufferSearchHighlights,
21069            >()));
21070
21071        if let Some((_color, ranges)) = highlights {
21072            ranges
21073                .iter()
21074                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21075                .collect_vec()
21076        } else {
21077            vec![]
21078        }
21079    }
21080
21081    fn document_highlights_for_position<'a>(
21082        &'a self,
21083        position: Anchor,
21084        buffer: &'a MultiBufferSnapshot,
21085    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21086        let read_highlights = self
21087            .background_highlights
21088            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21089            .map(|h| &h.1);
21090        let write_highlights = self
21091            .background_highlights
21092            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21093            .map(|h| &h.1);
21094        let left_position = position.bias_left(buffer);
21095        let right_position = position.bias_right(buffer);
21096        read_highlights
21097            .into_iter()
21098            .chain(write_highlights)
21099            .flat_map(move |ranges| {
21100                let start_ix = match ranges.binary_search_by(|probe| {
21101                    let cmp = probe.end.cmp(&left_position, buffer);
21102                    if cmp.is_ge() {
21103                        Ordering::Greater
21104                    } else {
21105                        Ordering::Less
21106                    }
21107                }) {
21108                    Ok(i) | Err(i) => i,
21109                };
21110
21111                ranges[start_ix..]
21112                    .iter()
21113                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21114            })
21115    }
21116
21117    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21118        self.background_highlights
21119            .get(&HighlightKey::Type(TypeId::of::<T>()))
21120            .is_some_and(|(_, highlights)| !highlights.is_empty())
21121    }
21122
21123    /// Returns all background highlights for a given range.
21124    ///
21125    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21126    pub fn background_highlights_in_range(
21127        &self,
21128        search_range: Range<Anchor>,
21129        display_snapshot: &DisplaySnapshot,
21130        theme: &Theme,
21131    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21132        let mut results = Vec::new();
21133        for (color_fetcher, ranges) in self.background_highlights.values() {
21134            let color = color_fetcher(theme);
21135            let start_ix = match ranges.binary_search_by(|probe| {
21136                let cmp = probe
21137                    .end
21138                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21139                if cmp.is_gt() {
21140                    Ordering::Greater
21141                } else {
21142                    Ordering::Less
21143                }
21144            }) {
21145                Ok(i) | Err(i) => i,
21146            };
21147            for range in &ranges[start_ix..] {
21148                if range
21149                    .start
21150                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21151                    .is_ge()
21152                {
21153                    break;
21154                }
21155
21156                let start = range.start.to_display_point(display_snapshot);
21157                let end = range.end.to_display_point(display_snapshot);
21158                results.push((start..end, color))
21159            }
21160        }
21161        results
21162    }
21163
21164    pub fn gutter_highlights_in_range(
21165        &self,
21166        search_range: Range<Anchor>,
21167        display_snapshot: &DisplaySnapshot,
21168        cx: &App,
21169    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21170        let mut results = Vec::new();
21171        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21172            let color = color_fetcher(cx);
21173            let start_ix = match ranges.binary_search_by(|probe| {
21174                let cmp = probe
21175                    .end
21176                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21177                if cmp.is_gt() {
21178                    Ordering::Greater
21179                } else {
21180                    Ordering::Less
21181                }
21182            }) {
21183                Ok(i) | Err(i) => i,
21184            };
21185            for range in &ranges[start_ix..] {
21186                if range
21187                    .start
21188                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21189                    .is_ge()
21190                {
21191                    break;
21192                }
21193
21194                let start = range.start.to_display_point(display_snapshot);
21195                let end = range.end.to_display_point(display_snapshot);
21196                results.push((start..end, color))
21197            }
21198        }
21199        results
21200    }
21201
21202    /// Get the text ranges corresponding to the redaction query
21203    pub fn redacted_ranges(
21204        &self,
21205        search_range: Range<Anchor>,
21206        display_snapshot: &DisplaySnapshot,
21207        cx: &App,
21208    ) -> Vec<Range<DisplayPoint>> {
21209        display_snapshot
21210            .buffer_snapshot()
21211            .redacted_ranges(search_range, |file| {
21212                if let Some(file) = file {
21213                    file.is_private()
21214                        && EditorSettings::get(
21215                            Some(SettingsLocation {
21216                                worktree_id: file.worktree_id(cx),
21217                                path: file.path().as_ref(),
21218                            }),
21219                            cx,
21220                        )
21221                        .redact_private_values
21222                } else {
21223                    false
21224                }
21225            })
21226            .map(|range| {
21227                range.start.to_display_point(display_snapshot)
21228                    ..range.end.to_display_point(display_snapshot)
21229            })
21230            .collect()
21231    }
21232
21233    pub fn highlight_text_key<T: 'static>(
21234        &mut self,
21235        key: usize,
21236        ranges: Vec<Range<Anchor>>,
21237        style: HighlightStyle,
21238        merge: bool,
21239        cx: &mut Context<Self>,
21240    ) {
21241        self.display_map.update(cx, |map, cx| {
21242            map.highlight_text(
21243                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21244                ranges,
21245                style,
21246                merge,
21247                cx,
21248            );
21249        });
21250        cx.notify();
21251    }
21252
21253    pub fn highlight_text<T: 'static>(
21254        &mut self,
21255        ranges: Vec<Range<Anchor>>,
21256        style: HighlightStyle,
21257        cx: &mut Context<Self>,
21258    ) {
21259        self.display_map.update(cx, |map, cx| {
21260            map.highlight_text(
21261                HighlightKey::Type(TypeId::of::<T>()),
21262                ranges,
21263                style,
21264                false,
21265                cx,
21266            )
21267        });
21268        cx.notify();
21269    }
21270
21271    pub fn text_highlights<'a, T: 'static>(
21272        &'a self,
21273        cx: &'a App,
21274    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21275        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21276    }
21277
21278    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21279        let cleared = self
21280            .display_map
21281            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21282        if cleared {
21283            cx.notify();
21284        }
21285    }
21286
21287    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21288        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21289            && self.focus_handle.is_focused(window)
21290    }
21291
21292    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21293        self.show_cursor_when_unfocused = is_enabled;
21294        cx.notify();
21295    }
21296
21297    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21298        cx.notify();
21299    }
21300
21301    fn on_debug_session_event(
21302        &mut self,
21303        _session: Entity<Session>,
21304        event: &SessionEvent,
21305        cx: &mut Context<Self>,
21306    ) {
21307        if let SessionEvent::InvalidateInlineValue = event {
21308            self.refresh_inline_values(cx);
21309        }
21310    }
21311
21312    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21313        let Some(project) = self.project.clone() else {
21314            return;
21315        };
21316
21317        if !self.inline_value_cache.enabled {
21318            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21319            self.splice_inlays(&inlays, Vec::new(), cx);
21320            return;
21321        }
21322
21323        let current_execution_position = self
21324            .highlighted_rows
21325            .get(&TypeId::of::<ActiveDebugLine>())
21326            .and_then(|lines| lines.last().map(|line| line.range.end));
21327
21328        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21329            let inline_values = editor
21330                .update(cx, |editor, cx| {
21331                    let Some(current_execution_position) = current_execution_position else {
21332                        return Some(Task::ready(Ok(Vec::new())));
21333                    };
21334
21335                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21336                        let snapshot = buffer.snapshot(cx);
21337
21338                        let excerpt = snapshot.excerpt_containing(
21339                            current_execution_position..current_execution_position,
21340                        )?;
21341
21342                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21343                    })?;
21344
21345                    let range =
21346                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21347
21348                    project.inline_values(buffer, range, cx)
21349                })
21350                .ok()
21351                .flatten()?
21352                .await
21353                .context("refreshing debugger inlays")
21354                .log_err()?;
21355
21356            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21357
21358            for (buffer_id, inline_value) in inline_values
21359                .into_iter()
21360                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21361            {
21362                buffer_inline_values
21363                    .entry(buffer_id)
21364                    .or_default()
21365                    .push(inline_value);
21366            }
21367
21368            editor
21369                .update(cx, |editor, cx| {
21370                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21371                    let mut new_inlays = Vec::default();
21372
21373                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21374                        let buffer_id = buffer_snapshot.remote_id();
21375                        buffer_inline_values
21376                            .get(&buffer_id)
21377                            .into_iter()
21378                            .flatten()
21379                            .for_each(|hint| {
21380                                let inlay = Inlay::debugger(
21381                                    post_inc(&mut editor.next_inlay_id),
21382                                    Anchor::in_buffer(excerpt_id, hint.position),
21383                                    hint.text(),
21384                                );
21385                                if !inlay.text().chars().contains(&'\n') {
21386                                    new_inlays.push(inlay);
21387                                }
21388                            });
21389                    }
21390
21391                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21392                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21393
21394                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21395                })
21396                .ok()?;
21397            Some(())
21398        });
21399    }
21400
21401    fn on_buffer_event(
21402        &mut self,
21403        multibuffer: &Entity<MultiBuffer>,
21404        event: &multi_buffer::Event,
21405        window: &mut Window,
21406        cx: &mut Context<Self>,
21407    ) {
21408        match event {
21409            multi_buffer::Event::Edited { edited_buffer } => {
21410                self.scrollbar_marker_state.dirty = true;
21411                self.active_indent_guides_state.dirty = true;
21412                self.refresh_active_diagnostics(cx);
21413                self.refresh_code_actions(window, cx);
21414                self.refresh_single_line_folds(window, cx);
21415                self.refresh_matching_bracket_highlights(window, cx);
21416                if self.has_active_edit_prediction() {
21417                    self.update_visible_edit_prediction(window, cx);
21418                }
21419
21420                if let Some(buffer) = edited_buffer {
21421                    if buffer.read(cx).file().is_none() {
21422                        cx.emit(EditorEvent::TitleChanged);
21423                    }
21424
21425                    if self.project.is_some() {
21426                        let buffer_id = buffer.read(cx).remote_id();
21427                        self.register_buffer(buffer_id, cx);
21428                        self.update_lsp_data(Some(buffer_id), window, cx);
21429                        self.refresh_inlay_hints(
21430                            InlayHintRefreshReason::BufferEdited(buffer_id),
21431                            cx,
21432                        );
21433                    }
21434                }
21435
21436                cx.emit(EditorEvent::BufferEdited);
21437                cx.emit(SearchEvent::MatchesInvalidated);
21438
21439                let Some(project) = &self.project else { return };
21440                let (telemetry, is_via_ssh) = {
21441                    let project = project.read(cx);
21442                    let telemetry = project.client().telemetry().clone();
21443                    let is_via_ssh = project.is_via_remote_server();
21444                    (telemetry, is_via_ssh)
21445                };
21446                telemetry.log_edit_event("editor", is_via_ssh);
21447            }
21448            multi_buffer::Event::ExcerptsAdded {
21449                buffer,
21450                predecessor,
21451                excerpts,
21452            } => {
21453                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21454                let buffer_id = buffer.read(cx).remote_id();
21455                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21456                    && let Some(project) = &self.project
21457                {
21458                    update_uncommitted_diff_for_buffer(
21459                        cx.entity(),
21460                        project,
21461                        [buffer.clone()],
21462                        self.buffer.clone(),
21463                        cx,
21464                    )
21465                    .detach();
21466                }
21467                self.update_lsp_data(Some(buffer_id), window, cx);
21468                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21469                self.colorize_brackets(false, cx);
21470                cx.emit(EditorEvent::ExcerptsAdded {
21471                    buffer: buffer.clone(),
21472                    predecessor: *predecessor,
21473                    excerpts: excerpts.clone(),
21474                });
21475            }
21476            multi_buffer::Event::ExcerptsRemoved {
21477                ids,
21478                removed_buffer_ids,
21479            } => {
21480                if let Some(inlay_hints) = &mut self.inlay_hints {
21481                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21482                }
21483                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21484                for buffer_id in removed_buffer_ids {
21485                    self.registered_buffers.remove(buffer_id);
21486                }
21487                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21488                cx.emit(EditorEvent::ExcerptsRemoved {
21489                    ids: ids.clone(),
21490                    removed_buffer_ids: removed_buffer_ids.clone(),
21491                });
21492            }
21493            multi_buffer::Event::ExcerptsEdited {
21494                excerpt_ids,
21495                buffer_ids,
21496            } => {
21497                self.display_map.update(cx, |map, cx| {
21498                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21499                });
21500                cx.emit(EditorEvent::ExcerptsEdited {
21501                    ids: excerpt_ids.clone(),
21502                });
21503            }
21504            multi_buffer::Event::ExcerptsExpanded { ids } => {
21505                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21506                self.refresh_document_highlights(cx);
21507                for id in ids {
21508                    self.fetched_tree_sitter_chunks.remove(id);
21509                }
21510                self.colorize_brackets(false, cx);
21511                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21512            }
21513            multi_buffer::Event::Reparsed(buffer_id) => {
21514                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21515                self.refresh_selected_text_highlights(true, window, cx);
21516                self.colorize_brackets(true, cx);
21517                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21518
21519                cx.emit(EditorEvent::Reparsed(*buffer_id));
21520            }
21521            multi_buffer::Event::DiffHunksToggled => {
21522                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21523            }
21524            multi_buffer::Event::LanguageChanged(buffer_id) => {
21525                self.registered_buffers.remove(&buffer_id);
21526                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21527                cx.emit(EditorEvent::Reparsed(*buffer_id));
21528                cx.notify();
21529            }
21530            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21531            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21532            multi_buffer::Event::FileHandleChanged
21533            | multi_buffer::Event::Reloaded
21534            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21535            multi_buffer::Event::DiagnosticsUpdated => {
21536                self.update_diagnostics_state(window, cx);
21537            }
21538            _ => {}
21539        };
21540    }
21541
21542    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21543        if !self.diagnostics_enabled() {
21544            return;
21545        }
21546        self.refresh_active_diagnostics(cx);
21547        self.refresh_inline_diagnostics(true, window, cx);
21548        self.scrollbar_marker_state.dirty = true;
21549        cx.notify();
21550    }
21551
21552    pub fn start_temporary_diff_override(&mut self) {
21553        self.load_diff_task.take();
21554        self.temporary_diff_override = true;
21555    }
21556
21557    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21558        self.temporary_diff_override = false;
21559        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21560        self.buffer.update(cx, |buffer, cx| {
21561            buffer.set_all_diff_hunks_collapsed(cx);
21562        });
21563
21564        if let Some(project) = self.project.clone() {
21565            self.load_diff_task = Some(
21566                update_uncommitted_diff_for_buffer(
21567                    cx.entity(),
21568                    &project,
21569                    self.buffer.read(cx).all_buffers(),
21570                    self.buffer.clone(),
21571                    cx,
21572                )
21573                .shared(),
21574            );
21575        }
21576    }
21577
21578    fn on_display_map_changed(
21579        &mut self,
21580        _: Entity<DisplayMap>,
21581        _: &mut Window,
21582        cx: &mut Context<Self>,
21583    ) {
21584        cx.notify();
21585    }
21586
21587    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21588        if !self.mode.is_full() {
21589            return Vec::new();
21590        }
21591
21592        let theme_settings = theme::ThemeSettings::get_global(cx);
21593
21594        theme_settings
21595            .theme_overrides
21596            .get(cx.theme().name.as_ref())
21597            .map(|theme_style| &theme_style.accents)
21598            .into_iter()
21599            .flatten()
21600            .chain(
21601                theme_settings
21602                    .experimental_theme_overrides
21603                    .as_ref()
21604                    .map(|overrides| &overrides.accents)
21605                    .into_iter()
21606                    .flatten(),
21607            )
21608            .flat_map(|accent| accent.0.clone())
21609            .collect()
21610    }
21611
21612    fn fetch_applicable_language_settings(
21613        &self,
21614        cx: &App,
21615    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21616        if !self.mode.is_full() {
21617            return HashMap::default();
21618        }
21619
21620        self.buffer().read(cx).all_buffers().into_iter().fold(
21621            HashMap::default(),
21622            |mut acc, buffer| {
21623                let buffer = buffer.read(cx);
21624                let language = buffer.language().map(|language| language.name());
21625                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21626                    let file = buffer.file();
21627                    v.insert(language_settings(language, file, cx).into_owned());
21628                }
21629                acc
21630            },
21631        )
21632    }
21633
21634    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21635        let new_language_settings = self.fetch_applicable_language_settings(cx);
21636        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21637        self.applicable_language_settings = new_language_settings;
21638
21639        let new_accent_overrides = self.fetch_accent_overrides(cx);
21640        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21641        self.accent_overrides = new_accent_overrides;
21642
21643        if self.diagnostics_enabled() {
21644            let new_severity = EditorSettings::get_global(cx)
21645                .diagnostics_max_severity
21646                .unwrap_or(DiagnosticSeverity::Hint);
21647            self.set_max_diagnostics_severity(new_severity, cx);
21648        }
21649        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21650        self.update_edit_prediction_settings(cx);
21651        self.refresh_edit_prediction(true, false, window, cx);
21652        self.refresh_inline_values(cx);
21653        self.refresh_inlay_hints(
21654            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21655                self.selections.newest_anchor().head(),
21656                &self.buffer.read(cx).snapshot(cx),
21657                cx,
21658            )),
21659            cx,
21660        );
21661
21662        let old_cursor_shape = self.cursor_shape;
21663        let old_show_breadcrumbs = self.show_breadcrumbs;
21664
21665        {
21666            let editor_settings = EditorSettings::get_global(cx);
21667            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21668            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21669            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21670            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21671        }
21672
21673        if old_cursor_shape != self.cursor_shape {
21674            cx.emit(EditorEvent::CursorShapeChanged);
21675        }
21676
21677        if old_show_breadcrumbs != self.show_breadcrumbs {
21678            cx.emit(EditorEvent::BreadcrumbsChanged);
21679        }
21680
21681        let project_settings = ProjectSettings::get_global(cx);
21682        self.buffer_serialization = self
21683            .should_serialize_buffer()
21684            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21685
21686        if self.mode.is_full() {
21687            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21688            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21689            if self.show_inline_diagnostics != show_inline_diagnostics {
21690                self.show_inline_diagnostics = show_inline_diagnostics;
21691                self.refresh_inline_diagnostics(false, window, cx);
21692            }
21693
21694            if self.git_blame_inline_enabled != inline_blame_enabled {
21695                self.toggle_git_blame_inline_internal(false, window, cx);
21696            }
21697
21698            let minimap_settings = EditorSettings::get_global(cx).minimap;
21699            if self.minimap_visibility != MinimapVisibility::Disabled {
21700                if self.minimap_visibility.settings_visibility()
21701                    != minimap_settings.minimap_enabled()
21702                {
21703                    self.set_minimap_visibility(
21704                        MinimapVisibility::for_mode(self.mode(), cx),
21705                        window,
21706                        cx,
21707                    );
21708                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21709                    minimap_entity.update(cx, |minimap_editor, cx| {
21710                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21711                    })
21712                }
21713            }
21714
21715            if language_settings_changed || accent_overrides_changed {
21716                self.colorize_brackets(true, cx);
21717            }
21718
21719            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21720                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21721            }) {
21722                if !inlay_splice.is_empty() {
21723                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21724                }
21725                self.refresh_colors_for_visible_range(None, window, cx);
21726            }
21727        }
21728
21729        cx.notify();
21730    }
21731
21732    pub fn set_searchable(&mut self, searchable: bool) {
21733        self.searchable = searchable;
21734    }
21735
21736    pub fn searchable(&self) -> bool {
21737        self.searchable
21738    }
21739
21740    pub fn open_excerpts_in_split(
21741        &mut self,
21742        _: &OpenExcerptsSplit,
21743        window: &mut Window,
21744        cx: &mut Context<Self>,
21745    ) {
21746        self.open_excerpts_common(None, true, window, cx)
21747    }
21748
21749    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21750        self.open_excerpts_common(None, false, window, cx)
21751    }
21752
21753    fn open_excerpts_common(
21754        &mut self,
21755        jump_data: Option<JumpData>,
21756        split: bool,
21757        window: &mut Window,
21758        cx: &mut Context<Self>,
21759    ) {
21760        let Some(workspace) = self.workspace() else {
21761            cx.propagate();
21762            return;
21763        };
21764
21765        if self.buffer.read(cx).is_singleton() {
21766            cx.propagate();
21767            return;
21768        }
21769
21770        let mut new_selections_by_buffer = HashMap::default();
21771        match &jump_data {
21772            Some(JumpData::MultiBufferPoint {
21773                excerpt_id,
21774                position,
21775                anchor,
21776                line_offset_from_top,
21777            }) => {
21778                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21779                if let Some(buffer) = multi_buffer_snapshot
21780                    .buffer_id_for_excerpt(*excerpt_id)
21781                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21782                {
21783                    let buffer_snapshot = buffer.read(cx).snapshot();
21784                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21785                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21786                    } else {
21787                        buffer_snapshot.clip_point(*position, Bias::Left)
21788                    };
21789                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21790                    new_selections_by_buffer.insert(
21791                        buffer,
21792                        (
21793                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21794                            Some(*line_offset_from_top),
21795                        ),
21796                    );
21797                }
21798            }
21799            Some(JumpData::MultiBufferRow {
21800                row,
21801                line_offset_from_top,
21802            }) => {
21803                let point = MultiBufferPoint::new(row.0, 0);
21804                if let Some((buffer, buffer_point, _)) =
21805                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21806                {
21807                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21808                    new_selections_by_buffer
21809                        .entry(buffer)
21810                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21811                        .0
21812                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21813                }
21814            }
21815            None => {
21816                let selections = self
21817                    .selections
21818                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21819                let multi_buffer = self.buffer.read(cx);
21820                for selection in selections {
21821                    for (snapshot, range, _, anchor) in multi_buffer
21822                        .snapshot(cx)
21823                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21824                    {
21825                        if let Some(anchor) = anchor {
21826                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21827                            else {
21828                                continue;
21829                            };
21830                            let offset = text::ToOffset::to_offset(
21831                                &anchor.text_anchor,
21832                                &buffer_handle.read(cx).snapshot(),
21833                            );
21834                            let range = BufferOffset(offset)..BufferOffset(offset);
21835                            new_selections_by_buffer
21836                                .entry(buffer_handle)
21837                                .or_insert((Vec::new(), None))
21838                                .0
21839                                .push(range)
21840                        } else {
21841                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21842                            else {
21843                                continue;
21844                            };
21845                            new_selections_by_buffer
21846                                .entry(buffer_handle)
21847                                .or_insert((Vec::new(), None))
21848                                .0
21849                                .push(range)
21850                        }
21851                    }
21852                }
21853            }
21854        }
21855
21856        new_selections_by_buffer
21857            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21858
21859        if new_selections_by_buffer.is_empty() {
21860            return;
21861        }
21862
21863        // We defer the pane interaction because we ourselves are a workspace item
21864        // and activating a new item causes the pane to call a method on us reentrantly,
21865        // which panics if we're on the stack.
21866        window.defer(cx, move |window, cx| {
21867            workspace.update(cx, |workspace, cx| {
21868                let pane = if split {
21869                    workspace.adjacent_pane(window, cx)
21870                } else {
21871                    workspace.active_pane().clone()
21872                };
21873
21874                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21875                    let editor = buffer
21876                        .read(cx)
21877                        .file()
21878                        .is_none()
21879                        .then(|| {
21880                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21881                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21882                            // Instead, we try to activate the existing editor in the pane first.
21883                            let (editor, pane_item_index) =
21884                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21885                                    let editor = item.downcast::<Editor>()?;
21886                                    let singleton_buffer =
21887                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21888                                    if singleton_buffer == buffer {
21889                                        Some((editor, i))
21890                                    } else {
21891                                        None
21892                                    }
21893                                })?;
21894                            pane.update(cx, |pane, cx| {
21895                                pane.activate_item(pane_item_index, true, true, window, cx)
21896                            });
21897                            Some(editor)
21898                        })
21899                        .flatten()
21900                        .unwrap_or_else(|| {
21901                            workspace.open_project_item::<Self>(
21902                                pane.clone(),
21903                                buffer,
21904                                true,
21905                                true,
21906                                window,
21907                                cx,
21908                            )
21909                        });
21910
21911                    editor.update(cx, |editor, cx| {
21912                        let autoscroll = match scroll_offset {
21913                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21914                            None => Autoscroll::newest(),
21915                        };
21916                        let nav_history = editor.nav_history.take();
21917                        editor.change_selections(
21918                            SelectionEffects::scroll(autoscroll),
21919                            window,
21920                            cx,
21921                            |s| {
21922                                s.select_ranges(ranges.into_iter().map(|range| {
21923                                    // we checked that the editor is a singleton editor so the offsets are valid
21924                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21925                                }));
21926                            },
21927                        );
21928                        editor.nav_history = nav_history;
21929                    });
21930                }
21931            })
21932        });
21933    }
21934
21935    // For now, don't allow opening excerpts in buffers that aren't backed by
21936    // regular project files.
21937    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21938        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21939    }
21940
21941    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21942        let snapshot = self.buffer.read(cx).read(cx);
21943        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21944        Some(
21945            ranges
21946                .iter()
21947                .map(move |range| {
21948                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21949                })
21950                .collect(),
21951        )
21952    }
21953
21954    fn selection_replacement_ranges(
21955        &self,
21956        range: Range<MultiBufferOffsetUtf16>,
21957        cx: &mut App,
21958    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21959        let selections = self
21960            .selections
21961            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21962        let newest_selection = selections
21963            .iter()
21964            .max_by_key(|selection| selection.id)
21965            .unwrap();
21966        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21967        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21968        let snapshot = self.buffer.read(cx).read(cx);
21969        selections
21970            .into_iter()
21971            .map(|mut selection| {
21972                selection.start.0.0 =
21973                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21974                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21975                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21976                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21977            })
21978            .collect()
21979    }
21980
21981    fn report_editor_event(
21982        &self,
21983        reported_event: ReportEditorEvent,
21984        file_extension: Option<String>,
21985        cx: &App,
21986    ) {
21987        if cfg!(any(test, feature = "test-support")) {
21988            return;
21989        }
21990
21991        let Some(project) = &self.project else { return };
21992
21993        // If None, we are in a file without an extension
21994        let file = self
21995            .buffer
21996            .read(cx)
21997            .as_singleton()
21998            .and_then(|b| b.read(cx).file());
21999        let file_extension = file_extension.or(file
22000            .as_ref()
22001            .and_then(|file| Path::new(file.file_name(cx)).extension())
22002            .and_then(|e| e.to_str())
22003            .map(|a| a.to_string()));
22004
22005        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22006            .map(|vim_mode| vim_mode.0)
22007            .unwrap_or(false);
22008
22009        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22010        let copilot_enabled = edit_predictions_provider
22011            == language::language_settings::EditPredictionProvider::Copilot;
22012        let copilot_enabled_for_language = self
22013            .buffer
22014            .read(cx)
22015            .language_settings(cx)
22016            .show_edit_predictions;
22017
22018        let project = project.read(cx);
22019        let event_type = reported_event.event_type();
22020
22021        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22022            telemetry::event!(
22023                event_type,
22024                type = if auto_saved {"autosave"} else {"manual"},
22025                file_extension,
22026                vim_mode,
22027                copilot_enabled,
22028                copilot_enabled_for_language,
22029                edit_predictions_provider,
22030                is_via_ssh = project.is_via_remote_server(),
22031            );
22032        } else {
22033            telemetry::event!(
22034                event_type,
22035                file_extension,
22036                vim_mode,
22037                copilot_enabled,
22038                copilot_enabled_for_language,
22039                edit_predictions_provider,
22040                is_via_ssh = project.is_via_remote_server(),
22041            );
22042        };
22043    }
22044
22045    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22046    /// with each line being an array of {text, highlight} objects.
22047    fn copy_highlight_json(
22048        &mut self,
22049        _: &CopyHighlightJson,
22050        window: &mut Window,
22051        cx: &mut Context<Self>,
22052    ) {
22053        #[derive(Serialize)]
22054        struct Chunk<'a> {
22055            text: String,
22056            highlight: Option<&'a str>,
22057        }
22058
22059        let snapshot = self.buffer.read(cx).snapshot(cx);
22060        let range = self
22061            .selected_text_range(false, window, cx)
22062            .and_then(|selection| {
22063                if selection.range.is_empty() {
22064                    None
22065                } else {
22066                    Some(
22067                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22068                            selection.range.start,
22069                        )))
22070                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22071                                selection.range.end,
22072                            ))),
22073                    )
22074                }
22075            })
22076            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22077
22078        let chunks = snapshot.chunks(range, true);
22079        let mut lines = Vec::new();
22080        let mut line: VecDeque<Chunk> = VecDeque::new();
22081
22082        let Some(style) = self.style.as_ref() else {
22083            return;
22084        };
22085
22086        for chunk in chunks {
22087            let highlight = chunk
22088                .syntax_highlight_id
22089                .and_then(|id| id.name(&style.syntax));
22090            let mut chunk_lines = chunk.text.split('\n').peekable();
22091            while let Some(text) = chunk_lines.next() {
22092                let mut merged_with_last_token = false;
22093                if let Some(last_token) = line.back_mut()
22094                    && last_token.highlight == highlight
22095                {
22096                    last_token.text.push_str(text);
22097                    merged_with_last_token = true;
22098                }
22099
22100                if !merged_with_last_token {
22101                    line.push_back(Chunk {
22102                        text: text.into(),
22103                        highlight,
22104                    });
22105                }
22106
22107                if chunk_lines.peek().is_some() {
22108                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22109                        line.pop_front();
22110                    }
22111                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22112                        line.pop_back();
22113                    }
22114
22115                    lines.push(mem::take(&mut line));
22116                }
22117            }
22118        }
22119
22120        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22121            return;
22122        };
22123        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22124    }
22125
22126    pub fn open_context_menu(
22127        &mut self,
22128        _: &OpenContextMenu,
22129        window: &mut Window,
22130        cx: &mut Context<Self>,
22131    ) {
22132        self.request_autoscroll(Autoscroll::newest(), cx);
22133        let position = self
22134            .selections
22135            .newest_display(&self.display_snapshot(cx))
22136            .start;
22137        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22138    }
22139
22140    pub fn replay_insert_event(
22141        &mut self,
22142        text: &str,
22143        relative_utf16_range: Option<Range<isize>>,
22144        window: &mut Window,
22145        cx: &mut Context<Self>,
22146    ) {
22147        if !self.input_enabled {
22148            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22149            return;
22150        }
22151        if let Some(relative_utf16_range) = relative_utf16_range {
22152            let selections = self
22153                .selections
22154                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22155            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22156                let new_ranges = selections.into_iter().map(|range| {
22157                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22158                        range
22159                            .head()
22160                            .0
22161                            .0
22162                            .saturating_add_signed(relative_utf16_range.start),
22163                    ));
22164                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22165                        range
22166                            .head()
22167                            .0
22168                            .0
22169                            .saturating_add_signed(relative_utf16_range.end),
22170                    ));
22171                    start..end
22172                });
22173                s.select_ranges(new_ranges);
22174            });
22175        }
22176
22177        self.handle_input(text, window, cx);
22178    }
22179
22180    pub fn is_focused(&self, window: &Window) -> bool {
22181        self.focus_handle.is_focused(window)
22182    }
22183
22184    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22185        cx.emit(EditorEvent::Focused);
22186
22187        if let Some(descendant) = self
22188            .last_focused_descendant
22189            .take()
22190            .and_then(|descendant| descendant.upgrade())
22191        {
22192            window.focus(&descendant);
22193        } else {
22194            if let Some(blame) = self.blame.as_ref() {
22195                blame.update(cx, GitBlame::focus)
22196            }
22197
22198            self.blink_manager.update(cx, BlinkManager::enable);
22199            self.show_cursor_names(window, cx);
22200            self.buffer.update(cx, |buffer, cx| {
22201                buffer.finalize_last_transaction(cx);
22202                if self.leader_id.is_none() {
22203                    buffer.set_active_selections(
22204                        &self.selections.disjoint_anchors_arc(),
22205                        self.selections.line_mode(),
22206                        self.cursor_shape,
22207                        cx,
22208                    );
22209                }
22210            });
22211
22212            if let Some(position_map) = self.last_position_map.clone() {
22213                EditorElement::mouse_moved(
22214                    self,
22215                    &MouseMoveEvent {
22216                        position: window.mouse_position(),
22217                        pressed_button: None,
22218                        modifiers: window.modifiers(),
22219                    },
22220                    &position_map,
22221                    window,
22222                    cx,
22223                );
22224            }
22225        }
22226    }
22227
22228    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22229        cx.emit(EditorEvent::FocusedIn)
22230    }
22231
22232    fn handle_focus_out(
22233        &mut self,
22234        event: FocusOutEvent,
22235        _window: &mut Window,
22236        cx: &mut Context<Self>,
22237    ) {
22238        if event.blurred != self.focus_handle {
22239            self.last_focused_descendant = Some(event.blurred);
22240        }
22241        self.selection_drag_state = SelectionDragState::None;
22242        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22243    }
22244
22245    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22246        self.blink_manager.update(cx, BlinkManager::disable);
22247        self.buffer
22248            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22249
22250        if let Some(blame) = self.blame.as_ref() {
22251            blame.update(cx, GitBlame::blur)
22252        }
22253        if !self.hover_state.focused(window, cx) {
22254            hide_hover(self, cx);
22255        }
22256        if !self
22257            .context_menu
22258            .borrow()
22259            .as_ref()
22260            .is_some_and(|context_menu| context_menu.focused(window, cx))
22261        {
22262            self.hide_context_menu(window, cx);
22263        }
22264        self.take_active_edit_prediction(cx);
22265        cx.emit(EditorEvent::Blurred);
22266        cx.notify();
22267    }
22268
22269    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22270        let mut pending: String = window
22271            .pending_input_keystrokes()
22272            .into_iter()
22273            .flatten()
22274            .filter_map(|keystroke| keystroke.key_char.clone())
22275            .collect();
22276
22277        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22278            pending = "".to_string();
22279        }
22280
22281        let existing_pending = self
22282            .text_highlights::<PendingInput>(cx)
22283            .map(|(_, ranges)| ranges.to_vec());
22284        if existing_pending.is_none() && pending.is_empty() {
22285            return;
22286        }
22287        let transaction =
22288            self.transact(window, cx, |this, window, cx| {
22289                let selections = this
22290                    .selections
22291                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22292                let edits = selections
22293                    .iter()
22294                    .map(|selection| (selection.end..selection.end, pending.clone()));
22295                this.edit(edits, cx);
22296                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22297                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22298                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22299                    }));
22300                });
22301                if let Some(existing_ranges) = existing_pending {
22302                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22303                    this.edit(edits, cx);
22304                }
22305            });
22306
22307        let snapshot = self.snapshot(window, cx);
22308        let ranges = self
22309            .selections
22310            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22311            .into_iter()
22312            .map(|selection| {
22313                snapshot.buffer_snapshot().anchor_after(selection.end)
22314                    ..snapshot
22315                        .buffer_snapshot()
22316                        .anchor_before(selection.end + pending.len())
22317            })
22318            .collect();
22319
22320        if pending.is_empty() {
22321            self.clear_highlights::<PendingInput>(cx);
22322        } else {
22323            self.highlight_text::<PendingInput>(
22324                ranges,
22325                HighlightStyle {
22326                    underline: Some(UnderlineStyle {
22327                        thickness: px(1.),
22328                        color: None,
22329                        wavy: false,
22330                    }),
22331                    ..Default::default()
22332                },
22333                cx,
22334            );
22335        }
22336
22337        self.ime_transaction = self.ime_transaction.or(transaction);
22338        if let Some(transaction) = self.ime_transaction {
22339            self.buffer.update(cx, |buffer, cx| {
22340                buffer.group_until_transaction(transaction, cx);
22341            });
22342        }
22343
22344        if self.text_highlights::<PendingInput>(cx).is_none() {
22345            self.ime_transaction.take();
22346        }
22347    }
22348
22349    pub fn register_action_renderer(
22350        &mut self,
22351        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22352    ) -> Subscription {
22353        let id = self.next_editor_action_id.post_inc();
22354        self.editor_actions
22355            .borrow_mut()
22356            .insert(id, Box::new(listener));
22357
22358        let editor_actions = self.editor_actions.clone();
22359        Subscription::new(move || {
22360            editor_actions.borrow_mut().remove(&id);
22361        })
22362    }
22363
22364    pub fn register_action<A: Action>(
22365        &mut self,
22366        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22367    ) -> Subscription {
22368        let id = self.next_editor_action_id.post_inc();
22369        let listener = Arc::new(listener);
22370        self.editor_actions.borrow_mut().insert(
22371            id,
22372            Box::new(move |_, window, _| {
22373                let listener = listener.clone();
22374                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22375                    let action = action.downcast_ref().unwrap();
22376                    if phase == DispatchPhase::Bubble {
22377                        listener(action, window, cx)
22378                    }
22379                })
22380            }),
22381        );
22382
22383        let editor_actions = self.editor_actions.clone();
22384        Subscription::new(move || {
22385            editor_actions.borrow_mut().remove(&id);
22386        })
22387    }
22388
22389    pub fn file_header_size(&self) -> u32 {
22390        FILE_HEADER_HEIGHT
22391    }
22392
22393    pub fn restore(
22394        &mut self,
22395        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22396        window: &mut Window,
22397        cx: &mut Context<Self>,
22398    ) {
22399        let workspace = self.workspace();
22400        let project = self.project();
22401        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22402            let mut tasks = Vec::new();
22403            for (buffer_id, changes) in revert_changes {
22404                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22405                    buffer.update(cx, |buffer, cx| {
22406                        buffer.edit(
22407                            changes
22408                                .into_iter()
22409                                .map(|(range, text)| (range, text.to_string())),
22410                            None,
22411                            cx,
22412                        );
22413                    });
22414
22415                    if let Some(project) =
22416                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22417                    {
22418                        project.update(cx, |project, cx| {
22419                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22420                        })
22421                    }
22422                }
22423            }
22424            tasks
22425        });
22426        cx.spawn_in(window, async move |_, cx| {
22427            for (buffer, task) in save_tasks {
22428                let result = task.await;
22429                if result.is_err() {
22430                    let Some(path) = buffer
22431                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22432                        .ok()
22433                    else {
22434                        continue;
22435                    };
22436                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22437                        let Some(task) = cx
22438                            .update_window_entity(workspace, |workspace, window, cx| {
22439                                workspace
22440                                    .open_path_preview(path, None, false, false, false, window, cx)
22441                            })
22442                            .ok()
22443                        else {
22444                            continue;
22445                        };
22446                        task.await.log_err();
22447                    }
22448                }
22449            }
22450        })
22451        .detach();
22452        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22453            selections.refresh()
22454        });
22455    }
22456
22457    pub fn to_pixel_point(
22458        &self,
22459        source: multi_buffer::Anchor,
22460        editor_snapshot: &EditorSnapshot,
22461        window: &mut Window,
22462    ) -> Option<gpui::Point<Pixels>> {
22463        let source_point = source.to_display_point(editor_snapshot);
22464        self.display_to_pixel_point(source_point, editor_snapshot, window)
22465    }
22466
22467    pub fn display_to_pixel_point(
22468        &self,
22469        source: DisplayPoint,
22470        editor_snapshot: &EditorSnapshot,
22471        window: &mut Window,
22472    ) -> Option<gpui::Point<Pixels>> {
22473        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22474        let text_layout_details = self.text_layout_details(window);
22475        let scroll_top = text_layout_details
22476            .scroll_anchor
22477            .scroll_position(editor_snapshot)
22478            .y;
22479
22480        if source.row().as_f64() < scroll_top.floor() {
22481            return None;
22482        }
22483        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22484        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22485        Some(gpui::Point::new(source_x, source_y))
22486    }
22487
22488    pub fn has_visible_completions_menu(&self) -> bool {
22489        !self.edit_prediction_preview_is_active()
22490            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22491                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22492            })
22493    }
22494
22495    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22496        if self.mode.is_minimap() {
22497            return;
22498        }
22499        self.addons
22500            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22501    }
22502
22503    pub fn unregister_addon<T: Addon>(&mut self) {
22504        self.addons.remove(&std::any::TypeId::of::<T>());
22505    }
22506
22507    pub fn addon<T: Addon>(&self) -> Option<&T> {
22508        let type_id = std::any::TypeId::of::<T>();
22509        self.addons
22510            .get(&type_id)
22511            .and_then(|item| item.to_any().downcast_ref::<T>())
22512    }
22513
22514    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22515        let type_id = std::any::TypeId::of::<T>();
22516        self.addons
22517            .get_mut(&type_id)
22518            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22519    }
22520
22521    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22522        let text_layout_details = self.text_layout_details(window);
22523        let style = &text_layout_details.editor_style;
22524        let font_id = window.text_system().resolve_font(&style.text.font());
22525        let font_size = style.text.font_size.to_pixels(window.rem_size());
22526        let line_height = style.text.line_height_in_pixels(window.rem_size());
22527        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22528        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22529
22530        CharacterDimensions {
22531            em_width,
22532            em_advance,
22533            line_height,
22534        }
22535    }
22536
22537    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22538        self.load_diff_task.clone()
22539    }
22540
22541    fn read_metadata_from_db(
22542        &mut self,
22543        item_id: u64,
22544        workspace_id: WorkspaceId,
22545        window: &mut Window,
22546        cx: &mut Context<Editor>,
22547    ) {
22548        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22549            && !self.mode.is_minimap()
22550            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22551        {
22552            let buffer_snapshot = OnceCell::new();
22553
22554            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22555                && !folds.is_empty()
22556            {
22557                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22558                self.fold_ranges(
22559                    folds
22560                        .into_iter()
22561                        .map(|(start, end)| {
22562                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22563                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22564                        })
22565                        .collect(),
22566                    false,
22567                    window,
22568                    cx,
22569                );
22570            }
22571
22572            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22573                && !selections.is_empty()
22574            {
22575                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22576                // skip adding the initial selection to selection history
22577                self.selection_history.mode = SelectionHistoryMode::Skipping;
22578                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22579                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22580                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22581                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22582                    }));
22583                });
22584                self.selection_history.mode = SelectionHistoryMode::Normal;
22585            };
22586        }
22587
22588        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22589    }
22590
22591    fn update_lsp_data(
22592        &mut self,
22593        for_buffer: Option<BufferId>,
22594        window: &mut Window,
22595        cx: &mut Context<'_, Self>,
22596    ) {
22597        self.pull_diagnostics(for_buffer, window, cx);
22598        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22599    }
22600
22601    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22602        if self.ignore_lsp_data() {
22603            return;
22604        }
22605        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22606            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22607        }
22608    }
22609
22610    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22611        if self.ignore_lsp_data() {
22612            return;
22613        }
22614
22615        if !self.registered_buffers.contains_key(&buffer_id)
22616            && let Some(project) = self.project.as_ref()
22617        {
22618            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22619                project.update(cx, |project, cx| {
22620                    self.registered_buffers.insert(
22621                        buffer_id,
22622                        project.register_buffer_with_language_servers(&buffer, cx),
22623                    );
22624                });
22625            } else {
22626                self.registered_buffers.remove(&buffer_id);
22627            }
22628        }
22629    }
22630
22631    fn ignore_lsp_data(&self) -> bool {
22632        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22633        // skip any LSP updates for it.
22634        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22635    }
22636}
22637
22638fn edit_for_markdown_paste<'a>(
22639    buffer: &MultiBufferSnapshot,
22640    range: Range<MultiBufferOffset>,
22641    to_insert: &'a str,
22642    url: Option<url::Url>,
22643) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22644    if url.is_none() {
22645        return (range, Cow::Borrowed(to_insert));
22646    };
22647
22648    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22649
22650    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22651        Cow::Borrowed(to_insert)
22652    } else {
22653        Cow::Owned(format!("[{old_text}]({to_insert})"))
22654    };
22655    (range, new_text)
22656}
22657
22658fn process_completion_for_edit(
22659    completion: &Completion,
22660    intent: CompletionIntent,
22661    buffer: &Entity<Buffer>,
22662    cursor_position: &text::Anchor,
22663    cx: &mut Context<Editor>,
22664) -> CompletionEdit {
22665    let buffer = buffer.read(cx);
22666    let buffer_snapshot = buffer.snapshot();
22667    let (snippet, new_text) = if completion.is_snippet() {
22668        let mut snippet_source = completion.new_text.clone();
22669        // Workaround for typescript language server issues so that methods don't expand within
22670        // strings and functions with type expressions. The previous point is used because the query
22671        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22672        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22673        let previous_point = if previous_point.column > 0 {
22674            cursor_position.to_previous_offset(&buffer_snapshot)
22675        } else {
22676            cursor_position.to_offset(&buffer_snapshot)
22677        };
22678        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22679            && scope.prefers_label_for_snippet_in_completion()
22680            && let Some(label) = completion.label()
22681            && matches!(
22682                completion.kind(),
22683                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22684            )
22685        {
22686            snippet_source = label;
22687        }
22688        match Snippet::parse(&snippet_source).log_err() {
22689            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22690            None => (None, completion.new_text.clone()),
22691        }
22692    } else {
22693        (None, completion.new_text.clone())
22694    };
22695
22696    let mut range_to_replace = {
22697        let replace_range = &completion.replace_range;
22698        if let CompletionSource::Lsp {
22699            insert_range: Some(insert_range),
22700            ..
22701        } = &completion.source
22702        {
22703            debug_assert_eq!(
22704                insert_range.start, replace_range.start,
22705                "insert_range and replace_range should start at the same position"
22706            );
22707            debug_assert!(
22708                insert_range
22709                    .start
22710                    .cmp(cursor_position, &buffer_snapshot)
22711                    .is_le(),
22712                "insert_range should start before or at cursor position"
22713            );
22714            debug_assert!(
22715                replace_range
22716                    .start
22717                    .cmp(cursor_position, &buffer_snapshot)
22718                    .is_le(),
22719                "replace_range should start before or at cursor position"
22720            );
22721
22722            let should_replace = match intent {
22723                CompletionIntent::CompleteWithInsert => false,
22724                CompletionIntent::CompleteWithReplace => true,
22725                CompletionIntent::Complete | CompletionIntent::Compose => {
22726                    let insert_mode =
22727                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22728                            .completions
22729                            .lsp_insert_mode;
22730                    match insert_mode {
22731                        LspInsertMode::Insert => false,
22732                        LspInsertMode::Replace => true,
22733                        LspInsertMode::ReplaceSubsequence => {
22734                            let mut text_to_replace = buffer.chars_for_range(
22735                                buffer.anchor_before(replace_range.start)
22736                                    ..buffer.anchor_after(replace_range.end),
22737                            );
22738                            let mut current_needle = text_to_replace.next();
22739                            for haystack_ch in completion.label.text.chars() {
22740                                if let Some(needle_ch) = current_needle
22741                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22742                                {
22743                                    current_needle = text_to_replace.next();
22744                                }
22745                            }
22746                            current_needle.is_none()
22747                        }
22748                        LspInsertMode::ReplaceSuffix => {
22749                            if replace_range
22750                                .end
22751                                .cmp(cursor_position, &buffer_snapshot)
22752                                .is_gt()
22753                            {
22754                                let range_after_cursor = *cursor_position..replace_range.end;
22755                                let text_after_cursor = buffer
22756                                    .text_for_range(
22757                                        buffer.anchor_before(range_after_cursor.start)
22758                                            ..buffer.anchor_after(range_after_cursor.end),
22759                                    )
22760                                    .collect::<String>()
22761                                    .to_ascii_lowercase();
22762                                completion
22763                                    .label
22764                                    .text
22765                                    .to_ascii_lowercase()
22766                                    .ends_with(&text_after_cursor)
22767                            } else {
22768                                true
22769                            }
22770                        }
22771                    }
22772                }
22773            };
22774
22775            if should_replace {
22776                replace_range.clone()
22777            } else {
22778                insert_range.clone()
22779            }
22780        } else {
22781            replace_range.clone()
22782        }
22783    };
22784
22785    if range_to_replace
22786        .end
22787        .cmp(cursor_position, &buffer_snapshot)
22788        .is_lt()
22789    {
22790        range_to_replace.end = *cursor_position;
22791    }
22792
22793    let replace_range = range_to_replace.to_offset(buffer);
22794    CompletionEdit {
22795        new_text,
22796        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22797        snippet,
22798    }
22799}
22800
22801struct CompletionEdit {
22802    new_text: String,
22803    replace_range: Range<BufferOffset>,
22804    snippet: Option<Snippet>,
22805}
22806
22807fn insert_extra_newline_brackets(
22808    buffer: &MultiBufferSnapshot,
22809    range: Range<MultiBufferOffset>,
22810    language: &language::LanguageScope,
22811) -> bool {
22812    let leading_whitespace_len = buffer
22813        .reversed_chars_at(range.start)
22814        .take_while(|c| c.is_whitespace() && *c != '\n')
22815        .map(|c| c.len_utf8())
22816        .sum::<usize>();
22817    let trailing_whitespace_len = buffer
22818        .chars_at(range.end)
22819        .take_while(|c| c.is_whitespace() && *c != '\n')
22820        .map(|c| c.len_utf8())
22821        .sum::<usize>();
22822    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22823
22824    language.brackets().any(|(pair, enabled)| {
22825        let pair_start = pair.start.trim_end();
22826        let pair_end = pair.end.trim_start();
22827
22828        enabled
22829            && pair.newline
22830            && buffer.contains_str_at(range.end, pair_end)
22831            && buffer.contains_str_at(
22832                range.start.saturating_sub_usize(pair_start.len()),
22833                pair_start,
22834            )
22835    })
22836}
22837
22838fn insert_extra_newline_tree_sitter(
22839    buffer: &MultiBufferSnapshot,
22840    range: Range<MultiBufferOffset>,
22841) -> bool {
22842    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22843        [(buffer, range, _)] => (*buffer, range.clone()),
22844        _ => return false,
22845    };
22846    let pair = {
22847        let mut result: Option<BracketMatch<usize>> = None;
22848
22849        for pair in buffer
22850            .all_bracket_ranges(range.start.0..range.end.0)
22851            .filter(move |pair| {
22852                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22853            })
22854        {
22855            let len = pair.close_range.end - pair.open_range.start;
22856
22857            if let Some(existing) = &result {
22858                let existing_len = existing.close_range.end - existing.open_range.start;
22859                if len > existing_len {
22860                    continue;
22861                }
22862            }
22863
22864            result = Some(pair);
22865        }
22866
22867        result
22868    };
22869    let Some(pair) = pair else {
22870        return false;
22871    };
22872    pair.newline_only
22873        && buffer
22874            .chars_for_range(pair.open_range.end..range.start.0)
22875            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22876            .all(|c| c.is_whitespace() && c != '\n')
22877}
22878
22879fn update_uncommitted_diff_for_buffer(
22880    editor: Entity<Editor>,
22881    project: &Entity<Project>,
22882    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22883    buffer: Entity<MultiBuffer>,
22884    cx: &mut App,
22885) -> Task<()> {
22886    let mut tasks = Vec::new();
22887    project.update(cx, |project, cx| {
22888        for buffer in buffers {
22889            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22890                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22891            }
22892        }
22893    });
22894    cx.spawn(async move |cx| {
22895        let diffs = future::join_all(tasks).await;
22896        if editor
22897            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22898            .unwrap_or(false)
22899        {
22900            return;
22901        }
22902
22903        buffer
22904            .update(cx, |buffer, cx| {
22905                for diff in diffs.into_iter().flatten() {
22906                    buffer.add_diff(diff, cx);
22907                }
22908            })
22909            .ok();
22910    })
22911}
22912
22913fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22914    let tab_size = tab_size.get() as usize;
22915    let mut width = offset;
22916
22917    for ch in text.chars() {
22918        width += if ch == '\t' {
22919            tab_size - (width % tab_size)
22920        } else {
22921            1
22922        };
22923    }
22924
22925    width - offset
22926}
22927
22928#[cfg(test)]
22929mod tests {
22930    use super::*;
22931
22932    #[test]
22933    fn test_string_size_with_expanded_tabs() {
22934        let nz = |val| NonZeroU32::new(val).unwrap();
22935        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22936        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22937        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22938        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22939        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22940        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22941        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22942        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22943    }
22944}
22945
22946/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22947struct WordBreakingTokenizer<'a> {
22948    input: &'a str,
22949}
22950
22951impl<'a> WordBreakingTokenizer<'a> {
22952    fn new(input: &'a str) -> Self {
22953        Self { input }
22954    }
22955}
22956
22957fn is_char_ideographic(ch: char) -> bool {
22958    use unicode_script::Script::*;
22959    use unicode_script::UnicodeScript;
22960    matches!(ch.script(), Han | Tangut | Yi)
22961}
22962
22963fn is_grapheme_ideographic(text: &str) -> bool {
22964    text.chars().any(is_char_ideographic)
22965}
22966
22967fn is_grapheme_whitespace(text: &str) -> bool {
22968    text.chars().any(|x| x.is_whitespace())
22969}
22970
22971fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22972    text.chars()
22973        .next()
22974        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22975}
22976
22977#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22978enum WordBreakToken<'a> {
22979    Word { token: &'a str, grapheme_len: usize },
22980    InlineWhitespace { token: &'a str, grapheme_len: usize },
22981    Newline,
22982}
22983
22984impl<'a> Iterator for WordBreakingTokenizer<'a> {
22985    /// Yields a span, the count of graphemes in the token, and whether it was
22986    /// whitespace. Note that it also breaks at word boundaries.
22987    type Item = WordBreakToken<'a>;
22988
22989    fn next(&mut self) -> Option<Self::Item> {
22990        use unicode_segmentation::UnicodeSegmentation;
22991        if self.input.is_empty() {
22992            return None;
22993        }
22994
22995        let mut iter = self.input.graphemes(true).peekable();
22996        let mut offset = 0;
22997        let mut grapheme_len = 0;
22998        if let Some(first_grapheme) = iter.next() {
22999            let is_newline = first_grapheme == "\n";
23000            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23001            offset += first_grapheme.len();
23002            grapheme_len += 1;
23003            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23004                if let Some(grapheme) = iter.peek().copied()
23005                    && should_stay_with_preceding_ideograph(grapheme)
23006                {
23007                    offset += grapheme.len();
23008                    grapheme_len += 1;
23009                }
23010            } else {
23011                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23012                let mut next_word_bound = words.peek().copied();
23013                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23014                    next_word_bound = words.next();
23015                }
23016                while let Some(grapheme) = iter.peek().copied() {
23017                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23018                        break;
23019                    };
23020                    if is_grapheme_whitespace(grapheme) != is_whitespace
23021                        || (grapheme == "\n") != is_newline
23022                    {
23023                        break;
23024                    };
23025                    offset += grapheme.len();
23026                    grapheme_len += 1;
23027                    iter.next();
23028                }
23029            }
23030            let token = &self.input[..offset];
23031            self.input = &self.input[offset..];
23032            if token == "\n" {
23033                Some(WordBreakToken::Newline)
23034            } else if is_whitespace {
23035                Some(WordBreakToken::InlineWhitespace {
23036                    token,
23037                    grapheme_len,
23038                })
23039            } else {
23040                Some(WordBreakToken::Word {
23041                    token,
23042                    grapheme_len,
23043                })
23044            }
23045        } else {
23046            None
23047        }
23048    }
23049}
23050
23051#[test]
23052fn test_word_breaking_tokenizer() {
23053    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23054        ("", &[]),
23055        ("  ", &[whitespace("  ", 2)]),
23056        ("Ʒ", &[word("Ʒ", 1)]),
23057        ("Ǽ", &[word("Ǽ", 1)]),
23058        ("", &[word("", 1)]),
23059        ("⋑⋑", &[word("⋑⋑", 2)]),
23060        (
23061            "原理,进而",
23062            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23063        ),
23064        (
23065            "hello world",
23066            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23067        ),
23068        (
23069            "hello, world",
23070            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23071        ),
23072        (
23073            "  hello world",
23074            &[
23075                whitespace("  ", 2),
23076                word("hello", 5),
23077                whitespace(" ", 1),
23078                word("world", 5),
23079            ],
23080        ),
23081        (
23082            "这是什么 \n 钢笔",
23083            &[
23084                word("", 1),
23085                word("", 1),
23086                word("", 1),
23087                word("", 1),
23088                whitespace(" ", 1),
23089                newline(),
23090                whitespace(" ", 1),
23091                word("", 1),
23092                word("", 1),
23093            ],
23094        ),
23095        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23096    ];
23097
23098    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23099        WordBreakToken::Word {
23100            token,
23101            grapheme_len,
23102        }
23103    }
23104
23105    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23106        WordBreakToken::InlineWhitespace {
23107            token,
23108            grapheme_len,
23109        }
23110    }
23111
23112    fn newline() -> WordBreakToken<'static> {
23113        WordBreakToken::Newline
23114    }
23115
23116    for (input, result) in tests {
23117        assert_eq!(
23118            WordBreakingTokenizer::new(input)
23119                .collect::<Vec<_>>()
23120                .as_slice(),
23121            *result,
23122        );
23123    }
23124}
23125
23126fn wrap_with_prefix(
23127    first_line_prefix: String,
23128    subsequent_lines_prefix: String,
23129    unwrapped_text: String,
23130    wrap_column: usize,
23131    tab_size: NonZeroU32,
23132    preserve_existing_whitespace: bool,
23133) -> String {
23134    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23135    let subsequent_lines_prefix_len =
23136        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23137    let mut wrapped_text = String::new();
23138    let mut current_line = first_line_prefix;
23139    let mut is_first_line = true;
23140
23141    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23142    let mut current_line_len = first_line_prefix_len;
23143    let mut in_whitespace = false;
23144    for token in tokenizer {
23145        let have_preceding_whitespace = in_whitespace;
23146        match token {
23147            WordBreakToken::Word {
23148                token,
23149                grapheme_len,
23150            } => {
23151                in_whitespace = false;
23152                let current_prefix_len = if is_first_line {
23153                    first_line_prefix_len
23154                } else {
23155                    subsequent_lines_prefix_len
23156                };
23157                if current_line_len + grapheme_len > wrap_column
23158                    && current_line_len != current_prefix_len
23159                {
23160                    wrapped_text.push_str(current_line.trim_end());
23161                    wrapped_text.push('\n');
23162                    is_first_line = false;
23163                    current_line = subsequent_lines_prefix.clone();
23164                    current_line_len = subsequent_lines_prefix_len;
23165                }
23166                current_line.push_str(token);
23167                current_line_len += grapheme_len;
23168            }
23169            WordBreakToken::InlineWhitespace {
23170                mut token,
23171                mut grapheme_len,
23172            } => {
23173                in_whitespace = true;
23174                if have_preceding_whitespace && !preserve_existing_whitespace {
23175                    continue;
23176                }
23177                if !preserve_existing_whitespace {
23178                    // Keep a single whitespace grapheme as-is
23179                    if let Some(first) =
23180                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23181                    {
23182                        token = first;
23183                    } else {
23184                        token = " ";
23185                    }
23186                    grapheme_len = 1;
23187                }
23188                let current_prefix_len = if is_first_line {
23189                    first_line_prefix_len
23190                } else {
23191                    subsequent_lines_prefix_len
23192                };
23193                if current_line_len + grapheme_len > wrap_column {
23194                    wrapped_text.push_str(current_line.trim_end());
23195                    wrapped_text.push('\n');
23196                    is_first_line = false;
23197                    current_line = subsequent_lines_prefix.clone();
23198                    current_line_len = subsequent_lines_prefix_len;
23199                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23200                    current_line.push_str(token);
23201                    current_line_len += grapheme_len;
23202                }
23203            }
23204            WordBreakToken::Newline => {
23205                in_whitespace = true;
23206                let current_prefix_len = if is_first_line {
23207                    first_line_prefix_len
23208                } else {
23209                    subsequent_lines_prefix_len
23210                };
23211                if preserve_existing_whitespace {
23212                    wrapped_text.push_str(current_line.trim_end());
23213                    wrapped_text.push('\n');
23214                    is_first_line = false;
23215                    current_line = subsequent_lines_prefix.clone();
23216                    current_line_len = subsequent_lines_prefix_len;
23217                } else if have_preceding_whitespace {
23218                    continue;
23219                } else if current_line_len + 1 > wrap_column
23220                    && current_line_len != current_prefix_len
23221                {
23222                    wrapped_text.push_str(current_line.trim_end());
23223                    wrapped_text.push('\n');
23224                    is_first_line = false;
23225                    current_line = subsequent_lines_prefix.clone();
23226                    current_line_len = subsequent_lines_prefix_len;
23227                } else if current_line_len != current_prefix_len {
23228                    current_line.push(' ');
23229                    current_line_len += 1;
23230                }
23231            }
23232        }
23233    }
23234
23235    if !current_line.is_empty() {
23236        wrapped_text.push_str(&current_line);
23237    }
23238    wrapped_text
23239}
23240
23241#[test]
23242fn test_wrap_with_prefix() {
23243    assert_eq!(
23244        wrap_with_prefix(
23245            "# ".to_string(),
23246            "# ".to_string(),
23247            "abcdefg".to_string(),
23248            4,
23249            NonZeroU32::new(4).unwrap(),
23250            false,
23251        ),
23252        "# abcdefg"
23253    );
23254    assert_eq!(
23255        wrap_with_prefix(
23256            "".to_string(),
23257            "".to_string(),
23258            "\thello world".to_string(),
23259            8,
23260            NonZeroU32::new(4).unwrap(),
23261            false,
23262        ),
23263        "hello\nworld"
23264    );
23265    assert_eq!(
23266        wrap_with_prefix(
23267            "// ".to_string(),
23268            "// ".to_string(),
23269            "xx \nyy zz aa bb cc".to_string(),
23270            12,
23271            NonZeroU32::new(4).unwrap(),
23272            false,
23273        ),
23274        "// xx yy zz\n// aa bb cc"
23275    );
23276    assert_eq!(
23277        wrap_with_prefix(
23278            String::new(),
23279            String::new(),
23280            "这是什么 \n 钢笔".to_string(),
23281            3,
23282            NonZeroU32::new(4).unwrap(),
23283            false,
23284        ),
23285        "这是什\n么 钢\n"
23286    );
23287    assert_eq!(
23288        wrap_with_prefix(
23289            String::new(),
23290            String::new(),
23291            format!("foo{}bar", '\u{2009}'), // thin space
23292            80,
23293            NonZeroU32::new(4).unwrap(),
23294            false,
23295        ),
23296        format!("foo{}bar", '\u{2009}')
23297    );
23298}
23299
23300pub trait CollaborationHub {
23301    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23302    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23303    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23304}
23305
23306impl CollaborationHub for Entity<Project> {
23307    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23308        self.read(cx).collaborators()
23309    }
23310
23311    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23312        self.read(cx).user_store().read(cx).participant_indices()
23313    }
23314
23315    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23316        let this = self.read(cx);
23317        let user_ids = this.collaborators().values().map(|c| c.user_id);
23318        this.user_store().read(cx).participant_names(user_ids, cx)
23319    }
23320}
23321
23322pub trait SemanticsProvider {
23323    fn hover(
23324        &self,
23325        buffer: &Entity<Buffer>,
23326        position: text::Anchor,
23327        cx: &mut App,
23328    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23329
23330    fn inline_values(
23331        &self,
23332        buffer_handle: Entity<Buffer>,
23333        range: Range<text::Anchor>,
23334        cx: &mut App,
23335    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23336
23337    fn applicable_inlay_chunks(
23338        &self,
23339        buffer: &Entity<Buffer>,
23340        ranges: &[Range<text::Anchor>],
23341        cx: &mut App,
23342    ) -> Vec<Range<BufferRow>>;
23343
23344    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23345
23346    fn inlay_hints(
23347        &self,
23348        invalidate: InvalidationStrategy,
23349        buffer: Entity<Buffer>,
23350        ranges: Vec<Range<text::Anchor>>,
23351        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23352        cx: &mut App,
23353    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23354
23355    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23356
23357    fn document_highlights(
23358        &self,
23359        buffer: &Entity<Buffer>,
23360        position: text::Anchor,
23361        cx: &mut App,
23362    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23363
23364    fn definitions(
23365        &self,
23366        buffer: &Entity<Buffer>,
23367        position: text::Anchor,
23368        kind: GotoDefinitionKind,
23369        cx: &mut App,
23370    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23371
23372    fn range_for_rename(
23373        &self,
23374        buffer: &Entity<Buffer>,
23375        position: text::Anchor,
23376        cx: &mut App,
23377    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23378
23379    fn perform_rename(
23380        &self,
23381        buffer: &Entity<Buffer>,
23382        position: text::Anchor,
23383        new_name: String,
23384        cx: &mut App,
23385    ) -> Option<Task<Result<ProjectTransaction>>>;
23386}
23387
23388pub trait CompletionProvider {
23389    fn completions(
23390        &self,
23391        excerpt_id: ExcerptId,
23392        buffer: &Entity<Buffer>,
23393        buffer_position: text::Anchor,
23394        trigger: CompletionContext,
23395        window: &mut Window,
23396        cx: &mut Context<Editor>,
23397    ) -> Task<Result<Vec<CompletionResponse>>>;
23398
23399    fn resolve_completions(
23400        &self,
23401        _buffer: Entity<Buffer>,
23402        _completion_indices: Vec<usize>,
23403        _completions: Rc<RefCell<Box<[Completion]>>>,
23404        _cx: &mut Context<Editor>,
23405    ) -> Task<Result<bool>> {
23406        Task::ready(Ok(false))
23407    }
23408
23409    fn apply_additional_edits_for_completion(
23410        &self,
23411        _buffer: Entity<Buffer>,
23412        _completions: Rc<RefCell<Box<[Completion]>>>,
23413        _completion_index: usize,
23414        _push_to_history: bool,
23415        _cx: &mut Context<Editor>,
23416    ) -> Task<Result<Option<language::Transaction>>> {
23417        Task::ready(Ok(None))
23418    }
23419
23420    fn is_completion_trigger(
23421        &self,
23422        buffer: &Entity<Buffer>,
23423        position: language::Anchor,
23424        text: &str,
23425        trigger_in_words: bool,
23426        menu_is_open: bool,
23427        cx: &mut Context<Editor>,
23428    ) -> bool;
23429
23430    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23431
23432    fn sort_completions(&self) -> bool {
23433        true
23434    }
23435
23436    fn filter_completions(&self) -> bool {
23437        true
23438    }
23439
23440    fn show_snippets(&self) -> bool {
23441        false
23442    }
23443}
23444
23445pub trait CodeActionProvider {
23446    fn id(&self) -> Arc<str>;
23447
23448    fn code_actions(
23449        &self,
23450        buffer: &Entity<Buffer>,
23451        range: Range<text::Anchor>,
23452        window: &mut Window,
23453        cx: &mut App,
23454    ) -> Task<Result<Vec<CodeAction>>>;
23455
23456    fn apply_code_action(
23457        &self,
23458        buffer_handle: Entity<Buffer>,
23459        action: CodeAction,
23460        excerpt_id: ExcerptId,
23461        push_to_history: bool,
23462        window: &mut Window,
23463        cx: &mut App,
23464    ) -> Task<Result<ProjectTransaction>>;
23465}
23466
23467impl CodeActionProvider for Entity<Project> {
23468    fn id(&self) -> Arc<str> {
23469        "project".into()
23470    }
23471
23472    fn code_actions(
23473        &self,
23474        buffer: &Entity<Buffer>,
23475        range: Range<text::Anchor>,
23476        _window: &mut Window,
23477        cx: &mut App,
23478    ) -> Task<Result<Vec<CodeAction>>> {
23479        self.update(cx, |project, cx| {
23480            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23481            let code_actions = project.code_actions(buffer, range, None, cx);
23482            cx.background_spawn(async move {
23483                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23484                Ok(code_lens_actions
23485                    .context("code lens fetch")?
23486                    .into_iter()
23487                    .flatten()
23488                    .chain(
23489                        code_actions
23490                            .context("code action fetch")?
23491                            .into_iter()
23492                            .flatten(),
23493                    )
23494                    .collect())
23495            })
23496        })
23497    }
23498
23499    fn apply_code_action(
23500        &self,
23501        buffer_handle: Entity<Buffer>,
23502        action: CodeAction,
23503        _excerpt_id: ExcerptId,
23504        push_to_history: bool,
23505        _window: &mut Window,
23506        cx: &mut App,
23507    ) -> Task<Result<ProjectTransaction>> {
23508        self.update(cx, |project, cx| {
23509            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23510        })
23511    }
23512}
23513
23514fn snippet_completions(
23515    project: &Project,
23516    buffer: &Entity<Buffer>,
23517    buffer_anchor: text::Anchor,
23518    classifier: CharClassifier,
23519    cx: &mut App,
23520) -> Task<Result<CompletionResponse>> {
23521    let languages = buffer.read(cx).languages_at(buffer_anchor);
23522    let snippet_store = project.snippets().read(cx);
23523
23524    let scopes: Vec<_> = languages
23525        .iter()
23526        .filter_map(|language| {
23527            let language_name = language.lsp_id();
23528            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23529
23530            if snippets.is_empty() {
23531                None
23532            } else {
23533                Some((language.default_scope(), snippets))
23534            }
23535        })
23536        .collect();
23537
23538    if scopes.is_empty() {
23539        return Task::ready(Ok(CompletionResponse {
23540            completions: vec![],
23541            display_options: CompletionDisplayOptions::default(),
23542            is_incomplete: false,
23543        }));
23544    }
23545
23546    let snapshot = buffer.read(cx).text_snapshot();
23547    let executor = cx.background_executor().clone();
23548
23549    cx.background_spawn(async move {
23550        let is_word_char = |c| classifier.is_word(c);
23551
23552        let mut is_incomplete = false;
23553        let mut completions: Vec<Completion> = Vec::new();
23554
23555        const MAX_PREFIX_LEN: usize = 128;
23556        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23557        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23558        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23559
23560        let max_buffer_window: String = snapshot
23561            .text_for_range(window_start..buffer_offset)
23562            .collect();
23563
23564        if max_buffer_window.is_empty() {
23565            return Ok(CompletionResponse {
23566                completions: vec![],
23567                display_options: CompletionDisplayOptions::default(),
23568                is_incomplete: true,
23569            });
23570        }
23571
23572        for (_scope, snippets) in scopes.into_iter() {
23573            // Sort snippets by word count to match longer snippet prefixes first.
23574            let mut sorted_snippet_candidates = snippets
23575                .iter()
23576                .enumerate()
23577                .flat_map(|(snippet_ix, snippet)| {
23578                    snippet
23579                        .prefix
23580                        .iter()
23581                        .enumerate()
23582                        .map(move |(prefix_ix, prefix)| {
23583                            let word_count =
23584                                snippet_candidate_suffixes(prefix, is_word_char).count();
23585                            ((snippet_ix, prefix_ix), prefix, word_count)
23586                        })
23587                })
23588                .collect_vec();
23589            sorted_snippet_candidates
23590                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23591
23592            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23593
23594            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23595                .take(
23596                    sorted_snippet_candidates
23597                        .first()
23598                        .map(|(_, _, word_count)| *word_count)
23599                        .unwrap_or_default(),
23600                )
23601                .collect_vec();
23602
23603            const MAX_RESULTS: usize = 100;
23604            // Each match also remembers how many characters from the buffer it consumed
23605            let mut matches: Vec<(StringMatch, usize)> = vec![];
23606
23607            let mut snippet_list_cutoff_index = 0;
23608            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23609                let word_count = buffer_index + 1;
23610                // Increase `snippet_list_cutoff_index` until we have all of the
23611                // snippets with sufficiently many words.
23612                while sorted_snippet_candidates
23613                    .get(snippet_list_cutoff_index)
23614                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23615                        *snippet_word_count >= word_count
23616                    })
23617                {
23618                    snippet_list_cutoff_index += 1;
23619                }
23620
23621                // Take only the candidates with at least `word_count` many words
23622                let snippet_candidates_at_word_len =
23623                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23624
23625                let candidates = snippet_candidates_at_word_len
23626                    .iter()
23627                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23628                    .enumerate() // index in `sorted_snippet_candidates`
23629                    // First char must match
23630                    .filter(|(_ix, prefix)| {
23631                        itertools::equal(
23632                            prefix
23633                                .chars()
23634                                .next()
23635                                .into_iter()
23636                                .flat_map(|c| c.to_lowercase()),
23637                            buffer_window
23638                                .chars()
23639                                .next()
23640                                .into_iter()
23641                                .flat_map(|c| c.to_lowercase()),
23642                        )
23643                    })
23644                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23645                    .collect::<Vec<StringMatchCandidate>>();
23646
23647                matches.extend(
23648                    fuzzy::match_strings(
23649                        &candidates,
23650                        &buffer_window,
23651                        buffer_window.chars().any(|c| c.is_uppercase()),
23652                        true,
23653                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23654                        &Default::default(),
23655                        executor.clone(),
23656                    )
23657                    .await
23658                    .into_iter()
23659                    .map(|string_match| (string_match, buffer_window.len())),
23660                );
23661
23662                if matches.len() >= MAX_RESULTS {
23663                    break;
23664                }
23665            }
23666
23667            let to_lsp = |point: &text::Anchor| {
23668                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23669                point_to_lsp(end)
23670            };
23671            let lsp_end = to_lsp(&buffer_anchor);
23672
23673            if matches.len() >= MAX_RESULTS {
23674                is_incomplete = true;
23675            }
23676
23677            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23678                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23679                    sorted_snippet_candidates[string_match.candidate_id];
23680                let snippet = &snippets[snippet_index];
23681                let start = buffer_offset - buffer_window_len;
23682                let start = snapshot.anchor_before(start);
23683                let range = start..buffer_anchor;
23684                let lsp_start = to_lsp(&start);
23685                let lsp_range = lsp::Range {
23686                    start: lsp_start,
23687                    end: lsp_end,
23688                };
23689                Completion {
23690                    replace_range: range,
23691                    new_text: snippet.body.clone(),
23692                    source: CompletionSource::Lsp {
23693                        insert_range: None,
23694                        server_id: LanguageServerId(usize::MAX),
23695                        resolved: true,
23696                        lsp_completion: Box::new(lsp::CompletionItem {
23697                            label: snippet.prefix.first().unwrap().clone(),
23698                            kind: Some(CompletionItemKind::SNIPPET),
23699                            label_details: snippet.description.as_ref().map(|description| {
23700                                lsp::CompletionItemLabelDetails {
23701                                    detail: Some(description.clone()),
23702                                    description: None,
23703                                }
23704                            }),
23705                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23706                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23707                                lsp::InsertReplaceEdit {
23708                                    new_text: snippet.body.clone(),
23709                                    insert: lsp_range,
23710                                    replace: lsp_range,
23711                                },
23712                            )),
23713                            filter_text: Some(snippet.body.clone()),
23714                            sort_text: Some(char::MAX.to_string()),
23715                            ..lsp::CompletionItem::default()
23716                        }),
23717                        lsp_defaults: None,
23718                    },
23719                    label: CodeLabel {
23720                        text: matching_prefix.clone(),
23721                        runs: Vec::new(),
23722                        filter_range: 0..matching_prefix.len(),
23723                    },
23724                    icon_path: None,
23725                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23726                        single_line: snippet.name.clone().into(),
23727                        plain_text: snippet
23728                            .description
23729                            .clone()
23730                            .map(|description| description.into()),
23731                    }),
23732                    insert_text_mode: None,
23733                    confirm: None,
23734                    match_start: Some(start),
23735                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23736                }
23737            }));
23738        }
23739
23740        Ok(CompletionResponse {
23741            completions,
23742            display_options: CompletionDisplayOptions::default(),
23743            is_incomplete,
23744        })
23745    })
23746}
23747
23748impl CompletionProvider for Entity<Project> {
23749    fn completions(
23750        &self,
23751        _excerpt_id: ExcerptId,
23752        buffer: &Entity<Buffer>,
23753        buffer_position: text::Anchor,
23754        options: CompletionContext,
23755        _window: &mut Window,
23756        cx: &mut Context<Editor>,
23757    ) -> Task<Result<Vec<CompletionResponse>>> {
23758        self.update(cx, |project, cx| {
23759            let task = project.completions(buffer, buffer_position, options, cx);
23760            cx.background_spawn(task)
23761        })
23762    }
23763
23764    fn resolve_completions(
23765        &self,
23766        buffer: Entity<Buffer>,
23767        completion_indices: Vec<usize>,
23768        completions: Rc<RefCell<Box<[Completion]>>>,
23769        cx: &mut Context<Editor>,
23770    ) -> Task<Result<bool>> {
23771        self.update(cx, |project, cx| {
23772            project.lsp_store().update(cx, |lsp_store, cx| {
23773                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23774            })
23775        })
23776    }
23777
23778    fn apply_additional_edits_for_completion(
23779        &self,
23780        buffer: Entity<Buffer>,
23781        completions: Rc<RefCell<Box<[Completion]>>>,
23782        completion_index: usize,
23783        push_to_history: bool,
23784        cx: &mut Context<Editor>,
23785    ) -> Task<Result<Option<language::Transaction>>> {
23786        self.update(cx, |project, cx| {
23787            project.lsp_store().update(cx, |lsp_store, cx| {
23788                lsp_store.apply_additional_edits_for_completion(
23789                    buffer,
23790                    completions,
23791                    completion_index,
23792                    push_to_history,
23793                    cx,
23794                )
23795            })
23796        })
23797    }
23798
23799    fn is_completion_trigger(
23800        &self,
23801        buffer: &Entity<Buffer>,
23802        position: language::Anchor,
23803        text: &str,
23804        trigger_in_words: bool,
23805        menu_is_open: bool,
23806        cx: &mut Context<Editor>,
23807    ) -> bool {
23808        let mut chars = text.chars();
23809        let char = if let Some(char) = chars.next() {
23810            char
23811        } else {
23812            return false;
23813        };
23814        if chars.next().is_some() {
23815            return false;
23816        }
23817
23818        let buffer = buffer.read(cx);
23819        let snapshot = buffer.snapshot();
23820        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23821            return false;
23822        }
23823        let classifier = snapshot
23824            .char_classifier_at(position)
23825            .scope_context(Some(CharScopeContext::Completion));
23826        if trigger_in_words && classifier.is_word(char) {
23827            return true;
23828        }
23829
23830        buffer.completion_triggers().contains(text)
23831    }
23832
23833    fn show_snippets(&self) -> bool {
23834        true
23835    }
23836}
23837
23838impl SemanticsProvider for Entity<Project> {
23839    fn hover(
23840        &self,
23841        buffer: &Entity<Buffer>,
23842        position: text::Anchor,
23843        cx: &mut App,
23844    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23845        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23846    }
23847
23848    fn document_highlights(
23849        &self,
23850        buffer: &Entity<Buffer>,
23851        position: text::Anchor,
23852        cx: &mut App,
23853    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23854        Some(self.update(cx, |project, cx| {
23855            project.document_highlights(buffer, position, cx)
23856        }))
23857    }
23858
23859    fn definitions(
23860        &self,
23861        buffer: &Entity<Buffer>,
23862        position: text::Anchor,
23863        kind: GotoDefinitionKind,
23864        cx: &mut App,
23865    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23866        Some(self.update(cx, |project, cx| match kind {
23867            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23868            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23869            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23870            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23871        }))
23872    }
23873
23874    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23875        self.update(cx, |project, cx| {
23876            if project
23877                .active_debug_session(cx)
23878                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23879            {
23880                return true;
23881            }
23882
23883            buffer.update(cx, |buffer, cx| {
23884                project.any_language_server_supports_inlay_hints(buffer, cx)
23885            })
23886        })
23887    }
23888
23889    fn inline_values(
23890        &self,
23891        buffer_handle: Entity<Buffer>,
23892        range: Range<text::Anchor>,
23893        cx: &mut App,
23894    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23895        self.update(cx, |project, cx| {
23896            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23897
23898            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23899        })
23900    }
23901
23902    fn applicable_inlay_chunks(
23903        &self,
23904        buffer: &Entity<Buffer>,
23905        ranges: &[Range<text::Anchor>],
23906        cx: &mut App,
23907    ) -> Vec<Range<BufferRow>> {
23908        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23909            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23910        })
23911    }
23912
23913    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23914        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23915            lsp_store.invalidate_inlay_hints(for_buffers)
23916        });
23917    }
23918
23919    fn inlay_hints(
23920        &self,
23921        invalidate: InvalidationStrategy,
23922        buffer: Entity<Buffer>,
23923        ranges: Vec<Range<text::Anchor>>,
23924        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23925        cx: &mut App,
23926    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23927        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23928            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23929        }))
23930    }
23931
23932    fn range_for_rename(
23933        &self,
23934        buffer: &Entity<Buffer>,
23935        position: text::Anchor,
23936        cx: &mut App,
23937    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23938        Some(self.update(cx, |project, cx| {
23939            let buffer = buffer.clone();
23940            let task = project.prepare_rename(buffer.clone(), position, cx);
23941            cx.spawn(async move |_, cx| {
23942                Ok(match task.await? {
23943                    PrepareRenameResponse::Success(range) => Some(range),
23944                    PrepareRenameResponse::InvalidPosition => None,
23945                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23946                        // Fallback on using TreeSitter info to determine identifier range
23947                        buffer.read_with(cx, |buffer, _| {
23948                            let snapshot = buffer.snapshot();
23949                            let (range, kind) = snapshot.surrounding_word(position, None);
23950                            if kind != Some(CharKind::Word) {
23951                                return None;
23952                            }
23953                            Some(
23954                                snapshot.anchor_before(range.start)
23955                                    ..snapshot.anchor_after(range.end),
23956                            )
23957                        })?
23958                    }
23959                })
23960            })
23961        }))
23962    }
23963
23964    fn perform_rename(
23965        &self,
23966        buffer: &Entity<Buffer>,
23967        position: text::Anchor,
23968        new_name: String,
23969        cx: &mut App,
23970    ) -> Option<Task<Result<ProjectTransaction>>> {
23971        Some(self.update(cx, |project, cx| {
23972            project.perform_rename(buffer.clone(), position, new_name, cx)
23973        }))
23974    }
23975}
23976
23977fn consume_contiguous_rows(
23978    contiguous_row_selections: &mut Vec<Selection<Point>>,
23979    selection: &Selection<Point>,
23980    display_map: &DisplaySnapshot,
23981    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23982) -> (MultiBufferRow, MultiBufferRow) {
23983    contiguous_row_selections.push(selection.clone());
23984    let start_row = starting_row(selection, display_map);
23985    let mut end_row = ending_row(selection, display_map);
23986
23987    while let Some(next_selection) = selections.peek() {
23988        if next_selection.start.row <= end_row.0 {
23989            end_row = ending_row(next_selection, display_map);
23990            contiguous_row_selections.push(selections.next().unwrap().clone());
23991        } else {
23992            break;
23993        }
23994    }
23995    (start_row, end_row)
23996}
23997
23998fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23999    if selection.start.column > 0 {
24000        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24001    } else {
24002        MultiBufferRow(selection.start.row)
24003    }
24004}
24005
24006fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24007    if next_selection.end.column > 0 || next_selection.is_empty() {
24008        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24009    } else {
24010        MultiBufferRow(next_selection.end.row)
24011    }
24012}
24013
24014impl EditorSnapshot {
24015    pub fn remote_selections_in_range<'a>(
24016        &'a self,
24017        range: &'a Range<Anchor>,
24018        collaboration_hub: &dyn CollaborationHub,
24019        cx: &'a App,
24020    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24021        let participant_names = collaboration_hub.user_names(cx);
24022        let participant_indices = collaboration_hub.user_participant_indices(cx);
24023        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24024        let collaborators_by_replica_id = collaborators_by_peer_id
24025            .values()
24026            .map(|collaborator| (collaborator.replica_id, collaborator))
24027            .collect::<HashMap<_, _>>();
24028        self.buffer_snapshot()
24029            .selections_in_range(range, false)
24030            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24031                if replica_id == ReplicaId::AGENT {
24032                    Some(RemoteSelection {
24033                        replica_id,
24034                        selection,
24035                        cursor_shape,
24036                        line_mode,
24037                        collaborator_id: CollaboratorId::Agent,
24038                        user_name: Some("Agent".into()),
24039                        color: cx.theme().players().agent(),
24040                    })
24041                } else {
24042                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24043                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24044                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24045                    Some(RemoteSelection {
24046                        replica_id,
24047                        selection,
24048                        cursor_shape,
24049                        line_mode,
24050                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24051                        user_name,
24052                        color: if let Some(index) = participant_index {
24053                            cx.theme().players().color_for_participant(index.0)
24054                        } else {
24055                            cx.theme().players().absent()
24056                        },
24057                    })
24058                }
24059            })
24060    }
24061
24062    pub fn hunks_for_ranges(
24063        &self,
24064        ranges: impl IntoIterator<Item = Range<Point>>,
24065    ) -> Vec<MultiBufferDiffHunk> {
24066        let mut hunks = Vec::new();
24067        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24068            HashMap::default();
24069        for query_range in ranges {
24070            let query_rows =
24071                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24072            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24073                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24074            ) {
24075                // Include deleted hunks that are adjacent to the query range, because
24076                // otherwise they would be missed.
24077                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24078                if hunk.status().is_deleted() {
24079                    intersects_range |= hunk.row_range.start == query_rows.end;
24080                    intersects_range |= hunk.row_range.end == query_rows.start;
24081                }
24082                if intersects_range {
24083                    if !processed_buffer_rows
24084                        .entry(hunk.buffer_id)
24085                        .or_default()
24086                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24087                    {
24088                        continue;
24089                    }
24090                    hunks.push(hunk);
24091                }
24092            }
24093        }
24094
24095        hunks
24096    }
24097
24098    fn display_diff_hunks_for_rows<'a>(
24099        &'a self,
24100        display_rows: Range<DisplayRow>,
24101        folded_buffers: &'a HashSet<BufferId>,
24102    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24103        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24104        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24105
24106        self.buffer_snapshot()
24107            .diff_hunks_in_range(buffer_start..buffer_end)
24108            .filter_map(|hunk| {
24109                if folded_buffers.contains(&hunk.buffer_id) {
24110                    return None;
24111                }
24112
24113                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24114                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24115
24116                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24117                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24118
24119                let display_hunk = if hunk_display_start.column() != 0 {
24120                    DisplayDiffHunk::Folded {
24121                        display_row: hunk_display_start.row(),
24122                    }
24123                } else {
24124                    let mut end_row = hunk_display_end.row();
24125                    if hunk_display_end.column() > 0 {
24126                        end_row.0 += 1;
24127                    }
24128                    let is_created_file = hunk.is_created_file();
24129                    DisplayDiffHunk::Unfolded {
24130                        status: hunk.status(),
24131                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24132                            ..hunk.diff_base_byte_range.end.0,
24133                        display_row_range: hunk_display_start.row()..end_row,
24134                        multi_buffer_range: Anchor::range_in_buffer(
24135                            hunk.excerpt_id,
24136                            hunk.buffer_range,
24137                        ),
24138                        is_created_file,
24139                    }
24140                };
24141
24142                Some(display_hunk)
24143            })
24144    }
24145
24146    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24147        self.display_snapshot
24148            .buffer_snapshot()
24149            .language_at(position)
24150    }
24151
24152    pub fn is_focused(&self) -> bool {
24153        self.is_focused
24154    }
24155
24156    pub fn placeholder_text(&self) -> Option<String> {
24157        self.placeholder_display_snapshot
24158            .as_ref()
24159            .map(|display_map| display_map.text())
24160    }
24161
24162    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24163        self.scroll_anchor.scroll_position(&self.display_snapshot)
24164    }
24165
24166    fn gutter_dimensions(
24167        &self,
24168        font_id: FontId,
24169        font_size: Pixels,
24170        max_line_number_width: Pixels,
24171        cx: &App,
24172    ) -> Option<GutterDimensions> {
24173        if !self.show_gutter {
24174            return None;
24175        }
24176
24177        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24178        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24179
24180        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24181            matches!(
24182                ProjectSettings::get_global(cx).git.git_gutter,
24183                GitGutterSetting::TrackedFiles
24184            )
24185        });
24186        let gutter_settings = EditorSettings::get_global(cx).gutter;
24187        let show_line_numbers = self
24188            .show_line_numbers
24189            .unwrap_or(gutter_settings.line_numbers);
24190        let line_gutter_width = if show_line_numbers {
24191            // Avoid flicker-like gutter resizes when the line number gains another digit by
24192            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24193            let min_width_for_number_on_gutter =
24194                ch_advance * gutter_settings.min_line_number_digits as f32;
24195            max_line_number_width.max(min_width_for_number_on_gutter)
24196        } else {
24197            0.0.into()
24198        };
24199
24200        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24201        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24202
24203        let git_blame_entries_width =
24204            self.git_blame_gutter_max_author_length
24205                .map(|max_author_length| {
24206                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24207                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24208
24209                    /// The number of characters to dedicate to gaps and margins.
24210                    const SPACING_WIDTH: usize = 4;
24211
24212                    let max_char_count = max_author_length.min(renderer.max_author_length())
24213                        + ::git::SHORT_SHA_LENGTH
24214                        + MAX_RELATIVE_TIMESTAMP.len()
24215                        + SPACING_WIDTH;
24216
24217                    ch_advance * max_char_count
24218                });
24219
24220        let is_singleton = self.buffer_snapshot().is_singleton();
24221
24222        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24223        left_padding += if !is_singleton {
24224            ch_width * 4.0
24225        } else if show_runnables || show_breakpoints {
24226            ch_width * 3.0
24227        } else if show_git_gutter && show_line_numbers {
24228            ch_width * 2.0
24229        } else if show_git_gutter || show_line_numbers {
24230            ch_width
24231        } else {
24232            px(0.)
24233        };
24234
24235        let shows_folds = is_singleton && gutter_settings.folds;
24236
24237        let right_padding = if shows_folds && show_line_numbers {
24238            ch_width * 4.0
24239        } else if shows_folds || (!is_singleton && show_line_numbers) {
24240            ch_width * 3.0
24241        } else if show_line_numbers {
24242            ch_width
24243        } else {
24244            px(0.)
24245        };
24246
24247        Some(GutterDimensions {
24248            left_padding,
24249            right_padding,
24250            width: line_gutter_width + left_padding + right_padding,
24251            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24252            git_blame_entries_width,
24253        })
24254    }
24255
24256    pub fn render_crease_toggle(
24257        &self,
24258        buffer_row: MultiBufferRow,
24259        row_contains_cursor: bool,
24260        editor: Entity<Editor>,
24261        window: &mut Window,
24262        cx: &mut App,
24263    ) -> Option<AnyElement> {
24264        let folded = self.is_line_folded(buffer_row);
24265        let mut is_foldable = false;
24266
24267        if let Some(crease) = self
24268            .crease_snapshot
24269            .query_row(buffer_row, self.buffer_snapshot())
24270        {
24271            is_foldable = true;
24272            match crease {
24273                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24274                    if let Some(render_toggle) = render_toggle {
24275                        let toggle_callback =
24276                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24277                                if folded {
24278                                    editor.update(cx, |editor, cx| {
24279                                        editor.fold_at(buffer_row, window, cx)
24280                                    });
24281                                } else {
24282                                    editor.update(cx, |editor, cx| {
24283                                        editor.unfold_at(buffer_row, window, cx)
24284                                    });
24285                                }
24286                            });
24287                        return Some((render_toggle)(
24288                            buffer_row,
24289                            folded,
24290                            toggle_callback,
24291                            window,
24292                            cx,
24293                        ));
24294                    }
24295                }
24296            }
24297        }
24298
24299        is_foldable |= self.starts_indent(buffer_row);
24300
24301        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24302            Some(
24303                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24304                    .toggle_state(folded)
24305                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24306                        if folded {
24307                            this.unfold_at(buffer_row, window, cx);
24308                        } else {
24309                            this.fold_at(buffer_row, window, cx);
24310                        }
24311                    }))
24312                    .into_any_element(),
24313            )
24314        } else {
24315            None
24316        }
24317    }
24318
24319    pub fn render_crease_trailer(
24320        &self,
24321        buffer_row: MultiBufferRow,
24322        window: &mut Window,
24323        cx: &mut App,
24324    ) -> Option<AnyElement> {
24325        let folded = self.is_line_folded(buffer_row);
24326        if let Crease::Inline { render_trailer, .. } = self
24327            .crease_snapshot
24328            .query_row(buffer_row, self.buffer_snapshot())?
24329        {
24330            let render_trailer = render_trailer.as_ref()?;
24331            Some(render_trailer(buffer_row, folded, window, cx))
24332        } else {
24333            None
24334        }
24335    }
24336}
24337
24338impl Deref for EditorSnapshot {
24339    type Target = DisplaySnapshot;
24340
24341    fn deref(&self) -> &Self::Target {
24342        &self.display_snapshot
24343    }
24344}
24345
24346#[derive(Clone, Debug, PartialEq, Eq)]
24347pub enum EditorEvent {
24348    InputIgnored {
24349        text: Arc<str>,
24350    },
24351    InputHandled {
24352        utf16_range_to_replace: Option<Range<isize>>,
24353        text: Arc<str>,
24354    },
24355    ExcerptsAdded {
24356        buffer: Entity<Buffer>,
24357        predecessor: ExcerptId,
24358        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24359    },
24360    ExcerptsRemoved {
24361        ids: Vec<ExcerptId>,
24362        removed_buffer_ids: Vec<BufferId>,
24363    },
24364    BufferFoldToggled {
24365        ids: Vec<ExcerptId>,
24366        folded: bool,
24367    },
24368    ExcerptsEdited {
24369        ids: Vec<ExcerptId>,
24370    },
24371    ExcerptsExpanded {
24372        ids: Vec<ExcerptId>,
24373    },
24374    BufferEdited,
24375    Edited {
24376        transaction_id: clock::Lamport,
24377    },
24378    Reparsed(BufferId),
24379    Focused,
24380    FocusedIn,
24381    Blurred,
24382    DirtyChanged,
24383    Saved,
24384    TitleChanged,
24385    SelectionsChanged {
24386        local: bool,
24387    },
24388    ScrollPositionChanged {
24389        local: bool,
24390        autoscroll: bool,
24391    },
24392    TransactionUndone {
24393        transaction_id: clock::Lamport,
24394    },
24395    TransactionBegun {
24396        transaction_id: clock::Lamport,
24397    },
24398    CursorShapeChanged,
24399    BreadcrumbsChanged,
24400    PushedToNavHistory {
24401        anchor: Anchor,
24402        is_deactivate: bool,
24403    },
24404}
24405
24406impl EventEmitter<EditorEvent> for Editor {}
24407
24408impl Focusable for Editor {
24409    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24410        self.focus_handle.clone()
24411    }
24412}
24413
24414impl Render for Editor {
24415    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24416        let settings = ThemeSettings::get_global(cx);
24417
24418        let mut text_style = match self.mode {
24419            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24420                color: cx.theme().colors().editor_foreground,
24421                font_family: settings.ui_font.family.clone(),
24422                font_features: settings.ui_font.features.clone(),
24423                font_fallbacks: settings.ui_font.fallbacks.clone(),
24424                font_size: rems(0.875).into(),
24425                font_weight: settings.ui_font.weight,
24426                line_height: relative(settings.buffer_line_height.value()),
24427                ..Default::default()
24428            },
24429            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24430                color: cx.theme().colors().editor_foreground,
24431                font_family: settings.buffer_font.family.clone(),
24432                font_features: settings.buffer_font.features.clone(),
24433                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24434                font_size: settings.buffer_font_size(cx).into(),
24435                font_weight: settings.buffer_font.weight,
24436                line_height: relative(settings.buffer_line_height.value()),
24437                ..Default::default()
24438            },
24439        };
24440        if let Some(text_style_refinement) = &self.text_style_refinement {
24441            text_style.refine(text_style_refinement)
24442        }
24443
24444        let background = match self.mode {
24445            EditorMode::SingleLine => cx.theme().system().transparent,
24446            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24447            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24448            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24449        };
24450
24451        EditorElement::new(
24452            &cx.entity(),
24453            EditorStyle {
24454                background,
24455                border: cx.theme().colors().border,
24456                local_player: cx.theme().players().local(),
24457                text: text_style,
24458                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24459                syntax: cx.theme().syntax().clone(),
24460                status: cx.theme().status().clone(),
24461                inlay_hints_style: make_inlay_hints_style(cx),
24462                edit_prediction_styles: make_suggestion_styles(cx),
24463                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24464                show_underlines: self.diagnostics_enabled(),
24465            },
24466        )
24467    }
24468}
24469
24470impl EntityInputHandler for Editor {
24471    fn text_for_range(
24472        &mut self,
24473        range_utf16: Range<usize>,
24474        adjusted_range: &mut Option<Range<usize>>,
24475        _: &mut Window,
24476        cx: &mut Context<Self>,
24477    ) -> Option<String> {
24478        let snapshot = self.buffer.read(cx).read(cx);
24479        let start = snapshot.clip_offset_utf16(
24480            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24481            Bias::Left,
24482        );
24483        let end = snapshot.clip_offset_utf16(
24484            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24485            Bias::Right,
24486        );
24487        if (start.0.0..end.0.0) != range_utf16 {
24488            adjusted_range.replace(start.0.0..end.0.0);
24489        }
24490        Some(snapshot.text_for_range(start..end).collect())
24491    }
24492
24493    fn selected_text_range(
24494        &mut self,
24495        ignore_disabled_input: bool,
24496        _: &mut Window,
24497        cx: &mut Context<Self>,
24498    ) -> Option<UTF16Selection> {
24499        // Prevent the IME menu from appearing when holding down an alphabetic key
24500        // while input is disabled.
24501        if !ignore_disabled_input && !self.input_enabled {
24502            return None;
24503        }
24504
24505        let selection = self
24506            .selections
24507            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24508        let range = selection.range();
24509
24510        Some(UTF16Selection {
24511            range: range.start.0.0..range.end.0.0,
24512            reversed: selection.reversed,
24513        })
24514    }
24515
24516    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24517        let snapshot = self.buffer.read(cx).read(cx);
24518        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24519        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24520    }
24521
24522    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24523        self.clear_highlights::<InputComposition>(cx);
24524        self.ime_transaction.take();
24525    }
24526
24527    fn replace_text_in_range(
24528        &mut self,
24529        range_utf16: Option<Range<usize>>,
24530        text: &str,
24531        window: &mut Window,
24532        cx: &mut Context<Self>,
24533    ) {
24534        if !self.input_enabled {
24535            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24536            return;
24537        }
24538
24539        self.transact(window, cx, |this, window, cx| {
24540            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24541                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24542                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24543                Some(this.selection_replacement_ranges(range_utf16, cx))
24544            } else {
24545                this.marked_text_ranges(cx)
24546            };
24547
24548            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24549                let newest_selection_id = this.selections.newest_anchor().id;
24550                this.selections
24551                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24552                    .iter()
24553                    .zip(ranges_to_replace.iter())
24554                    .find_map(|(selection, range)| {
24555                        if selection.id == newest_selection_id {
24556                            Some(
24557                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24558                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24559                            )
24560                        } else {
24561                            None
24562                        }
24563                    })
24564            });
24565
24566            cx.emit(EditorEvent::InputHandled {
24567                utf16_range_to_replace: range_to_replace,
24568                text: text.into(),
24569            });
24570
24571            if let Some(new_selected_ranges) = new_selected_ranges {
24572                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24573                    selections.select_ranges(new_selected_ranges)
24574                });
24575                this.backspace(&Default::default(), window, cx);
24576            }
24577
24578            this.handle_input(text, window, cx);
24579        });
24580
24581        if let Some(transaction) = self.ime_transaction {
24582            self.buffer.update(cx, |buffer, cx| {
24583                buffer.group_until_transaction(transaction, cx);
24584            });
24585        }
24586
24587        self.unmark_text(window, cx);
24588    }
24589
24590    fn replace_and_mark_text_in_range(
24591        &mut self,
24592        range_utf16: Option<Range<usize>>,
24593        text: &str,
24594        new_selected_range_utf16: Option<Range<usize>>,
24595        window: &mut Window,
24596        cx: &mut Context<Self>,
24597    ) {
24598        if !self.input_enabled {
24599            return;
24600        }
24601
24602        let transaction = self.transact(window, cx, |this, window, cx| {
24603            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24604                let snapshot = this.buffer.read(cx).read(cx);
24605                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24606                    for marked_range in &mut marked_ranges {
24607                        marked_range.end = marked_range.start + relative_range_utf16.end;
24608                        marked_range.start += relative_range_utf16.start;
24609                        marked_range.start =
24610                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24611                        marked_range.end =
24612                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24613                    }
24614                }
24615                Some(marked_ranges)
24616            } else if let Some(range_utf16) = range_utf16 {
24617                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24618                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24619                Some(this.selection_replacement_ranges(range_utf16, cx))
24620            } else {
24621                None
24622            };
24623
24624            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24625                let newest_selection_id = this.selections.newest_anchor().id;
24626                this.selections
24627                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24628                    .iter()
24629                    .zip(ranges_to_replace.iter())
24630                    .find_map(|(selection, range)| {
24631                        if selection.id == newest_selection_id {
24632                            Some(
24633                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24634                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24635                            )
24636                        } else {
24637                            None
24638                        }
24639                    })
24640            });
24641
24642            cx.emit(EditorEvent::InputHandled {
24643                utf16_range_to_replace: range_to_replace,
24644                text: text.into(),
24645            });
24646
24647            if let Some(ranges) = ranges_to_replace {
24648                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24649                    s.select_ranges(ranges)
24650                });
24651            }
24652
24653            let marked_ranges = {
24654                let snapshot = this.buffer.read(cx).read(cx);
24655                this.selections
24656                    .disjoint_anchors_arc()
24657                    .iter()
24658                    .map(|selection| {
24659                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24660                    })
24661                    .collect::<Vec<_>>()
24662            };
24663
24664            if text.is_empty() {
24665                this.unmark_text(window, cx);
24666            } else {
24667                this.highlight_text::<InputComposition>(
24668                    marked_ranges.clone(),
24669                    HighlightStyle {
24670                        underline: Some(UnderlineStyle {
24671                            thickness: px(1.),
24672                            color: None,
24673                            wavy: false,
24674                        }),
24675                        ..Default::default()
24676                    },
24677                    cx,
24678                );
24679            }
24680
24681            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24682            let use_autoclose = this.use_autoclose;
24683            let use_auto_surround = this.use_auto_surround;
24684            this.set_use_autoclose(false);
24685            this.set_use_auto_surround(false);
24686            this.handle_input(text, window, cx);
24687            this.set_use_autoclose(use_autoclose);
24688            this.set_use_auto_surround(use_auto_surround);
24689
24690            if let Some(new_selected_range) = new_selected_range_utf16 {
24691                let snapshot = this.buffer.read(cx).read(cx);
24692                let new_selected_ranges = marked_ranges
24693                    .into_iter()
24694                    .map(|marked_range| {
24695                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24696                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24697                            insertion_start.0 + new_selected_range.start,
24698                        ));
24699                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24700                            insertion_start.0 + new_selected_range.end,
24701                        ));
24702                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24703                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24704                    })
24705                    .collect::<Vec<_>>();
24706
24707                drop(snapshot);
24708                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24709                    selections.select_ranges(new_selected_ranges)
24710                });
24711            }
24712        });
24713
24714        self.ime_transaction = self.ime_transaction.or(transaction);
24715        if let Some(transaction) = self.ime_transaction {
24716            self.buffer.update(cx, |buffer, cx| {
24717                buffer.group_until_transaction(transaction, cx);
24718            });
24719        }
24720
24721        if self.text_highlights::<InputComposition>(cx).is_none() {
24722            self.ime_transaction.take();
24723        }
24724    }
24725
24726    fn bounds_for_range(
24727        &mut self,
24728        range_utf16: Range<usize>,
24729        element_bounds: gpui::Bounds<Pixels>,
24730        window: &mut Window,
24731        cx: &mut Context<Self>,
24732    ) -> Option<gpui::Bounds<Pixels>> {
24733        let text_layout_details = self.text_layout_details(window);
24734        let CharacterDimensions {
24735            em_width,
24736            em_advance,
24737            line_height,
24738        } = self.character_dimensions(window);
24739
24740        let snapshot = self.snapshot(window, cx);
24741        let scroll_position = snapshot.scroll_position();
24742        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24743
24744        let start =
24745            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24746        let x = Pixels::from(
24747            ScrollOffset::from(
24748                snapshot.x_for_display_point(start, &text_layout_details)
24749                    + self.gutter_dimensions.full_width(),
24750            ) - scroll_left,
24751        );
24752        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24753
24754        Some(Bounds {
24755            origin: element_bounds.origin + point(x, y),
24756            size: size(em_width, line_height),
24757        })
24758    }
24759
24760    fn character_index_for_point(
24761        &mut self,
24762        point: gpui::Point<Pixels>,
24763        _window: &mut Window,
24764        _cx: &mut Context<Self>,
24765    ) -> Option<usize> {
24766        let position_map = self.last_position_map.as_ref()?;
24767        if !position_map.text_hitbox.contains(&point) {
24768            return None;
24769        }
24770        let display_point = position_map.point_for_position(point).previous_valid;
24771        let anchor = position_map
24772            .snapshot
24773            .display_point_to_anchor(display_point, Bias::Left);
24774        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24775        Some(utf16_offset.0.0)
24776    }
24777
24778    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24779        self.input_enabled
24780    }
24781}
24782
24783trait SelectionExt {
24784    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24785    fn spanned_rows(
24786        &self,
24787        include_end_if_at_line_start: bool,
24788        map: &DisplaySnapshot,
24789    ) -> Range<MultiBufferRow>;
24790}
24791
24792impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24793    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24794        let start = self
24795            .start
24796            .to_point(map.buffer_snapshot())
24797            .to_display_point(map);
24798        let end = self
24799            .end
24800            .to_point(map.buffer_snapshot())
24801            .to_display_point(map);
24802        if self.reversed {
24803            end..start
24804        } else {
24805            start..end
24806        }
24807    }
24808
24809    fn spanned_rows(
24810        &self,
24811        include_end_if_at_line_start: bool,
24812        map: &DisplaySnapshot,
24813    ) -> Range<MultiBufferRow> {
24814        let start = self.start.to_point(map.buffer_snapshot());
24815        let mut end = self.end.to_point(map.buffer_snapshot());
24816        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24817            end.row -= 1;
24818        }
24819
24820        let buffer_start = map.prev_line_boundary(start).0;
24821        let buffer_end = map.next_line_boundary(end).0;
24822        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24823    }
24824}
24825
24826impl<T: InvalidationRegion> InvalidationStack<T> {
24827    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24828    where
24829        S: Clone + ToOffset,
24830    {
24831        while let Some(region) = self.last() {
24832            let all_selections_inside_invalidation_ranges =
24833                if selections.len() == region.ranges().len() {
24834                    selections
24835                        .iter()
24836                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24837                        .all(|(selection, invalidation_range)| {
24838                            let head = selection.head().to_offset(buffer);
24839                            invalidation_range.start <= head && invalidation_range.end >= head
24840                        })
24841                } else {
24842                    false
24843                };
24844
24845            if all_selections_inside_invalidation_ranges {
24846                break;
24847            } else {
24848                self.pop();
24849            }
24850        }
24851    }
24852}
24853
24854impl<T> Default for InvalidationStack<T> {
24855    fn default() -> Self {
24856        Self(Default::default())
24857    }
24858}
24859
24860impl<T> Deref for InvalidationStack<T> {
24861    type Target = Vec<T>;
24862
24863    fn deref(&self) -> &Self::Target {
24864        &self.0
24865    }
24866}
24867
24868impl<T> DerefMut for InvalidationStack<T> {
24869    fn deref_mut(&mut self) -> &mut Self::Target {
24870        &mut self.0
24871    }
24872}
24873
24874impl InvalidationRegion for SnippetState {
24875    fn ranges(&self) -> &[Range<Anchor>] {
24876        &self.ranges[self.active_index]
24877    }
24878}
24879
24880fn edit_prediction_edit_text(
24881    current_snapshot: &BufferSnapshot,
24882    edits: &[(Range<Anchor>, impl AsRef<str>)],
24883    edit_preview: &EditPreview,
24884    include_deletions: bool,
24885    cx: &App,
24886) -> HighlightedText {
24887    let edits = edits
24888        .iter()
24889        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24890        .collect::<Vec<_>>();
24891
24892    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24893}
24894
24895fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24896    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24897    // Just show the raw edit text with basic styling
24898    let mut text = String::new();
24899    let mut highlights = Vec::new();
24900
24901    let insertion_highlight_style = HighlightStyle {
24902        color: Some(cx.theme().colors().text),
24903        ..Default::default()
24904    };
24905
24906    for (_, edit_text) in edits {
24907        let start_offset = text.len();
24908        text.push_str(edit_text);
24909        let end_offset = text.len();
24910
24911        if start_offset < end_offset {
24912            highlights.push((start_offset..end_offset, insertion_highlight_style));
24913        }
24914    }
24915
24916    HighlightedText {
24917        text: text.into(),
24918        highlights,
24919    }
24920}
24921
24922pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24923    match severity {
24924        lsp::DiagnosticSeverity::ERROR => colors.error,
24925        lsp::DiagnosticSeverity::WARNING => colors.warning,
24926        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24927        lsp::DiagnosticSeverity::HINT => colors.info,
24928        _ => colors.ignored,
24929    }
24930}
24931
24932pub fn styled_runs_for_code_label<'a>(
24933    label: &'a CodeLabel,
24934    syntax_theme: &'a theme::SyntaxTheme,
24935    local_player: &'a theme::PlayerColor,
24936) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24937    let fade_out = HighlightStyle {
24938        fade_out: Some(0.35),
24939        ..Default::default()
24940    };
24941
24942    let mut prev_end = label.filter_range.end;
24943    label
24944        .runs
24945        .iter()
24946        .enumerate()
24947        .flat_map(move |(ix, (range, highlight_id))| {
24948            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
24949                HighlightStyle {
24950                    color: Some(local_player.cursor),
24951                    ..Default::default()
24952                }
24953            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
24954                HighlightStyle {
24955                    background_color: Some(local_player.selection),
24956                    ..Default::default()
24957                }
24958            } else if let Some(style) = highlight_id.style(syntax_theme) {
24959                style
24960            } else {
24961                return Default::default();
24962            };
24963            let muted_style = style.highlight(fade_out);
24964
24965            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24966            if range.start >= label.filter_range.end {
24967                if range.start > prev_end {
24968                    runs.push((prev_end..range.start, fade_out));
24969                }
24970                runs.push((range.clone(), muted_style));
24971            } else if range.end <= label.filter_range.end {
24972                runs.push((range.clone(), style));
24973            } else {
24974                runs.push((range.start..label.filter_range.end, style));
24975                runs.push((label.filter_range.end..range.end, muted_style));
24976            }
24977            prev_end = cmp::max(prev_end, range.end);
24978
24979            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24980                runs.push((prev_end..label.text.len(), fade_out));
24981            }
24982
24983            runs
24984        })
24985}
24986
24987pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24988    let mut prev_index = 0;
24989    let mut prev_codepoint: Option<char> = None;
24990    text.char_indices()
24991        .chain([(text.len(), '\0')])
24992        .filter_map(move |(index, codepoint)| {
24993            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24994            let is_boundary = index == text.len()
24995                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24996                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24997            if is_boundary {
24998                let chunk = &text[prev_index..index];
24999                prev_index = index;
25000                Some(chunk)
25001            } else {
25002                None
25003            }
25004        })
25005}
25006
25007/// Given a string of text immediately before the cursor, iterates over possible
25008/// strings a snippet could match to. More precisely: returns an iterator over
25009/// suffixes of `text` created by splitting at word boundaries (before & after
25010/// every non-word character).
25011///
25012/// Shorter suffixes are returned first.
25013pub(crate) fn snippet_candidate_suffixes(
25014    text: &str,
25015    is_word_char: impl Fn(char) -> bool,
25016) -> impl std::iter::Iterator<Item = &str> {
25017    let mut prev_index = text.len();
25018    let mut prev_codepoint = None;
25019    text.char_indices()
25020        .rev()
25021        .chain([(0, '\0')])
25022        .filter_map(move |(index, codepoint)| {
25023            let prev_index = std::mem::replace(&mut prev_index, index);
25024            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25025            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25026                None
25027            } else {
25028                let chunk = &text[prev_index..]; // go to end of string
25029                Some(chunk)
25030            }
25031        })
25032}
25033
25034pub trait RangeToAnchorExt: Sized {
25035    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25036
25037    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25038        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25039        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25040    }
25041}
25042
25043impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25044    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25045        let start_offset = self.start.to_offset(snapshot);
25046        let end_offset = self.end.to_offset(snapshot);
25047        if start_offset == end_offset {
25048            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25049        } else {
25050            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25051        }
25052    }
25053}
25054
25055pub trait RowExt {
25056    fn as_f64(&self) -> f64;
25057
25058    fn next_row(&self) -> Self;
25059
25060    fn previous_row(&self) -> Self;
25061
25062    fn minus(&self, other: Self) -> u32;
25063}
25064
25065impl RowExt for DisplayRow {
25066    fn as_f64(&self) -> f64 {
25067        self.0 as _
25068    }
25069
25070    fn next_row(&self) -> Self {
25071        Self(self.0 + 1)
25072    }
25073
25074    fn previous_row(&self) -> Self {
25075        Self(self.0.saturating_sub(1))
25076    }
25077
25078    fn minus(&self, other: Self) -> u32 {
25079        self.0 - other.0
25080    }
25081}
25082
25083impl RowExt for MultiBufferRow {
25084    fn as_f64(&self) -> f64 {
25085        self.0 as _
25086    }
25087
25088    fn next_row(&self) -> Self {
25089        Self(self.0 + 1)
25090    }
25091
25092    fn previous_row(&self) -> Self {
25093        Self(self.0.saturating_sub(1))
25094    }
25095
25096    fn minus(&self, other: Self) -> u32 {
25097        self.0 - other.0
25098    }
25099}
25100
25101trait RowRangeExt {
25102    type Row;
25103
25104    fn len(&self) -> usize;
25105
25106    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25107}
25108
25109impl RowRangeExt for Range<MultiBufferRow> {
25110    type Row = MultiBufferRow;
25111
25112    fn len(&self) -> usize {
25113        (self.end.0 - self.start.0) as usize
25114    }
25115
25116    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25117        (self.start.0..self.end.0).map(MultiBufferRow)
25118    }
25119}
25120
25121impl RowRangeExt for Range<DisplayRow> {
25122    type Row = DisplayRow;
25123
25124    fn len(&self) -> usize {
25125        (self.end.0 - self.start.0) as usize
25126    }
25127
25128    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25129        (self.start.0..self.end.0).map(DisplayRow)
25130    }
25131}
25132
25133/// If select range has more than one line, we
25134/// just point the cursor to range.start.
25135fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25136    if range.start.row == range.end.row {
25137        range
25138    } else {
25139        range.start..range.start
25140    }
25141}
25142pub struct KillRing(ClipboardItem);
25143impl Global for KillRing {}
25144
25145const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25146
25147enum BreakpointPromptEditAction {
25148    Log,
25149    Condition,
25150    HitCondition,
25151}
25152
25153struct BreakpointPromptEditor {
25154    pub(crate) prompt: Entity<Editor>,
25155    editor: WeakEntity<Editor>,
25156    breakpoint_anchor: Anchor,
25157    breakpoint: Breakpoint,
25158    edit_action: BreakpointPromptEditAction,
25159    block_ids: HashSet<CustomBlockId>,
25160    editor_margins: Arc<Mutex<EditorMargins>>,
25161    _subscriptions: Vec<Subscription>,
25162}
25163
25164impl BreakpointPromptEditor {
25165    const MAX_LINES: u8 = 4;
25166
25167    fn new(
25168        editor: WeakEntity<Editor>,
25169        breakpoint_anchor: Anchor,
25170        breakpoint: Breakpoint,
25171        edit_action: BreakpointPromptEditAction,
25172        window: &mut Window,
25173        cx: &mut Context<Self>,
25174    ) -> Self {
25175        let base_text = match edit_action {
25176            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25177            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25178            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25179        }
25180        .map(|msg| msg.to_string())
25181        .unwrap_or_default();
25182
25183        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25184        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25185
25186        let prompt = cx.new(|cx| {
25187            let mut prompt = Editor::new(
25188                EditorMode::AutoHeight {
25189                    min_lines: 1,
25190                    max_lines: Some(Self::MAX_LINES as usize),
25191                },
25192                buffer,
25193                None,
25194                window,
25195                cx,
25196            );
25197            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25198            prompt.set_show_cursor_when_unfocused(false, cx);
25199            prompt.set_placeholder_text(
25200                match edit_action {
25201                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25202                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25203                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25204                },
25205                window,
25206                cx,
25207            );
25208
25209            prompt
25210        });
25211
25212        Self {
25213            prompt,
25214            editor,
25215            breakpoint_anchor,
25216            breakpoint,
25217            edit_action,
25218            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25219            block_ids: Default::default(),
25220            _subscriptions: vec![],
25221        }
25222    }
25223
25224    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25225        self.block_ids.extend(block_ids)
25226    }
25227
25228    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25229        if let Some(editor) = self.editor.upgrade() {
25230            let message = self
25231                .prompt
25232                .read(cx)
25233                .buffer
25234                .read(cx)
25235                .as_singleton()
25236                .expect("A multi buffer in breakpoint prompt isn't possible")
25237                .read(cx)
25238                .as_rope()
25239                .to_string();
25240
25241            editor.update(cx, |editor, cx| {
25242                editor.edit_breakpoint_at_anchor(
25243                    self.breakpoint_anchor,
25244                    self.breakpoint.clone(),
25245                    match self.edit_action {
25246                        BreakpointPromptEditAction::Log => {
25247                            BreakpointEditAction::EditLogMessage(message.into())
25248                        }
25249                        BreakpointPromptEditAction::Condition => {
25250                            BreakpointEditAction::EditCondition(message.into())
25251                        }
25252                        BreakpointPromptEditAction::HitCondition => {
25253                            BreakpointEditAction::EditHitCondition(message.into())
25254                        }
25255                    },
25256                    cx,
25257                );
25258
25259                editor.remove_blocks(self.block_ids.clone(), None, cx);
25260                cx.focus_self(window);
25261            });
25262        }
25263    }
25264
25265    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25266        self.editor
25267            .update(cx, |editor, cx| {
25268                editor.remove_blocks(self.block_ids.clone(), None, cx);
25269                window.focus(&editor.focus_handle);
25270            })
25271            .log_err();
25272    }
25273
25274    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25275        let settings = ThemeSettings::get_global(cx);
25276        let text_style = TextStyle {
25277            color: if self.prompt.read(cx).read_only(cx) {
25278                cx.theme().colors().text_disabled
25279            } else {
25280                cx.theme().colors().text
25281            },
25282            font_family: settings.buffer_font.family.clone(),
25283            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25284            font_size: settings.buffer_font_size(cx).into(),
25285            font_weight: settings.buffer_font.weight,
25286            line_height: relative(settings.buffer_line_height.value()),
25287            ..Default::default()
25288        };
25289        EditorElement::new(
25290            &self.prompt,
25291            EditorStyle {
25292                background: cx.theme().colors().editor_background,
25293                local_player: cx.theme().players().local(),
25294                text: text_style,
25295                ..Default::default()
25296            },
25297        )
25298    }
25299}
25300
25301impl Render for BreakpointPromptEditor {
25302    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25303        let editor_margins = *self.editor_margins.lock();
25304        let gutter_dimensions = editor_margins.gutter;
25305        h_flex()
25306            .key_context("Editor")
25307            .bg(cx.theme().colors().editor_background)
25308            .border_y_1()
25309            .border_color(cx.theme().status().info_border)
25310            .size_full()
25311            .py(window.line_height() / 2.5)
25312            .on_action(cx.listener(Self::confirm))
25313            .on_action(cx.listener(Self::cancel))
25314            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25315            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25316    }
25317}
25318
25319impl Focusable for BreakpointPromptEditor {
25320    fn focus_handle(&self, cx: &App) -> FocusHandle {
25321        self.prompt.focus_handle(cx)
25322    }
25323}
25324
25325fn all_edits_insertions_or_deletions(
25326    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25327    snapshot: &MultiBufferSnapshot,
25328) -> bool {
25329    let mut all_insertions = true;
25330    let mut all_deletions = true;
25331
25332    for (range, new_text) in edits.iter() {
25333        let range_is_empty = range.to_offset(snapshot).is_empty();
25334        let text_is_empty = new_text.is_empty();
25335
25336        if range_is_empty != text_is_empty {
25337            if range_is_empty {
25338                all_deletions = false;
25339            } else {
25340                all_insertions = false;
25341            }
25342        } else {
25343            return false;
25344        }
25345
25346        if !all_insertions && !all_deletions {
25347            return false;
25348        }
25349    }
25350    all_insertions || all_deletions
25351}
25352
25353struct MissingEditPredictionKeybindingTooltip;
25354
25355impl Render for MissingEditPredictionKeybindingTooltip {
25356    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25357        ui::tooltip_container(cx, |container, cx| {
25358            container
25359                .flex_shrink_0()
25360                .max_w_80()
25361                .min_h(rems_from_px(124.))
25362                .justify_between()
25363                .child(
25364                    v_flex()
25365                        .flex_1()
25366                        .text_ui_sm(cx)
25367                        .child(Label::new("Conflict with Accept Keybinding"))
25368                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25369                )
25370                .child(
25371                    h_flex()
25372                        .pb_1()
25373                        .gap_1()
25374                        .items_end()
25375                        .w_full()
25376                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25377                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25378                        }))
25379                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25380                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25381                        })),
25382                )
25383        })
25384    }
25385}
25386
25387#[derive(Debug, Clone, Copy, PartialEq)]
25388pub struct LineHighlight {
25389    pub background: Background,
25390    pub border: Option<gpui::Hsla>,
25391    pub include_gutter: bool,
25392    pub type_id: Option<TypeId>,
25393}
25394
25395struct LineManipulationResult {
25396    pub new_text: String,
25397    pub line_count_before: usize,
25398    pub line_count_after: usize,
25399}
25400
25401fn render_diff_hunk_controls(
25402    row: u32,
25403    status: &DiffHunkStatus,
25404    hunk_range: Range<Anchor>,
25405    is_created_file: bool,
25406    line_height: Pixels,
25407    editor: &Entity<Editor>,
25408    _window: &mut Window,
25409    cx: &mut App,
25410) -> AnyElement {
25411    h_flex()
25412        .h(line_height)
25413        .mr_1()
25414        .gap_1()
25415        .px_0p5()
25416        .pb_1()
25417        .border_x_1()
25418        .border_b_1()
25419        .border_color(cx.theme().colors().border_variant)
25420        .rounded_b_lg()
25421        .bg(cx.theme().colors().editor_background)
25422        .gap_1()
25423        .block_mouse_except_scroll()
25424        .shadow_md()
25425        .child(if status.has_secondary_hunk() {
25426            Button::new(("stage", row as u64), "Stage")
25427                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25428                .tooltip({
25429                    let focus_handle = editor.focus_handle(cx);
25430                    move |_window, cx| {
25431                        Tooltip::for_action_in(
25432                            "Stage Hunk",
25433                            &::git::ToggleStaged,
25434                            &focus_handle,
25435                            cx,
25436                        )
25437                    }
25438                })
25439                .on_click({
25440                    let editor = editor.clone();
25441                    move |_event, _window, cx| {
25442                        editor.update(cx, |editor, cx| {
25443                            editor.stage_or_unstage_diff_hunks(
25444                                true,
25445                                vec![hunk_range.start..hunk_range.start],
25446                                cx,
25447                            );
25448                        });
25449                    }
25450                })
25451        } else {
25452            Button::new(("unstage", row as u64), "Unstage")
25453                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25454                .tooltip({
25455                    let focus_handle = editor.focus_handle(cx);
25456                    move |_window, cx| {
25457                        Tooltip::for_action_in(
25458                            "Unstage Hunk",
25459                            &::git::ToggleStaged,
25460                            &focus_handle,
25461                            cx,
25462                        )
25463                    }
25464                })
25465                .on_click({
25466                    let editor = editor.clone();
25467                    move |_event, _window, cx| {
25468                        editor.update(cx, |editor, cx| {
25469                            editor.stage_or_unstage_diff_hunks(
25470                                false,
25471                                vec![hunk_range.start..hunk_range.start],
25472                                cx,
25473                            );
25474                        });
25475                    }
25476                })
25477        })
25478        .child(
25479            Button::new(("restore", row as u64), "Restore")
25480                .tooltip({
25481                    let focus_handle = editor.focus_handle(cx);
25482                    move |_window, cx| {
25483                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25484                    }
25485                })
25486                .on_click({
25487                    let editor = editor.clone();
25488                    move |_event, window, cx| {
25489                        editor.update(cx, |editor, cx| {
25490                            let snapshot = editor.snapshot(window, cx);
25491                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25492                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25493                        });
25494                    }
25495                })
25496                .disabled(is_created_file),
25497        )
25498        .when(
25499            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25500            |el| {
25501                el.child(
25502                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25503                        .shape(IconButtonShape::Square)
25504                        .icon_size(IconSize::Small)
25505                        // .disabled(!has_multiple_hunks)
25506                        .tooltip({
25507                            let focus_handle = editor.focus_handle(cx);
25508                            move |_window, cx| {
25509                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25510                            }
25511                        })
25512                        .on_click({
25513                            let editor = editor.clone();
25514                            move |_event, window, cx| {
25515                                editor.update(cx, |editor, cx| {
25516                                    let snapshot = editor.snapshot(window, cx);
25517                                    let position =
25518                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25519                                    editor.go_to_hunk_before_or_after_position(
25520                                        &snapshot,
25521                                        position,
25522                                        Direction::Next,
25523                                        window,
25524                                        cx,
25525                                    );
25526                                    editor.expand_selected_diff_hunks(cx);
25527                                });
25528                            }
25529                        }),
25530                )
25531                .child(
25532                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25533                        .shape(IconButtonShape::Square)
25534                        .icon_size(IconSize::Small)
25535                        // .disabled(!has_multiple_hunks)
25536                        .tooltip({
25537                            let focus_handle = editor.focus_handle(cx);
25538                            move |_window, cx| {
25539                                Tooltip::for_action_in(
25540                                    "Previous Hunk",
25541                                    &GoToPreviousHunk,
25542                                    &focus_handle,
25543                                    cx,
25544                                )
25545                            }
25546                        })
25547                        .on_click({
25548                            let editor = editor.clone();
25549                            move |_event, window, cx| {
25550                                editor.update(cx, |editor, cx| {
25551                                    let snapshot = editor.snapshot(window, cx);
25552                                    let point =
25553                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25554                                    editor.go_to_hunk_before_or_after_position(
25555                                        &snapshot,
25556                                        point,
25557                                        Direction::Prev,
25558                                        window,
25559                                        cx,
25560                                    );
25561                                    editor.expand_selected_diff_hunks(cx);
25562                                });
25563                            }
25564                        }),
25565                )
25566            },
25567        )
25568        .into_any_element()
25569}
25570
25571pub fn multibuffer_context_lines(cx: &App) -> u32 {
25572    EditorSettings::try_get(cx)
25573        .map(|settings| settings.excerpt_context_lines)
25574        .unwrap_or(2)
25575        .min(32)
25576}