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
  287pub struct HunkAddedColor;
  288pub struct HunkRemovedColor;
  289
  290#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  291pub enum Navigated {
  292    Yes,
  293    No,
  294}
  295
  296impl Navigated {
  297    pub fn from_bool(yes: bool) -> Navigated {
  298        if yes { Navigated::Yes } else { Navigated::No }
  299    }
  300}
  301
  302#[derive(Debug, Clone, PartialEq, Eq)]
  303enum DisplayDiffHunk {
  304    Folded {
  305        display_row: DisplayRow,
  306    },
  307    Unfolded {
  308        is_created_file: bool,
  309        diff_base_byte_range: Range<usize>,
  310        display_row_range: Range<DisplayRow>,
  311        multi_buffer_range: Range<Anchor>,
  312        status: DiffHunkStatus,
  313        word_diffs: Vec<Range<MultiBufferOffset>>,
  314    },
  315}
  316
  317pub enum HideMouseCursorOrigin {
  318    TypingAction,
  319    MovementAction,
  320}
  321
  322pub fn init(cx: &mut App) {
  323    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  324
  325    workspace::register_project_item::<Editor>(cx);
  326    workspace::FollowableViewRegistry::register::<Editor>(cx);
  327    workspace::register_serializable_item::<Editor>(cx);
  328
  329    cx.observe_new(
  330        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  331            workspace.register_action(Editor::new_file);
  332            workspace.register_action(Editor::new_file_split);
  333            workspace.register_action(Editor::new_file_vertical);
  334            workspace.register_action(Editor::new_file_horizontal);
  335            workspace.register_action(Editor::cancel_language_server_work);
  336            workspace.register_action(Editor::toggle_focus);
  337        },
  338    )
  339    .detach();
  340
  341    cx.on_action(move |_: &workspace::NewFile, cx| {
  342        let app_state = workspace::AppState::global(cx);
  343        if let Some(app_state) = app_state.upgrade() {
  344            workspace::open_new(
  345                Default::default(),
  346                app_state,
  347                cx,
  348                |workspace, window, cx| {
  349                    Editor::new_file(workspace, &Default::default(), window, cx)
  350                },
  351            )
  352            .detach();
  353        }
  354    });
  355    cx.on_action(move |_: &workspace::NewWindow, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    cx.activate(true);
  364                    Editor::new_file(workspace, &Default::default(), window, cx)
  365                },
  366            )
  367            .detach();
  368        }
  369    });
  370}
  371
  372pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  373    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  374}
  375
  376pub trait DiagnosticRenderer {
  377    fn render_group(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        buffer_id: BufferId,
  381        snapshot: EditorSnapshot,
  382        editor: WeakEntity<Editor>,
  383        language_registry: Option<Arc<LanguageRegistry>>,
  384        cx: &mut App,
  385    ) -> Vec<BlockProperties<Anchor>>;
  386
  387    fn render_hover(
  388        &self,
  389        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  390        range: Range<Point>,
  391        buffer_id: BufferId,
  392        language_registry: Option<Arc<LanguageRegistry>>,
  393        cx: &mut App,
  394    ) -> Option<Entity<markdown::Markdown>>;
  395
  396    fn open_link(
  397        &self,
  398        editor: &mut Editor,
  399        link: SharedString,
  400        window: &mut Window,
  401        cx: &mut Context<Editor>,
  402    );
  403}
  404
  405pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  406
  407impl GlobalDiagnosticRenderer {
  408    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  409        cx.try_global::<Self>().map(|g| g.0.clone())
  410    }
  411}
  412
  413impl gpui::Global for GlobalDiagnosticRenderer {}
  414pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  415    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  416}
  417
  418pub struct SearchWithinRange;
  419
  420trait InvalidationRegion {
  421    fn ranges(&self) -> &[Range<Anchor>];
  422}
  423
  424#[derive(Clone, Debug, PartialEq)]
  425pub enum SelectPhase {
  426    Begin {
  427        position: DisplayPoint,
  428        add: bool,
  429        click_count: usize,
  430    },
  431    BeginColumnar {
  432        position: DisplayPoint,
  433        reset: bool,
  434        mode: ColumnarMode,
  435        goal_column: u32,
  436    },
  437    Extend {
  438        position: DisplayPoint,
  439        click_count: usize,
  440    },
  441    Update {
  442        position: DisplayPoint,
  443        goal_column: u32,
  444        scroll_delta: gpui::Point<f32>,
  445    },
  446    End,
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum ColumnarMode {
  451    FromMouse,
  452    FromSelection,
  453}
  454
  455#[derive(Clone, Debug)]
  456pub enum SelectMode {
  457    Character,
  458    Word(Range<Anchor>),
  459    Line(Range<Anchor>),
  460    All,
  461}
  462
  463#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  464pub enum SizingBehavior {
  465    /// The editor will layout itself using `size_full` and will include the vertical
  466    /// scroll margin as requested by user settings.
  467    #[default]
  468    Default,
  469    /// The editor will layout itself using `size_full`, but will not have any
  470    /// vertical overscroll.
  471    ExcludeOverscrollMargin,
  472    /// The editor will request a vertical size according to its content and will be
  473    /// layouted without a vertical scroll margin.
  474    SizeByContent,
  475}
  476
  477#[derive(Clone, PartialEq, Eq, Debug)]
  478pub enum EditorMode {
  479    SingleLine,
  480    AutoHeight {
  481        min_lines: usize,
  482        max_lines: Option<usize>,
  483    },
  484    Full {
  485        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  486        scale_ui_elements_with_buffer_font_size: bool,
  487        /// When set to `true`, the editor will render a background for the active line.
  488        show_active_line_background: bool,
  489        /// Determines the sizing behavior for this editor
  490        sizing_behavior: SizingBehavior,
  491    },
  492    Minimap {
  493        parent: WeakEntity<Editor>,
  494    },
  495}
  496
  497impl EditorMode {
  498    pub fn full() -> Self {
  499        Self::Full {
  500            scale_ui_elements_with_buffer_font_size: true,
  501            show_active_line_background: true,
  502            sizing_behavior: SizingBehavior::Default,
  503        }
  504    }
  505
  506    #[inline]
  507    pub fn is_full(&self) -> bool {
  508        matches!(self, Self::Full { .. })
  509    }
  510
  511    #[inline]
  512    pub fn is_single_line(&self) -> bool {
  513        matches!(self, Self::SingleLine { .. })
  514    }
  515
  516    #[inline]
  517    fn is_minimap(&self) -> bool {
  518        matches!(self, Self::Minimap { .. })
  519    }
  520}
  521
  522#[derive(Copy, Clone, Debug)]
  523pub enum SoftWrap {
  524    /// Prefer not to wrap at all.
  525    ///
  526    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  527    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  528    GitDiff,
  529    /// Prefer a single line generally, unless an overly long line is encountered.
  530    None,
  531    /// Soft wrap lines that exceed the editor width.
  532    EditorWidth,
  533    /// Soft wrap lines at the preferred line length.
  534    Column(u32),
  535    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  536    Bounded(u32),
  537}
  538
  539#[derive(Clone)]
  540pub struct EditorStyle {
  541    pub background: Hsla,
  542    pub border: Hsla,
  543    pub local_player: PlayerColor,
  544    pub text: TextStyle,
  545    pub scrollbar_width: Pixels,
  546    pub syntax: Arc<SyntaxTheme>,
  547    pub status: StatusColors,
  548    pub inlay_hints_style: HighlightStyle,
  549    pub edit_prediction_styles: EditPredictionStyles,
  550    pub unnecessary_code_fade: f32,
  551    pub show_underlines: bool,
  552}
  553
  554impl Default for EditorStyle {
  555    fn default() -> Self {
  556        Self {
  557            background: Hsla::default(),
  558            border: Hsla::default(),
  559            local_player: PlayerColor::default(),
  560            text: TextStyle::default(),
  561            scrollbar_width: Pixels::default(),
  562            syntax: Default::default(),
  563            // HACK: Status colors don't have a real default.
  564            // We should look into removing the status colors from the editor
  565            // style and retrieve them directly from the theme.
  566            status: StatusColors::dark(),
  567            inlay_hints_style: HighlightStyle::default(),
  568            edit_prediction_styles: EditPredictionStyles {
  569                insertion: HighlightStyle::default(),
  570                whitespace: HighlightStyle::default(),
  571            },
  572            unnecessary_code_fade: Default::default(),
  573            show_underlines: true,
  574        }
  575    }
  576}
  577
  578pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  579    let show_background = language_settings::language_settings(None, None, cx)
  580        .inlay_hints
  581        .show_background;
  582
  583    let mut style = cx.theme().syntax().get("hint");
  584
  585    if style.color.is_none() {
  586        style.color = Some(cx.theme().status().hint);
  587    }
  588
  589    if !show_background {
  590        style.background_color = None;
  591        return style;
  592    }
  593
  594    if style.background_color.is_none() {
  595        style.background_color = Some(cx.theme().status().hint_background);
  596    }
  597
  598    style
  599}
  600
  601pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  602    EditPredictionStyles {
  603        insertion: HighlightStyle {
  604            color: Some(cx.theme().status().predictive),
  605            ..HighlightStyle::default()
  606        },
  607        whitespace: HighlightStyle {
  608            background_color: Some(cx.theme().status().created_background),
  609            ..HighlightStyle::default()
  610        },
  611    }
  612}
  613
  614type CompletionId = usize;
  615
  616pub(crate) enum EditDisplayMode {
  617    TabAccept,
  618    DiffPopover,
  619    Inline,
  620}
  621
  622enum EditPrediction {
  623    Edit {
  624        edits: Vec<(Range<Anchor>, Arc<str>)>,
  625        edit_preview: Option<EditPreview>,
  626        display_mode: EditDisplayMode,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in the active editor
  630    MoveWithin {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634    /// Move to a specific location in a different editor (not the active one)
  635    MoveOutside {
  636        target: language::Anchor,
  637        snapshot: BufferSnapshot,
  638    },
  639}
  640
  641struct EditPredictionState {
  642    inlay_ids: Vec<InlayId>,
  643    completion: EditPrediction,
  644    completion_id: Option<SharedString>,
  645    invalidation_range: Option<Range<Anchor>>,
  646}
  647
  648enum EditPredictionSettings {
  649    Disabled,
  650    Enabled {
  651        show_in_menu: bool,
  652        preview_requires_modifier: bool,
  653    },
  654}
  655
  656enum EditPredictionHighlight {}
  657
  658#[derive(Debug, Clone)]
  659struct InlineDiagnostic {
  660    message: SharedString,
  661    group_id: usize,
  662    is_primary: bool,
  663    start: Point,
  664    severity: lsp::DiagnosticSeverity,
  665}
  666
  667pub enum MenuEditPredictionsPolicy {
  668    Never,
  669    ByProvider,
  670}
  671
  672pub enum EditPredictionPreview {
  673    /// Modifier is not pressed
  674    Inactive { released_too_fast: bool },
  675    /// Modifier pressed
  676    Active {
  677        since: Instant,
  678        previous_scroll_position: Option<ScrollAnchor>,
  679    },
  680}
  681
  682impl EditPredictionPreview {
  683    pub fn released_too_fast(&self) -> bool {
  684        match self {
  685            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  686            EditPredictionPreview::Active { .. } => false,
  687        }
  688    }
  689
  690    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  691        if let EditPredictionPreview::Active {
  692            previous_scroll_position,
  693            ..
  694        } = self
  695        {
  696            *previous_scroll_position = scroll_position;
  697        }
  698    }
  699}
  700
  701pub struct ContextMenuOptions {
  702    pub min_entries_visible: usize,
  703    pub max_entries_visible: usize,
  704    pub placement: Option<ContextMenuPlacement>,
  705}
  706
  707#[derive(Debug, Clone, PartialEq, Eq)]
  708pub enum ContextMenuPlacement {
  709    Above,
  710    Below,
  711}
  712
  713#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  714struct EditorActionId(usize);
  715
  716impl EditorActionId {
  717    pub fn post_inc(&mut self) -> Self {
  718        let answer = self.0;
  719
  720        *self = Self(answer + 1);
  721
  722        Self(answer)
  723    }
  724}
  725
  726// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  727// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  728
  729type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  730type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  731
  732#[derive(Default)]
  733struct ScrollbarMarkerState {
  734    scrollbar_size: Size<Pixels>,
  735    dirty: bool,
  736    markers: Arc<[PaintQuad]>,
  737    pending_refresh: Option<Task<Result<()>>>,
  738}
  739
  740impl ScrollbarMarkerState {
  741    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  742        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  743    }
  744}
  745
  746#[derive(Clone, Copy, PartialEq, Eq)]
  747pub enum MinimapVisibility {
  748    Disabled,
  749    Enabled {
  750        /// The configuration currently present in the users settings.
  751        setting_configuration: bool,
  752        /// Whether to override the currently set visibility from the users setting.
  753        toggle_override: bool,
  754    },
  755}
  756
  757impl MinimapVisibility {
  758    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  759        if mode.is_full() {
  760            Self::Enabled {
  761                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  762                toggle_override: false,
  763            }
  764        } else {
  765            Self::Disabled
  766        }
  767    }
  768
  769    fn hidden(&self) -> Self {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                ..
  774            } => Self::Enabled {
  775                setting_configuration,
  776                toggle_override: setting_configuration,
  777            },
  778            Self::Disabled => Self::Disabled,
  779        }
  780    }
  781
  782    fn disabled(&self) -> bool {
  783        matches!(*self, Self::Disabled)
  784    }
  785
  786    fn settings_visibility(&self) -> bool {
  787        match *self {
  788            Self::Enabled {
  789                setting_configuration,
  790                ..
  791            } => setting_configuration,
  792            _ => false,
  793        }
  794    }
  795
  796    fn visible(&self) -> bool {
  797        match *self {
  798            Self::Enabled {
  799                setting_configuration,
  800                toggle_override,
  801            } => setting_configuration ^ toggle_override,
  802            _ => false,
  803        }
  804    }
  805
  806    fn toggle_visibility(&self) -> Self {
  807        match *self {
  808            Self::Enabled {
  809                toggle_override,
  810                setting_configuration,
  811            } => Self::Enabled {
  812                setting_configuration,
  813                toggle_override: !toggle_override,
  814            },
  815            Self::Disabled => Self::Disabled,
  816        }
  817    }
  818}
  819
  820#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  821pub enum BufferSerialization {
  822    All,
  823    NonDirtyBuffers,
  824}
  825
  826impl BufferSerialization {
  827    fn new(restore_unsaved_buffers: bool) -> Self {
  828        if restore_unsaved_buffers {
  829            Self::All
  830        } else {
  831            Self::NonDirtyBuffers
  832        }
  833    }
  834}
  835
  836#[derive(Clone, Debug)]
  837struct RunnableTasks {
  838    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  839    offset: multi_buffer::Anchor,
  840    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  841    column: u32,
  842    // Values of all named captures, including those starting with '_'
  843    extra_variables: HashMap<String, String>,
  844    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  845    context_range: Range<BufferOffset>,
  846}
  847
  848impl RunnableTasks {
  849    fn resolve<'a>(
  850        &'a self,
  851        cx: &'a task::TaskContext,
  852    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  853        self.templates.iter().filter_map(|(kind, template)| {
  854            template
  855                .resolve_task(&kind.to_id_base(), cx)
  856                .map(|task| (kind.clone(), task))
  857        })
  858    }
  859}
  860
  861#[derive(Clone)]
  862pub struct ResolvedTasks {
  863    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  864    position: Anchor,
  865}
  866
  867/// Addons allow storing per-editor state in other crates (e.g. Vim)
  868pub trait Addon: 'static {
  869    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  870
  871    fn render_buffer_header_controls(
  872        &self,
  873        _: &ExcerptInfo,
  874        _: &Window,
  875        _: &App,
  876    ) -> Option<AnyElement> {
  877        None
  878    }
  879
  880    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  881        None
  882    }
  883
  884    fn to_any(&self) -> &dyn std::any::Any;
  885
  886    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  887        None
  888    }
  889}
  890
  891struct ChangeLocation {
  892    current: Option<Vec<Anchor>>,
  893    original: Vec<Anchor>,
  894}
  895impl ChangeLocation {
  896    fn locations(&self) -> &[Anchor] {
  897        self.current.as_ref().unwrap_or(&self.original)
  898    }
  899}
  900
  901/// A set of caret positions, registered when the editor was edited.
  902pub struct ChangeList {
  903    changes: Vec<ChangeLocation>,
  904    /// Currently "selected" change.
  905    position: Option<usize>,
  906}
  907
  908impl ChangeList {
  909    pub fn new() -> Self {
  910        Self {
  911            changes: Vec::new(),
  912            position: None,
  913        }
  914    }
  915
  916    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  917    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  918    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  919        if self.changes.is_empty() {
  920            return None;
  921        }
  922
  923        let prev = self.position.unwrap_or(self.changes.len());
  924        let next = if direction == Direction::Prev {
  925            prev.saturating_sub(count)
  926        } else {
  927            (prev + count).min(self.changes.len() - 1)
  928        };
  929        self.position = Some(next);
  930        self.changes.get(next).map(|change| change.locations())
  931    }
  932
  933    /// Adds a new change to the list, resetting the change list position.
  934    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  935        self.position.take();
  936        if let Some(last) = self.changes.last_mut()
  937            && group
  938        {
  939            last.current = Some(new_positions)
  940        } else {
  941            self.changes.push(ChangeLocation {
  942                original: new_positions,
  943                current: None,
  944            });
  945        }
  946    }
  947
  948    pub fn last(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.locations())
  950    }
  951
  952    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  953        self.changes.last().map(|change| change.original.as_slice())
  954    }
  955
  956    pub fn invert_last_group(&mut self) {
  957        if let Some(last) = self.changes.last_mut()
  958            && let Some(current) = last.current.as_mut()
  959        {
  960            mem::swap(&mut last.original, current);
  961        }
  962    }
  963}
  964
  965#[derive(Clone)]
  966struct InlineBlamePopoverState {
  967    scroll_handle: ScrollHandle,
  968    commit_message: Option<ParsedCommitMessage>,
  969    markdown: Entity<Markdown>,
  970}
  971
  972struct InlineBlamePopover {
  973    position: gpui::Point<Pixels>,
  974    hide_task: Option<Task<()>>,
  975    popover_bounds: Option<Bounds<Pixels>>,
  976    popover_state: InlineBlamePopoverState,
  977    keyboard_grace: bool,
  978}
  979
  980enum SelectionDragState {
  981    /// State when no drag related activity is detected.
  982    None,
  983    /// State when the mouse is down on a selection that is about to be dragged.
  984    ReadyToDrag {
  985        selection: Selection<Anchor>,
  986        click_position: gpui::Point<Pixels>,
  987        mouse_down_time: Instant,
  988    },
  989    /// State when the mouse is dragging the selection in the editor.
  990    Dragging {
  991        selection: Selection<Anchor>,
  992        drop_cursor: Selection<Anchor>,
  993        hide_drop_cursor: bool,
  994    },
  995}
  996
  997enum ColumnarSelectionState {
  998    FromMouse {
  999        selection_tail: Anchor,
 1000        display_point: Option<DisplayPoint>,
 1001    },
 1002    FromSelection {
 1003        selection_tail: Anchor,
 1004    },
 1005}
 1006
 1007/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1008/// a breakpoint on them.
 1009#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1010struct PhantomBreakpointIndicator {
 1011    display_row: DisplayRow,
 1012    /// There's a small debounce between hovering over the line and showing the indicator.
 1013    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1014    is_active: bool,
 1015    collides_with_existing_breakpoint: bool,
 1016}
 1017
 1018/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1019///
 1020/// See the [module level documentation](self) for more information.
 1021pub struct Editor {
 1022    focus_handle: FocusHandle,
 1023    last_focused_descendant: Option<WeakFocusHandle>,
 1024    /// The text buffer being edited
 1025    buffer: Entity<MultiBuffer>,
 1026    /// Map of how text in the buffer should be displayed.
 1027    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1028    pub display_map: Entity<DisplayMap>,
 1029    placeholder_display_map: Option<Entity<DisplayMap>>,
 1030    pub selections: SelectionsCollection,
 1031    pub scroll_manager: ScrollManager,
 1032    /// When inline assist editors are linked, they all render cursors because
 1033    /// typing enters text into each of them, even the ones that aren't focused.
 1034    pub(crate) show_cursor_when_unfocused: bool,
 1035    columnar_selection_state: Option<ColumnarSelectionState>,
 1036    add_selections_state: Option<AddSelectionsState>,
 1037    select_next_state: Option<SelectNextState>,
 1038    select_prev_state: Option<SelectNextState>,
 1039    selection_history: SelectionHistory,
 1040    defer_selection_effects: bool,
 1041    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1042    autoclose_regions: Vec<AutocloseRegion>,
 1043    snippet_stack: InvalidationStack<SnippetState>,
 1044    select_syntax_node_history: SelectSyntaxNodeHistory,
 1045    ime_transaction: Option<TransactionId>,
 1046    pub diagnostics_max_severity: DiagnosticSeverity,
 1047    active_diagnostics: ActiveDiagnostic,
 1048    show_inline_diagnostics: bool,
 1049    inline_diagnostics_update: Task<()>,
 1050    inline_diagnostics_enabled: bool,
 1051    diagnostics_enabled: bool,
 1052    word_completions_enabled: bool,
 1053    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1054    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1055    hard_wrap: Option<usize>,
 1056    project: Option<Entity<Project>>,
 1057    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1058    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1059    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1060    blink_manager: Entity<BlinkManager>,
 1061    show_cursor_names: bool,
 1062    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1063    pub show_local_selections: bool,
 1064    mode: EditorMode,
 1065    show_breadcrumbs: bool,
 1066    show_gutter: bool,
 1067    show_scrollbars: ScrollbarAxes,
 1068    minimap_visibility: MinimapVisibility,
 1069    offset_content: bool,
 1070    disable_expand_excerpt_buttons: bool,
 1071    show_line_numbers: Option<bool>,
 1072    use_relative_line_numbers: Option<bool>,
 1073    show_git_diff_gutter: Option<bool>,
 1074    show_code_actions: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    show_wrap_guides: Option<bool>,
 1078    show_indent_guides: Option<bool>,
 1079    highlight_order: usize,
 1080    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1081    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1082    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1083    scrollbar_marker_state: ScrollbarMarkerState,
 1084    active_indent_guides_state: ActiveIndentGuidesState,
 1085    nav_history: Option<ItemNavHistory>,
 1086    context_menu: RefCell<Option<CodeContextMenu>>,
 1087    context_menu_options: Option<ContextMenuOptions>,
 1088    mouse_context_menu: Option<MouseContextMenu>,
 1089    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1090    inline_blame_popover: Option<InlineBlamePopover>,
 1091    inline_blame_popover_show_task: Option<Task<()>>,
 1092    signature_help_state: SignatureHelpState,
 1093    auto_signature_help: Option<bool>,
 1094    find_all_references_task_sources: Vec<Anchor>,
 1095    next_completion_id: CompletionId,
 1096    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1097    code_actions_task: Option<Task<Result<()>>>,
 1098    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1099    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1100    document_highlights_task: Option<Task<()>>,
 1101    linked_editing_range_task: Option<Task<Option<()>>>,
 1102    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1103    pending_rename: Option<RenameState>,
 1104    searchable: bool,
 1105    cursor_shape: CursorShape,
 1106    current_line_highlight: Option<CurrentLineHighlight>,
 1107    pub collapse_matches: bool,
 1108    autoindent_mode: Option<AutoindentMode>,
 1109    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1110    input_enabled: bool,
 1111    use_modal_editing: bool,
 1112    read_only: bool,
 1113    leader_id: Option<CollaboratorId>,
 1114    remote_id: Option<ViewId>,
 1115    pub hover_state: HoverState,
 1116    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1117    gutter_hovered: bool,
 1118    hovered_link_state: Option<HoveredLinkState>,
 1119    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1120    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1121    active_edit_prediction: Option<EditPredictionState>,
 1122    /// Used to prevent flickering as the user types while the menu is open
 1123    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1124    edit_prediction_settings: EditPredictionSettings,
 1125    edit_predictions_hidden_for_vim_mode: bool,
 1126    show_edit_predictions_override: Option<bool>,
 1127    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1128    edit_prediction_preview: EditPredictionPreview,
 1129    edit_prediction_indent_conflict: bool,
 1130    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1131    next_inlay_id: usize,
 1132    next_color_inlay_id: usize,
 1133    _subscriptions: Vec<Subscription>,
 1134    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1135    gutter_dimensions: GutterDimensions,
 1136    style: Option<EditorStyle>,
 1137    text_style_refinement: Option<TextStyleRefinement>,
 1138    next_editor_action_id: EditorActionId,
 1139    editor_actions: Rc<
 1140        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1141    >,
 1142    use_autoclose: bool,
 1143    use_auto_surround: bool,
 1144    auto_replace_emoji_shortcode: bool,
 1145    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1146    show_git_blame_gutter: bool,
 1147    show_git_blame_inline: bool,
 1148    show_git_blame_inline_delay_task: Option<Task<()>>,
 1149    git_blame_inline_enabled: bool,
 1150    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1151    buffer_serialization: Option<BufferSerialization>,
 1152    show_selection_menu: Option<bool>,
 1153    blame: Option<Entity<GitBlame>>,
 1154    blame_subscription: Option<Subscription>,
 1155    custom_context_menu: Option<
 1156        Box<
 1157            dyn 'static
 1158                + Fn(
 1159                    &mut Self,
 1160                    DisplayPoint,
 1161                    &mut Window,
 1162                    &mut Context<Self>,
 1163                ) -> Option<Entity<ui::ContextMenu>>,
 1164        >,
 1165    >,
 1166    last_bounds: Option<Bounds<Pixels>>,
 1167    last_position_map: Option<Rc<PositionMap>>,
 1168    expect_bounds_change: Option<Bounds<Pixels>>,
 1169    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1170    tasks_update_task: Option<Task<()>>,
 1171    breakpoint_store: Option<Entity<BreakpointStore>>,
 1172    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1173    hovered_diff_hunk_row: Option<DisplayRow>,
 1174    pull_diagnostics_task: Task<()>,
 1175    in_project_search: bool,
 1176    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1177    breadcrumb_header: Option<String>,
 1178    focused_block: Option<FocusedBlock>,
 1179    next_scroll_position: NextScrollCursorCenterTopBottom,
 1180    addons: HashMap<TypeId, Box<dyn Addon>>,
 1181    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1182    load_diff_task: Option<Shared<Task<()>>>,
 1183    /// Whether we are temporarily displaying a diff other than git's
 1184    temporary_diff_override: bool,
 1185    selection_mark_mode: bool,
 1186    toggle_fold_multiple_buffers: Task<()>,
 1187    _scroll_cursor_center_top_bottom_task: Task<()>,
 1188    serialize_selections: Task<()>,
 1189    serialize_folds: Task<()>,
 1190    mouse_cursor_hidden: bool,
 1191    minimap: Option<Entity<Self>>,
 1192    hide_mouse_mode: HideMouseMode,
 1193    pub change_list: ChangeList,
 1194    inline_value_cache: InlineValueCache,
 1195
 1196    selection_drag_state: SelectionDragState,
 1197    colors: Option<LspColorData>,
 1198    post_scroll_update: Task<()>,
 1199    refresh_colors_task: Task<()>,
 1200    inlay_hints: Option<LspInlayHintData>,
 1201    folding_newlines: Task<()>,
 1202    select_next_is_case_sensitive: Option<bool>,
 1203    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1204    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1205    accent_overrides: Vec<SharedString>,
 1206    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1207    use_base_text_line_numbers: bool,
 1208}
 1209
 1210fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1211    if debounce_ms > 0 {
 1212        Some(Duration::from_millis(debounce_ms))
 1213    } else {
 1214        None
 1215    }
 1216}
 1217
 1218#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1219enum NextScrollCursorCenterTopBottom {
 1220    #[default]
 1221    Center,
 1222    Top,
 1223    Bottom,
 1224}
 1225
 1226impl NextScrollCursorCenterTopBottom {
 1227    fn next(&self) -> Self {
 1228        match self {
 1229            Self::Center => Self::Top,
 1230            Self::Top => Self::Bottom,
 1231            Self::Bottom => Self::Center,
 1232        }
 1233    }
 1234}
 1235
 1236#[derive(Clone)]
 1237pub struct EditorSnapshot {
 1238    pub mode: EditorMode,
 1239    show_gutter: bool,
 1240    show_line_numbers: Option<bool>,
 1241    show_git_diff_gutter: Option<bool>,
 1242    show_code_actions: Option<bool>,
 1243    show_runnables: Option<bool>,
 1244    show_breakpoints: Option<bool>,
 1245    git_blame_gutter_max_author_length: Option<usize>,
 1246    pub display_snapshot: DisplaySnapshot,
 1247    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1248    is_focused: bool,
 1249    scroll_anchor: ScrollAnchor,
 1250    ongoing_scroll: OngoingScroll,
 1251    current_line_highlight: CurrentLineHighlight,
 1252    gutter_hovered: bool,
 1253}
 1254
 1255#[derive(Default, Debug, Clone, Copy)]
 1256pub struct GutterDimensions {
 1257    pub left_padding: Pixels,
 1258    pub right_padding: Pixels,
 1259    pub width: Pixels,
 1260    pub margin: Pixels,
 1261    pub git_blame_entries_width: Option<Pixels>,
 1262}
 1263
 1264impl GutterDimensions {
 1265    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1266        Self {
 1267            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1268            ..Default::default()
 1269        }
 1270    }
 1271
 1272    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1273        -cx.text_system().descent(font_id, font_size)
 1274    }
 1275    /// The full width of the space taken up by the gutter.
 1276    pub fn full_width(&self) -> Pixels {
 1277        self.margin + self.width
 1278    }
 1279
 1280    /// The width of the space reserved for the fold indicators,
 1281    /// use alongside 'justify_end' and `gutter_width` to
 1282    /// right align content with the line numbers
 1283    pub fn fold_area_width(&self) -> Pixels {
 1284        self.margin + self.right_padding
 1285    }
 1286}
 1287
 1288struct CharacterDimensions {
 1289    em_width: Pixels,
 1290    em_advance: Pixels,
 1291    line_height: Pixels,
 1292}
 1293
 1294#[derive(Debug)]
 1295pub struct RemoteSelection {
 1296    pub replica_id: ReplicaId,
 1297    pub selection: Selection<Anchor>,
 1298    pub cursor_shape: CursorShape,
 1299    pub collaborator_id: CollaboratorId,
 1300    pub line_mode: bool,
 1301    pub user_name: Option<SharedString>,
 1302    pub color: PlayerColor,
 1303}
 1304
 1305#[derive(Clone, Debug)]
 1306struct SelectionHistoryEntry {
 1307    selections: Arc<[Selection<Anchor>]>,
 1308    select_next_state: Option<SelectNextState>,
 1309    select_prev_state: Option<SelectNextState>,
 1310    add_selections_state: Option<AddSelectionsState>,
 1311}
 1312
 1313#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1314enum SelectionHistoryMode {
 1315    #[default]
 1316    Normal,
 1317    Undoing,
 1318    Redoing,
 1319    Skipping,
 1320}
 1321
 1322#[derive(Clone, PartialEq, Eq, Hash)]
 1323struct HoveredCursor {
 1324    replica_id: ReplicaId,
 1325    selection_id: usize,
 1326}
 1327
 1328#[derive(Debug)]
 1329/// SelectionEffects controls the side-effects of updating the selection.
 1330///
 1331/// The default behaviour does "what you mostly want":
 1332/// - it pushes to the nav history if the cursor moved by >10 lines
 1333/// - it re-triggers completion requests
 1334/// - it scrolls to fit
 1335///
 1336/// You might want to modify these behaviours. For example when doing a "jump"
 1337/// like go to definition, we always want to add to nav history; but when scrolling
 1338/// in vim mode we never do.
 1339///
 1340/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1341/// move.
 1342#[derive(Clone)]
 1343pub struct SelectionEffects {
 1344    nav_history: Option<bool>,
 1345    completions: bool,
 1346    scroll: Option<Autoscroll>,
 1347}
 1348
 1349impl Default for SelectionEffects {
 1350    fn default() -> Self {
 1351        Self {
 1352            nav_history: None,
 1353            completions: true,
 1354            scroll: Some(Autoscroll::fit()),
 1355        }
 1356    }
 1357}
 1358impl SelectionEffects {
 1359    pub fn scroll(scroll: Autoscroll) -> Self {
 1360        Self {
 1361            scroll: Some(scroll),
 1362            ..Default::default()
 1363        }
 1364    }
 1365
 1366    pub fn no_scroll() -> Self {
 1367        Self {
 1368            scroll: None,
 1369            ..Default::default()
 1370        }
 1371    }
 1372
 1373    pub fn completions(self, completions: bool) -> Self {
 1374        Self {
 1375            completions,
 1376            ..self
 1377        }
 1378    }
 1379
 1380    pub fn nav_history(self, nav_history: bool) -> Self {
 1381        Self {
 1382            nav_history: Some(nav_history),
 1383            ..self
 1384        }
 1385    }
 1386}
 1387
 1388struct DeferredSelectionEffectsState {
 1389    changed: bool,
 1390    effects: SelectionEffects,
 1391    old_cursor_position: Anchor,
 1392    history_entry: SelectionHistoryEntry,
 1393}
 1394
 1395#[derive(Default)]
 1396struct SelectionHistory {
 1397    #[allow(clippy::type_complexity)]
 1398    selections_by_transaction:
 1399        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1400    mode: SelectionHistoryMode,
 1401    undo_stack: VecDeque<SelectionHistoryEntry>,
 1402    redo_stack: VecDeque<SelectionHistoryEntry>,
 1403}
 1404
 1405impl SelectionHistory {
 1406    #[track_caller]
 1407    fn insert_transaction(
 1408        &mut self,
 1409        transaction_id: TransactionId,
 1410        selections: Arc<[Selection<Anchor>]>,
 1411    ) {
 1412        if selections.is_empty() {
 1413            log::error!(
 1414                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1415                std::panic::Location::caller()
 1416            );
 1417            return;
 1418        }
 1419        self.selections_by_transaction
 1420            .insert(transaction_id, (selections, None));
 1421    }
 1422
 1423    #[allow(clippy::type_complexity)]
 1424    fn transaction(
 1425        &self,
 1426        transaction_id: TransactionId,
 1427    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1428        self.selections_by_transaction.get(&transaction_id)
 1429    }
 1430
 1431    #[allow(clippy::type_complexity)]
 1432    fn transaction_mut(
 1433        &mut self,
 1434        transaction_id: TransactionId,
 1435    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1436        self.selections_by_transaction.get_mut(&transaction_id)
 1437    }
 1438
 1439    fn push(&mut self, entry: SelectionHistoryEntry) {
 1440        if !entry.selections.is_empty() {
 1441            match self.mode {
 1442                SelectionHistoryMode::Normal => {
 1443                    self.push_undo(entry);
 1444                    self.redo_stack.clear();
 1445                }
 1446                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1447                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1448                SelectionHistoryMode::Skipping => {}
 1449            }
 1450        }
 1451    }
 1452
 1453    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1454        if self
 1455            .undo_stack
 1456            .back()
 1457            .is_none_or(|e| e.selections != entry.selections)
 1458        {
 1459            self.undo_stack.push_back(entry);
 1460            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1461                self.undo_stack.pop_front();
 1462            }
 1463        }
 1464    }
 1465
 1466    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1467        if self
 1468            .redo_stack
 1469            .back()
 1470            .is_none_or(|e| e.selections != entry.selections)
 1471        {
 1472            self.redo_stack.push_back(entry);
 1473            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1474                self.redo_stack.pop_front();
 1475            }
 1476        }
 1477    }
 1478}
 1479
 1480#[derive(Clone, Copy)]
 1481pub struct RowHighlightOptions {
 1482    pub autoscroll: bool,
 1483    pub include_gutter: bool,
 1484}
 1485
 1486impl Default for RowHighlightOptions {
 1487    fn default() -> Self {
 1488        Self {
 1489            autoscroll: Default::default(),
 1490            include_gutter: true,
 1491        }
 1492    }
 1493}
 1494
 1495struct RowHighlight {
 1496    index: usize,
 1497    range: Range<Anchor>,
 1498    color: Hsla,
 1499    options: RowHighlightOptions,
 1500    type_id: TypeId,
 1501}
 1502
 1503#[derive(Clone, Debug)]
 1504struct AddSelectionsState {
 1505    groups: Vec<AddSelectionsGroup>,
 1506}
 1507
 1508#[derive(Clone, Debug)]
 1509struct AddSelectionsGroup {
 1510    above: bool,
 1511    stack: Vec<usize>,
 1512}
 1513
 1514#[derive(Clone)]
 1515struct SelectNextState {
 1516    query: AhoCorasick,
 1517    wordwise: bool,
 1518    done: bool,
 1519}
 1520
 1521impl std::fmt::Debug for SelectNextState {
 1522    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1523        f.debug_struct(std::any::type_name::<Self>())
 1524            .field("wordwise", &self.wordwise)
 1525            .field("done", &self.done)
 1526            .finish()
 1527    }
 1528}
 1529
 1530#[derive(Debug)]
 1531struct AutocloseRegion {
 1532    selection_id: usize,
 1533    range: Range<Anchor>,
 1534    pair: BracketPair,
 1535}
 1536
 1537#[derive(Debug)]
 1538struct SnippetState {
 1539    ranges: Vec<Vec<Range<Anchor>>>,
 1540    active_index: usize,
 1541    choices: Vec<Option<Vec<String>>>,
 1542}
 1543
 1544#[doc(hidden)]
 1545pub struct RenameState {
 1546    pub range: Range<Anchor>,
 1547    pub old_name: Arc<str>,
 1548    pub editor: Entity<Editor>,
 1549    block_id: CustomBlockId,
 1550}
 1551
 1552struct InvalidationStack<T>(Vec<T>);
 1553
 1554struct RegisteredEditPredictionProvider {
 1555    provider: Arc<dyn EditPredictionProviderHandle>,
 1556    _subscription: Subscription,
 1557}
 1558
 1559#[derive(Debug, PartialEq, Eq)]
 1560pub struct ActiveDiagnosticGroup {
 1561    pub active_range: Range<Anchor>,
 1562    pub active_message: String,
 1563    pub group_id: usize,
 1564    pub blocks: HashSet<CustomBlockId>,
 1565}
 1566
 1567#[derive(Debug, PartialEq, Eq)]
 1568
 1569pub(crate) enum ActiveDiagnostic {
 1570    None,
 1571    All,
 1572    Group(ActiveDiagnosticGroup),
 1573}
 1574
 1575#[derive(Serialize, Deserialize, Clone, Debug)]
 1576pub struct ClipboardSelection {
 1577    /// The number of bytes in this selection.
 1578    pub len: usize,
 1579    /// Whether this was a full-line selection.
 1580    pub is_entire_line: bool,
 1581    /// The indentation of the first line when this content was originally copied.
 1582    pub first_line_indent: u32,
 1583}
 1584
 1585// selections, scroll behavior, was newest selection reversed
 1586type SelectSyntaxNodeHistoryState = (
 1587    Box<[Selection<MultiBufferOffset>]>,
 1588    SelectSyntaxNodeScrollBehavior,
 1589    bool,
 1590);
 1591
 1592#[derive(Default)]
 1593struct SelectSyntaxNodeHistory {
 1594    stack: Vec<SelectSyntaxNodeHistoryState>,
 1595    // disable temporarily to allow changing selections without losing the stack
 1596    pub disable_clearing: bool,
 1597}
 1598
 1599impl SelectSyntaxNodeHistory {
 1600    pub fn try_clear(&mut self) {
 1601        if !self.disable_clearing {
 1602            self.stack.clear();
 1603        }
 1604    }
 1605
 1606    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1607        self.stack.push(selection);
 1608    }
 1609
 1610    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1611        self.stack.pop()
 1612    }
 1613}
 1614
 1615enum SelectSyntaxNodeScrollBehavior {
 1616    CursorTop,
 1617    FitSelection,
 1618    CursorBottom,
 1619}
 1620
 1621#[derive(Debug)]
 1622pub(crate) struct NavigationData {
 1623    cursor_anchor: Anchor,
 1624    cursor_position: Point,
 1625    scroll_anchor: ScrollAnchor,
 1626    scroll_top_row: u32,
 1627}
 1628
 1629#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1630pub enum GotoDefinitionKind {
 1631    Symbol,
 1632    Declaration,
 1633    Type,
 1634    Implementation,
 1635}
 1636
 1637pub enum FormatTarget {
 1638    Buffers(HashSet<Entity<Buffer>>),
 1639    Ranges(Vec<Range<MultiBufferPoint>>),
 1640}
 1641
 1642pub(crate) struct FocusedBlock {
 1643    id: BlockId,
 1644    focus_handle: WeakFocusHandle,
 1645}
 1646
 1647#[derive(Clone, Debug)]
 1648enum JumpData {
 1649    MultiBufferRow {
 1650        row: MultiBufferRow,
 1651        line_offset_from_top: u32,
 1652    },
 1653    MultiBufferPoint {
 1654        excerpt_id: ExcerptId,
 1655        position: Point,
 1656        anchor: text::Anchor,
 1657        line_offset_from_top: u32,
 1658    },
 1659}
 1660
 1661pub enum MultibufferSelectionMode {
 1662    First,
 1663    All,
 1664}
 1665
 1666#[derive(Clone, Copy, Debug, Default)]
 1667pub struct RewrapOptions {
 1668    pub override_language_settings: bool,
 1669    pub preserve_existing_whitespace: bool,
 1670}
 1671
 1672impl Editor {
 1673    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1680        let buffer = cx.new(|cx| Buffer::local("", cx));
 1681        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1682        Self::new(EditorMode::full(), buffer, None, window, cx)
 1683    }
 1684
 1685    pub fn auto_height(
 1686        min_lines: usize,
 1687        max_lines: usize,
 1688        window: &mut Window,
 1689        cx: &mut Context<Self>,
 1690    ) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(
 1694            EditorMode::AutoHeight {
 1695                min_lines,
 1696                max_lines: Some(max_lines),
 1697            },
 1698            buffer,
 1699            None,
 1700            window,
 1701            cx,
 1702        )
 1703    }
 1704
 1705    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1706    /// The editor grows as tall as needed to fit its content.
 1707    pub fn auto_height_unbounded(
 1708        min_lines: usize,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| Buffer::local("", cx));
 1713        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1714        Self::new(
 1715            EditorMode::AutoHeight {
 1716                min_lines,
 1717                max_lines: None,
 1718            },
 1719            buffer,
 1720            None,
 1721            window,
 1722            cx,
 1723        )
 1724    }
 1725
 1726    pub fn for_buffer(
 1727        buffer: Entity<Buffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn for_multibuffer(
 1737        buffer: Entity<MultiBuffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        Self::new(EditorMode::full(), buffer, project, window, cx)
 1743    }
 1744
 1745    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1746        let mut clone = Self::new(
 1747            self.mode.clone(),
 1748            self.buffer.clone(),
 1749            self.project.clone(),
 1750            window,
 1751            cx,
 1752        );
 1753        self.display_map.update(cx, |display_map, cx| {
 1754            let snapshot = display_map.snapshot(cx);
 1755            clone.display_map.update(cx, |display_map, cx| {
 1756                display_map.set_state(&snapshot, cx);
 1757            });
 1758        });
 1759        clone.folds_did_change(cx);
 1760        clone.selections.clone_state(&self.selections);
 1761        clone.scroll_manager.clone_state(&self.scroll_manager);
 1762        clone.searchable = self.searchable;
 1763        clone.read_only = self.read_only;
 1764        clone
 1765    }
 1766
 1767    pub fn new(
 1768        mode: EditorMode,
 1769        buffer: Entity<MultiBuffer>,
 1770        project: Option<Entity<Project>>,
 1771        window: &mut Window,
 1772        cx: &mut Context<Self>,
 1773    ) -> Self {
 1774        Editor::new_internal(mode, buffer, project, None, window, cx)
 1775    }
 1776
 1777    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1778        let multi_buffer = self.buffer().read(cx);
 1779        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1780        let multi_buffer_visible_start = self
 1781            .scroll_manager
 1782            .anchor()
 1783            .anchor
 1784            .to_point(&multi_buffer_snapshot);
 1785        let max_row = multi_buffer_snapshot.max_point().row;
 1786
 1787        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1788        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1789
 1790        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1791            let outline_items = buffer
 1792                .outline_items_containing(
 1793                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1794                    true,
 1795                    self.style().map(|style| style.syntax.as_ref()),
 1796                )
 1797                .into_iter()
 1798                .map(|outline_item| OutlineItem {
 1799                    depth: outline_item.depth,
 1800                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1801                    source_range_for_text: Anchor::range_in_buffer(
 1802                        *excerpt_id,
 1803                        outline_item.source_range_for_text,
 1804                    ),
 1805                    text: outline_item.text,
 1806                    highlight_ranges: outline_item.highlight_ranges,
 1807                    name_ranges: outline_item.name_ranges,
 1808                    body_range: outline_item
 1809                        .body_range
 1810                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1811                    annotation_range: outline_item
 1812                        .annotation_range
 1813                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1814                });
 1815            return Some(outline_items.collect());
 1816        }
 1817
 1818        None
 1819    }
 1820
 1821    fn new_internal(
 1822        mode: EditorMode,
 1823        multi_buffer: Entity<MultiBuffer>,
 1824        project: Option<Entity<Project>>,
 1825        display_map: Option<Entity<DisplayMap>>,
 1826        window: &mut Window,
 1827        cx: &mut Context<Self>,
 1828    ) -> Self {
 1829        debug_assert!(
 1830            display_map.is_none() || mode.is_minimap(),
 1831            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1832        );
 1833
 1834        let full_mode = mode.is_full();
 1835        let is_minimap = mode.is_minimap();
 1836        let diagnostics_max_severity = if full_mode {
 1837            EditorSettings::get_global(cx)
 1838                .diagnostics_max_severity
 1839                .unwrap_or(DiagnosticSeverity::Hint)
 1840        } else {
 1841            DiagnosticSeverity::Off
 1842        };
 1843        let style = window.text_style();
 1844        let font_size = style.font_size.to_pixels(window.rem_size());
 1845        let editor = cx.entity().downgrade();
 1846        let fold_placeholder = FoldPlaceholder {
 1847            constrain_width: false,
 1848            render: Arc::new(move |fold_id, fold_range, cx| {
 1849                let editor = editor.clone();
 1850                div()
 1851                    .id(fold_id)
 1852                    .bg(cx.theme().colors().ghost_element_background)
 1853                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1854                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1855                    .rounded_xs()
 1856                    .size_full()
 1857                    .cursor_pointer()
 1858                    .child("")
 1859                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1860                    .on_click(move |_, _window, cx| {
 1861                        editor
 1862                            .update(cx, |editor, cx| {
 1863                                editor.unfold_ranges(
 1864                                    &[fold_range.start..fold_range.end],
 1865                                    true,
 1866                                    false,
 1867                                    cx,
 1868                                );
 1869                                cx.stop_propagation();
 1870                            })
 1871                            .ok();
 1872                    })
 1873                    .into_any()
 1874            }),
 1875            merge_adjacent: true,
 1876            ..FoldPlaceholder::default()
 1877        };
 1878        let display_map = display_map.unwrap_or_else(|| {
 1879            cx.new(|cx| {
 1880                DisplayMap::new(
 1881                    multi_buffer.clone(),
 1882                    style.font(),
 1883                    font_size,
 1884                    None,
 1885                    FILE_HEADER_HEIGHT,
 1886                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1887                    fold_placeholder,
 1888                    diagnostics_max_severity,
 1889                    cx,
 1890                )
 1891            })
 1892        });
 1893
 1894        let selections = SelectionsCollection::new();
 1895
 1896        let blink_manager = cx.new(|cx| {
 1897            let mut blink_manager = BlinkManager::new(
 1898                CURSOR_BLINK_INTERVAL,
 1899                |cx| EditorSettings::get_global(cx).cursor_blink,
 1900                cx,
 1901            );
 1902            if is_minimap {
 1903                blink_manager.disable(cx);
 1904            }
 1905            blink_manager
 1906        });
 1907
 1908        let soft_wrap_mode_override =
 1909            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1910
 1911        let mut project_subscriptions = Vec::new();
 1912        if full_mode && let Some(project) = project.as_ref() {
 1913            project_subscriptions.push(cx.subscribe_in(
 1914                project,
 1915                window,
 1916                |editor, _, event, window, cx| match event {
 1917                    project::Event::RefreshCodeLens => {
 1918                        // we always query lens with actions, without storing them, always refreshing them
 1919                    }
 1920                    project::Event::RefreshInlayHints {
 1921                        server_id,
 1922                        request_id,
 1923                    } => {
 1924                        editor.refresh_inlay_hints(
 1925                            InlayHintRefreshReason::RefreshRequested {
 1926                                server_id: *server_id,
 1927                                request_id: *request_id,
 1928                            },
 1929                            cx,
 1930                        );
 1931                    }
 1932                    project::Event::LanguageServerRemoved(..) => {
 1933                        if editor.tasks_update_task.is_none() {
 1934                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1935                        }
 1936                        editor.registered_buffers.clear();
 1937                        editor.register_visible_buffers(cx);
 1938                    }
 1939                    project::Event::LanguageServerAdded(..) => {
 1940                        if editor.tasks_update_task.is_none() {
 1941                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1942                        }
 1943                    }
 1944                    project::Event::SnippetEdit(id, snippet_edits) => {
 1945                        // todo(lw): Non singletons
 1946                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1947                            let snapshot = buffer.read(cx).snapshot();
 1948                            let focus_handle = editor.focus_handle(cx);
 1949                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1950                                for (range, snippet) in snippet_edits {
 1951                                    let buffer_range =
 1952                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1953                                    editor
 1954                                        .insert_snippet(
 1955                                            &[MultiBufferOffset(buffer_range.start)
 1956                                                ..MultiBufferOffset(buffer_range.end)],
 1957                                            snippet.clone(),
 1958                                            window,
 1959                                            cx,
 1960                                        )
 1961                                        .ok();
 1962                                }
 1963                            }
 1964                        }
 1965                    }
 1966                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1967                        let buffer_id = *buffer_id;
 1968                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1969                            editor.register_buffer(buffer_id, cx);
 1970                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1971                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1972                            refresh_linked_ranges(editor, window, cx);
 1973                            editor.refresh_code_actions(window, cx);
 1974                            editor.refresh_document_highlights(cx);
 1975                        }
 1976                    }
 1977
 1978                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1979                        let Some(workspace) = editor.workspace() else {
 1980                            return;
 1981                        };
 1982                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1983                        else {
 1984                            return;
 1985                        };
 1986
 1987                        if active_editor.entity_id() == cx.entity_id() {
 1988                            let entity_id = cx.entity_id();
 1989                            workspace.update(cx, |this, cx| {
 1990                                this.panes_mut()
 1991                                    .iter_mut()
 1992                                    .filter(|pane| pane.entity_id() != entity_id)
 1993                                    .for_each(|p| {
 1994                                        p.update(cx, |pane, _| {
 1995                                            pane.nav_history_mut().rename_item(
 1996                                                entity_id,
 1997                                                project_path.clone(),
 1998                                                abs_path.clone().into(),
 1999                                            );
 2000                                        })
 2001                                    });
 2002                            });
 2003                            let edited_buffers_already_open = {
 2004                                let other_editors: Vec<Entity<Editor>> = workspace
 2005                                    .read(cx)
 2006                                    .panes()
 2007                                    .iter()
 2008                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2009                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2010                                    .collect();
 2011
 2012                                transaction.0.keys().all(|buffer| {
 2013                                    other_editors.iter().any(|editor| {
 2014                                        let multi_buffer = editor.read(cx).buffer();
 2015                                        multi_buffer.read(cx).is_singleton()
 2016                                            && multi_buffer.read(cx).as_singleton().map_or(
 2017                                                false,
 2018                                                |singleton| {
 2019                                                    singleton.entity_id() == buffer.entity_id()
 2020                                                },
 2021                                            )
 2022                                    })
 2023                                })
 2024                            };
 2025                            if !edited_buffers_already_open {
 2026                                let workspace = workspace.downgrade();
 2027                                let transaction = transaction.clone();
 2028                                cx.defer_in(window, move |_, window, cx| {
 2029                                    cx.spawn_in(window, async move |editor, cx| {
 2030                                        Self::open_project_transaction(
 2031                                            &editor,
 2032                                            workspace,
 2033                                            transaction,
 2034                                            "Rename".to_string(),
 2035                                            cx,
 2036                                        )
 2037                                        .await
 2038                                        .ok()
 2039                                    })
 2040                                    .detach();
 2041                                });
 2042                            }
 2043                        }
 2044                    }
 2045
 2046                    _ => {}
 2047                },
 2048            ));
 2049            if let Some(task_inventory) = project
 2050                .read(cx)
 2051                .task_store()
 2052                .read(cx)
 2053                .task_inventory()
 2054                .cloned()
 2055            {
 2056                project_subscriptions.push(cx.observe_in(
 2057                    &task_inventory,
 2058                    window,
 2059                    |editor, _, window, cx| {
 2060                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2061                    },
 2062                ));
 2063            };
 2064
 2065            project_subscriptions.push(cx.subscribe_in(
 2066                &project.read(cx).breakpoint_store(),
 2067                window,
 2068                |editor, _, event, window, cx| match event {
 2069                    BreakpointStoreEvent::ClearDebugLines => {
 2070                        editor.clear_row_highlights::<ActiveDebugLine>();
 2071                        editor.refresh_inline_values(cx);
 2072                    }
 2073                    BreakpointStoreEvent::SetDebugLine => {
 2074                        if editor.go_to_active_debug_line(window, cx) {
 2075                            cx.stop_propagation();
 2076                        }
 2077
 2078                        editor.refresh_inline_values(cx);
 2079                    }
 2080                    _ => {}
 2081                },
 2082            ));
 2083            let git_store = project.read(cx).git_store().clone();
 2084            let project = project.clone();
 2085            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2086                if let GitStoreEvent::RepositoryAdded = event {
 2087                    this.load_diff_task = Some(
 2088                        update_uncommitted_diff_for_buffer(
 2089                            cx.entity(),
 2090                            &project,
 2091                            this.buffer.read(cx).all_buffers(),
 2092                            this.buffer.clone(),
 2093                            cx,
 2094                        )
 2095                        .shared(),
 2096                    );
 2097                }
 2098            }));
 2099        }
 2100
 2101        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2102
 2103        let inlay_hint_settings =
 2104            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2105        let focus_handle = cx.focus_handle();
 2106        if !is_minimap {
 2107            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2108                .detach();
 2109            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2110                .detach();
 2111            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2112                .detach();
 2113            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2114                .detach();
 2115            cx.observe_pending_input(window, Self::observe_pending_input)
 2116                .detach();
 2117        }
 2118
 2119        let show_indent_guides =
 2120            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2121                Some(false)
 2122            } else {
 2123                None
 2124            };
 2125
 2126        let breakpoint_store = match (&mode, project.as_ref()) {
 2127            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2128            _ => None,
 2129        };
 2130
 2131        let mut code_action_providers = Vec::new();
 2132        let mut load_uncommitted_diff = None;
 2133        if let Some(project) = project.clone() {
 2134            load_uncommitted_diff = Some(
 2135                update_uncommitted_diff_for_buffer(
 2136                    cx.entity(),
 2137                    &project,
 2138                    multi_buffer.read(cx).all_buffers(),
 2139                    multi_buffer.clone(),
 2140                    cx,
 2141                )
 2142                .shared(),
 2143            );
 2144            code_action_providers.push(Rc::new(project) as Rc<_>);
 2145        }
 2146
 2147        let mut editor = Self {
 2148            focus_handle,
 2149            show_cursor_when_unfocused: false,
 2150            last_focused_descendant: None,
 2151            buffer: multi_buffer.clone(),
 2152            display_map: display_map.clone(),
 2153            placeholder_display_map: None,
 2154            selections,
 2155            scroll_manager: ScrollManager::new(cx),
 2156            columnar_selection_state: None,
 2157            add_selections_state: None,
 2158            select_next_state: None,
 2159            select_prev_state: None,
 2160            selection_history: SelectionHistory::default(),
 2161            defer_selection_effects: false,
 2162            deferred_selection_effects_state: None,
 2163            autoclose_regions: Vec::new(),
 2164            snippet_stack: InvalidationStack::default(),
 2165            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2166            ime_transaction: None,
 2167            active_diagnostics: ActiveDiagnostic::None,
 2168            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2169            inline_diagnostics_update: Task::ready(()),
 2170            inline_diagnostics: Vec::new(),
 2171            soft_wrap_mode_override,
 2172            diagnostics_max_severity,
 2173            hard_wrap: None,
 2174            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2175            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2176            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2177            project,
 2178            blink_manager: blink_manager.clone(),
 2179            show_local_selections: true,
 2180            show_scrollbars: ScrollbarAxes {
 2181                horizontal: full_mode,
 2182                vertical: full_mode,
 2183            },
 2184            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2185            offset_content: !matches!(mode, EditorMode::SingleLine),
 2186            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2187            show_gutter: full_mode,
 2188            show_line_numbers: (!full_mode).then_some(false),
 2189            use_relative_line_numbers: None,
 2190            disable_expand_excerpt_buttons: !full_mode,
 2191            show_git_diff_gutter: None,
 2192            show_code_actions: None,
 2193            show_runnables: None,
 2194            show_breakpoints: None,
 2195            show_wrap_guides: None,
 2196            show_indent_guides,
 2197            highlight_order: 0,
 2198            highlighted_rows: HashMap::default(),
 2199            background_highlights: HashMap::default(),
 2200            gutter_highlights: HashMap::default(),
 2201            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2202            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2203            nav_history: None,
 2204            context_menu: RefCell::new(None),
 2205            context_menu_options: None,
 2206            mouse_context_menu: None,
 2207            completion_tasks: Vec::new(),
 2208            inline_blame_popover: None,
 2209            inline_blame_popover_show_task: None,
 2210            signature_help_state: SignatureHelpState::default(),
 2211            auto_signature_help: None,
 2212            find_all_references_task_sources: Vec::new(),
 2213            next_completion_id: 0,
 2214            next_inlay_id: 0,
 2215            code_action_providers,
 2216            available_code_actions: None,
 2217            code_actions_task: None,
 2218            quick_selection_highlight_task: None,
 2219            debounced_selection_highlight_task: None,
 2220            document_highlights_task: None,
 2221            linked_editing_range_task: None,
 2222            pending_rename: None,
 2223            searchable: !is_minimap,
 2224            cursor_shape: EditorSettings::get_global(cx)
 2225                .cursor_shape
 2226                .unwrap_or_default(),
 2227            current_line_highlight: None,
 2228            autoindent_mode: Some(AutoindentMode::EachLine),
 2229            collapse_matches: false,
 2230            workspace: None,
 2231            input_enabled: !is_minimap,
 2232            use_modal_editing: full_mode,
 2233            read_only: is_minimap,
 2234            use_autoclose: true,
 2235            use_auto_surround: true,
 2236            auto_replace_emoji_shortcode: false,
 2237            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2238            leader_id: None,
 2239            remote_id: None,
 2240            hover_state: HoverState::default(),
 2241            pending_mouse_down: None,
 2242            hovered_link_state: None,
 2243            edit_prediction_provider: None,
 2244            active_edit_prediction: None,
 2245            stale_edit_prediction_in_menu: None,
 2246            edit_prediction_preview: EditPredictionPreview::Inactive {
 2247                released_too_fast: false,
 2248            },
 2249            inline_diagnostics_enabled: full_mode,
 2250            diagnostics_enabled: full_mode,
 2251            word_completions_enabled: full_mode,
 2252            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2253            gutter_hovered: false,
 2254            pixel_position_of_newest_cursor: None,
 2255            last_bounds: None,
 2256            last_position_map: None,
 2257            expect_bounds_change: None,
 2258            gutter_dimensions: GutterDimensions::default(),
 2259            style: None,
 2260            show_cursor_names: false,
 2261            hovered_cursors: HashMap::default(),
 2262            next_editor_action_id: EditorActionId::default(),
 2263            editor_actions: Rc::default(),
 2264            edit_predictions_hidden_for_vim_mode: false,
 2265            show_edit_predictions_override: None,
 2266            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2267            edit_prediction_settings: EditPredictionSettings::Disabled,
 2268            edit_prediction_indent_conflict: false,
 2269            edit_prediction_requires_modifier_in_indent_conflict: true,
 2270            custom_context_menu: None,
 2271            show_git_blame_gutter: false,
 2272            show_git_blame_inline: false,
 2273            show_selection_menu: None,
 2274            show_git_blame_inline_delay_task: None,
 2275            git_blame_inline_enabled: full_mode
 2276                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2277            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2278            buffer_serialization: is_minimap.not().then(|| {
 2279                BufferSerialization::new(
 2280                    ProjectSettings::get_global(cx)
 2281                        .session
 2282                        .restore_unsaved_buffers,
 2283                )
 2284            }),
 2285            blame: None,
 2286            blame_subscription: None,
 2287            tasks: BTreeMap::default(),
 2288
 2289            breakpoint_store,
 2290            gutter_breakpoint_indicator: (None, None),
 2291            hovered_diff_hunk_row: None,
 2292            _subscriptions: (!is_minimap)
 2293                .then(|| {
 2294                    vec![
 2295                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2296                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2297                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2298                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2299                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2300                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2301                        cx.observe_window_activation(window, |editor, window, cx| {
 2302                            let active = window.is_window_active();
 2303                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2304                                if active {
 2305                                    blink_manager.enable(cx);
 2306                                } else {
 2307                                    blink_manager.disable(cx);
 2308                                }
 2309                            });
 2310                            if active {
 2311                                editor.show_mouse_cursor(cx);
 2312                            }
 2313                        }),
 2314                    ]
 2315                })
 2316                .unwrap_or_default(),
 2317            tasks_update_task: None,
 2318            pull_diagnostics_task: Task::ready(()),
 2319            colors: None,
 2320            refresh_colors_task: Task::ready(()),
 2321            inlay_hints: None,
 2322            next_color_inlay_id: 0,
 2323            post_scroll_update: Task::ready(()),
 2324            linked_edit_ranges: Default::default(),
 2325            in_project_search: false,
 2326            previous_search_ranges: None,
 2327            breadcrumb_header: None,
 2328            focused_block: None,
 2329            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2330            addons: HashMap::default(),
 2331            registered_buffers: HashMap::default(),
 2332            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2333            selection_mark_mode: false,
 2334            toggle_fold_multiple_buffers: Task::ready(()),
 2335            serialize_selections: Task::ready(()),
 2336            serialize_folds: Task::ready(()),
 2337            text_style_refinement: None,
 2338            load_diff_task: load_uncommitted_diff,
 2339            temporary_diff_override: false,
 2340            mouse_cursor_hidden: false,
 2341            minimap: None,
 2342            hide_mouse_mode: EditorSettings::get_global(cx)
 2343                .hide_mouse
 2344                .unwrap_or_default(),
 2345            change_list: ChangeList::new(),
 2346            mode,
 2347            selection_drag_state: SelectionDragState::None,
 2348            folding_newlines: Task::ready(()),
 2349            lookup_key: None,
 2350            select_next_is_case_sensitive: None,
 2351            applicable_language_settings: HashMap::default(),
 2352            accent_overrides: Vec::new(),
 2353            fetched_tree_sitter_chunks: HashMap::default(),
 2354            use_base_text_line_numbers: false,
 2355        };
 2356
 2357        if is_minimap {
 2358            return editor;
 2359        }
 2360
 2361        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2362        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2363
 2364        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2365            editor
 2366                ._subscriptions
 2367                .push(cx.observe(breakpoints, |_, _, cx| {
 2368                    cx.notify();
 2369                }));
 2370        }
 2371        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2372        editor._subscriptions.extend(project_subscriptions);
 2373
 2374        editor._subscriptions.push(cx.subscribe_in(
 2375            &cx.entity(),
 2376            window,
 2377            |editor, _, e: &EditorEvent, window, cx| match e {
 2378                EditorEvent::ScrollPositionChanged { local, .. } => {
 2379                    if *local {
 2380                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2381                        editor.inline_blame_popover.take();
 2382                        let new_anchor = editor.scroll_manager.anchor();
 2383                        let snapshot = editor.snapshot(window, cx);
 2384                        editor.update_restoration_data(cx, move |data| {
 2385                            data.scroll_position = (
 2386                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2387                                new_anchor.offset,
 2388                            );
 2389                        });
 2390
 2391                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2392                            cx.background_executor()
 2393                                .timer(Duration::from_millis(50))
 2394                                .await;
 2395                            editor
 2396                                .update_in(cx, |editor, window, cx| {
 2397                                    editor.register_visible_buffers(cx);
 2398                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2399                                    editor.refresh_inlay_hints(
 2400                                        InlayHintRefreshReason::NewLinesShown,
 2401                                        cx,
 2402                                    );
 2403                                    editor.colorize_brackets(false, cx);
 2404                                })
 2405                                .ok();
 2406                        });
 2407                    }
 2408                }
 2409                EditorEvent::Edited { .. } => {
 2410                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2411                        .map(|vim_mode| vim_mode.0)
 2412                        .unwrap_or(false);
 2413                    if !vim_mode {
 2414                        let display_map = editor.display_snapshot(cx);
 2415                        let selections = editor.selections.all_adjusted_display(&display_map);
 2416                        let pop_state = editor
 2417                            .change_list
 2418                            .last()
 2419                            .map(|previous| {
 2420                                previous.len() == selections.len()
 2421                                    && previous.iter().enumerate().all(|(ix, p)| {
 2422                                        p.to_display_point(&display_map).row()
 2423                                            == selections[ix].head().row()
 2424                                    })
 2425                            })
 2426                            .unwrap_or(false);
 2427                        let new_positions = selections
 2428                            .into_iter()
 2429                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2430                            .collect();
 2431                        editor
 2432                            .change_list
 2433                            .push_to_change_list(pop_state, new_positions);
 2434                    }
 2435                }
 2436                _ => (),
 2437            },
 2438        ));
 2439
 2440        if let Some(dap_store) = editor
 2441            .project
 2442            .as_ref()
 2443            .map(|project| project.read(cx).dap_store())
 2444        {
 2445            let weak_editor = cx.weak_entity();
 2446
 2447            editor
 2448                ._subscriptions
 2449                .push(
 2450                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2451                        let session_entity = cx.entity();
 2452                        weak_editor
 2453                            .update(cx, |editor, cx| {
 2454                                editor._subscriptions.push(
 2455                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2456                                );
 2457                            })
 2458                            .ok();
 2459                    }),
 2460                );
 2461
 2462            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2463                editor
 2464                    ._subscriptions
 2465                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2466            }
 2467        }
 2468
 2469        // skip adding the initial selection to selection history
 2470        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2471        editor.end_selection(window, cx);
 2472        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2473
 2474        editor.scroll_manager.show_scrollbars(window, cx);
 2475        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2476
 2477        if full_mode {
 2478            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2479            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2480
 2481            if editor.git_blame_inline_enabled {
 2482                editor.start_git_blame_inline(false, window, cx);
 2483            }
 2484
 2485            editor.go_to_active_debug_line(window, cx);
 2486
 2487            editor.minimap =
 2488                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2489            editor.colors = Some(LspColorData::new(cx));
 2490            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2491
 2492            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2493                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2494            }
 2495            editor.update_lsp_data(None, window, cx);
 2496            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2497        }
 2498
 2499        editor
 2500    }
 2501
 2502    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2503        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2504    }
 2505
 2506    pub fn deploy_mouse_context_menu(
 2507        &mut self,
 2508        position: gpui::Point<Pixels>,
 2509        context_menu: Entity<ContextMenu>,
 2510        window: &mut Window,
 2511        cx: &mut Context<Self>,
 2512    ) {
 2513        self.mouse_context_menu = Some(MouseContextMenu::new(
 2514            self,
 2515            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2516            context_menu,
 2517            window,
 2518            cx,
 2519        ));
 2520    }
 2521
 2522    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2523        self.mouse_context_menu
 2524            .as_ref()
 2525            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2526    }
 2527
 2528    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2529        if self
 2530            .selections
 2531            .pending_anchor()
 2532            .is_some_and(|pending_selection| {
 2533                let snapshot = self.buffer().read(cx).snapshot(cx);
 2534                pending_selection.range().includes(range, &snapshot)
 2535            })
 2536        {
 2537            return true;
 2538        }
 2539
 2540        self.selections
 2541            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2542            .into_iter()
 2543            .any(|selection| {
 2544                // This is needed to cover a corner case, if we just check for an existing
 2545                // selection in the fold range, having a cursor at the start of the fold
 2546                // marks it as selected. Non-empty selections don't cause this.
 2547                let length = selection.end - selection.start;
 2548                length > 0
 2549            })
 2550    }
 2551
 2552    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2553        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2554    }
 2555
 2556    fn key_context_internal(
 2557        &self,
 2558        has_active_edit_prediction: bool,
 2559        window: &mut Window,
 2560        cx: &mut App,
 2561    ) -> KeyContext {
 2562        let mut key_context = KeyContext::new_with_defaults();
 2563        key_context.add("Editor");
 2564        let mode = match self.mode {
 2565            EditorMode::SingleLine => "single_line",
 2566            EditorMode::AutoHeight { .. } => "auto_height",
 2567            EditorMode::Minimap { .. } => "minimap",
 2568            EditorMode::Full { .. } => "full",
 2569        };
 2570
 2571        if EditorSettings::jupyter_enabled(cx) {
 2572            key_context.add("jupyter");
 2573        }
 2574
 2575        key_context.set("mode", mode);
 2576        if self.pending_rename.is_some() {
 2577            key_context.add("renaming");
 2578        }
 2579
 2580        if let Some(snippet_stack) = self.snippet_stack.last() {
 2581            key_context.add("in_snippet");
 2582
 2583            if snippet_stack.active_index > 0 {
 2584                key_context.add("has_previous_tabstop");
 2585            }
 2586
 2587            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2588                key_context.add("has_next_tabstop");
 2589            }
 2590        }
 2591
 2592        match self.context_menu.borrow().as_ref() {
 2593            Some(CodeContextMenu::Completions(menu)) => {
 2594                if menu.visible() {
 2595                    key_context.add("menu");
 2596                    key_context.add("showing_completions");
 2597                }
 2598            }
 2599            Some(CodeContextMenu::CodeActions(menu)) => {
 2600                if menu.visible() {
 2601                    key_context.add("menu");
 2602                    key_context.add("showing_code_actions")
 2603                }
 2604            }
 2605            None => {}
 2606        }
 2607
 2608        if self.signature_help_state.has_multiple_signatures() {
 2609            key_context.add("showing_signature_help");
 2610        }
 2611
 2612        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2613        if !self.focus_handle(cx).contains_focused(window, cx)
 2614            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2615        {
 2616            for addon in self.addons.values() {
 2617                addon.extend_key_context(&mut key_context, cx)
 2618            }
 2619        }
 2620
 2621        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2622            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2623                Some(
 2624                    file.full_path(cx)
 2625                        .extension()?
 2626                        .to_string_lossy()
 2627                        .into_owned(),
 2628                )
 2629            }) {
 2630                key_context.set("extension", extension);
 2631            }
 2632        } else {
 2633            key_context.add("multibuffer");
 2634        }
 2635
 2636        if has_active_edit_prediction {
 2637            if self.edit_prediction_in_conflict() {
 2638                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2639            } else {
 2640                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2641                key_context.add("copilot_suggestion");
 2642            }
 2643        }
 2644
 2645        if self.selection_mark_mode {
 2646            key_context.add("selection_mode");
 2647        }
 2648
 2649        let disjoint = self.selections.disjoint_anchors();
 2650        let snapshot = self.snapshot(window, cx);
 2651        let snapshot = snapshot.buffer_snapshot();
 2652        if self.mode == EditorMode::SingleLine
 2653            && let [selection] = disjoint
 2654            && selection.start == selection.end
 2655            && selection.end.to_offset(snapshot) == snapshot.len()
 2656        {
 2657            key_context.add("end_of_input");
 2658        }
 2659
 2660        if self.has_any_expanded_diff_hunks(cx) {
 2661            key_context.add("diffs_expanded");
 2662        }
 2663
 2664        key_context
 2665    }
 2666
 2667    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2668        self.last_bounds.as_ref()
 2669    }
 2670
 2671    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2672        if self.mouse_cursor_hidden {
 2673            self.mouse_cursor_hidden = false;
 2674            cx.notify();
 2675        }
 2676    }
 2677
 2678    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2679        let hide_mouse_cursor = match origin {
 2680            HideMouseCursorOrigin::TypingAction => {
 2681                matches!(
 2682                    self.hide_mouse_mode,
 2683                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2684                )
 2685            }
 2686            HideMouseCursorOrigin::MovementAction => {
 2687                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2688            }
 2689        };
 2690        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2691            self.mouse_cursor_hidden = hide_mouse_cursor;
 2692            cx.notify();
 2693        }
 2694    }
 2695
 2696    pub fn edit_prediction_in_conflict(&self) -> bool {
 2697        if !self.show_edit_predictions_in_menu() {
 2698            return false;
 2699        }
 2700
 2701        let showing_completions = self
 2702            .context_menu
 2703            .borrow()
 2704            .as_ref()
 2705            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2706
 2707        showing_completions
 2708            || self.edit_prediction_requires_modifier()
 2709            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2710            // bindings to insert tab characters.
 2711            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2712    }
 2713
 2714    pub fn accept_edit_prediction_keybind(
 2715        &self,
 2716        accept_partial: bool,
 2717        window: &mut Window,
 2718        cx: &mut App,
 2719    ) -> AcceptEditPredictionBinding {
 2720        let key_context = self.key_context_internal(true, window, cx);
 2721        let in_conflict = self.edit_prediction_in_conflict();
 2722
 2723        let bindings = if accept_partial {
 2724            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2725        } else {
 2726            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2727        };
 2728
 2729        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2730        // just the first one.
 2731        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2732            !in_conflict
 2733                || binding
 2734                    .keystrokes()
 2735                    .first()
 2736                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2737        }))
 2738    }
 2739
 2740    pub fn new_file(
 2741        workspace: &mut Workspace,
 2742        _: &workspace::NewFile,
 2743        window: &mut Window,
 2744        cx: &mut Context<Workspace>,
 2745    ) {
 2746        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2747            "Failed to create buffer",
 2748            window,
 2749            cx,
 2750            |e, _, _| match e.error_code() {
 2751                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2752                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2753                e.error_tag("required").unwrap_or("the latest version")
 2754            )),
 2755                _ => None,
 2756            },
 2757        );
 2758    }
 2759
 2760    pub fn new_in_workspace(
 2761        workspace: &mut Workspace,
 2762        window: &mut Window,
 2763        cx: &mut Context<Workspace>,
 2764    ) -> Task<Result<Entity<Editor>>> {
 2765        let project = workspace.project().clone();
 2766        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2767
 2768        cx.spawn_in(window, async move |workspace, cx| {
 2769            let buffer = create.await?;
 2770            workspace.update_in(cx, |workspace, window, cx| {
 2771                let editor =
 2772                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2773                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2774                editor
 2775            })
 2776        })
 2777    }
 2778
 2779    fn new_file_vertical(
 2780        workspace: &mut Workspace,
 2781        _: &workspace::NewFileSplitVertical,
 2782        window: &mut Window,
 2783        cx: &mut Context<Workspace>,
 2784    ) {
 2785        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2786    }
 2787
 2788    fn new_file_horizontal(
 2789        workspace: &mut Workspace,
 2790        _: &workspace::NewFileSplitHorizontal,
 2791        window: &mut Window,
 2792        cx: &mut Context<Workspace>,
 2793    ) {
 2794        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2795    }
 2796
 2797    fn new_file_split(
 2798        workspace: &mut Workspace,
 2799        action: &workspace::NewFileSplit,
 2800        window: &mut Window,
 2801        cx: &mut Context<Workspace>,
 2802    ) {
 2803        Self::new_file_in_direction(workspace, action.0, window, cx)
 2804    }
 2805
 2806    fn new_file_in_direction(
 2807        workspace: &mut Workspace,
 2808        direction: SplitDirection,
 2809        window: &mut Window,
 2810        cx: &mut Context<Workspace>,
 2811    ) {
 2812        let project = workspace.project().clone();
 2813        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2814
 2815        cx.spawn_in(window, async move |workspace, cx| {
 2816            let buffer = create.await?;
 2817            workspace.update_in(cx, move |workspace, window, cx| {
 2818                workspace.split_item(
 2819                    direction,
 2820                    Box::new(
 2821                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2822                    ),
 2823                    window,
 2824                    cx,
 2825                )
 2826            })?;
 2827            anyhow::Ok(())
 2828        })
 2829        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2830            match e.error_code() {
 2831                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2832                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2833                e.error_tag("required").unwrap_or("the latest version")
 2834            )),
 2835                _ => None,
 2836            }
 2837        });
 2838    }
 2839
 2840    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2841        self.leader_id
 2842    }
 2843
 2844    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2845        &self.buffer
 2846    }
 2847
 2848    pub fn project(&self) -> Option<&Entity<Project>> {
 2849        self.project.as_ref()
 2850    }
 2851
 2852    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2853        self.workspace.as_ref()?.0.upgrade()
 2854    }
 2855
 2856    /// Returns the workspace serialization ID if this editor should be serialized.
 2857    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2858        self.workspace
 2859            .as_ref()
 2860            .filter(|_| self.should_serialize_buffer())
 2861            .and_then(|workspace| workspace.1)
 2862    }
 2863
 2864    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2865        self.buffer().read(cx).title(cx)
 2866    }
 2867
 2868    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2869        let git_blame_gutter_max_author_length = self
 2870            .render_git_blame_gutter(cx)
 2871            .then(|| {
 2872                if let Some(blame) = self.blame.as_ref() {
 2873                    let max_author_length =
 2874                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2875                    Some(max_author_length)
 2876                } else {
 2877                    None
 2878                }
 2879            })
 2880            .flatten();
 2881
 2882        EditorSnapshot {
 2883            mode: self.mode.clone(),
 2884            show_gutter: self.show_gutter,
 2885            show_line_numbers: self.show_line_numbers,
 2886            show_git_diff_gutter: self.show_git_diff_gutter,
 2887            show_code_actions: self.show_code_actions,
 2888            show_runnables: self.show_runnables,
 2889            show_breakpoints: self.show_breakpoints,
 2890            git_blame_gutter_max_author_length,
 2891            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2892            placeholder_display_snapshot: self
 2893                .placeholder_display_map
 2894                .as_ref()
 2895                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2896            scroll_anchor: self.scroll_manager.anchor(),
 2897            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2898            is_focused: self.focus_handle.is_focused(window),
 2899            current_line_highlight: self
 2900                .current_line_highlight
 2901                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2902            gutter_hovered: self.gutter_hovered,
 2903        }
 2904    }
 2905
 2906    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2907        self.buffer.read(cx).language_at(point, cx)
 2908    }
 2909
 2910    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2911        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2912    }
 2913
 2914    pub fn active_excerpt(
 2915        &self,
 2916        cx: &App,
 2917    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2918        self.buffer
 2919            .read(cx)
 2920            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2921    }
 2922
 2923    pub fn mode(&self) -> &EditorMode {
 2924        &self.mode
 2925    }
 2926
 2927    pub fn set_mode(&mut self, mode: EditorMode) {
 2928        self.mode = mode;
 2929    }
 2930
 2931    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2932        self.collaboration_hub.as_deref()
 2933    }
 2934
 2935    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2936        self.collaboration_hub = Some(hub);
 2937    }
 2938
 2939    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2940        self.in_project_search = in_project_search;
 2941    }
 2942
 2943    pub fn set_custom_context_menu(
 2944        &mut self,
 2945        f: impl 'static
 2946        + Fn(
 2947            &mut Self,
 2948            DisplayPoint,
 2949            &mut Window,
 2950            &mut Context<Self>,
 2951        ) -> Option<Entity<ui::ContextMenu>>,
 2952    ) {
 2953        self.custom_context_menu = Some(Box::new(f))
 2954    }
 2955
 2956    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2957        self.completion_provider = provider;
 2958    }
 2959
 2960    #[cfg(any(test, feature = "test-support"))]
 2961    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2962        self.completion_provider.clone()
 2963    }
 2964
 2965    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2966        self.semantics_provider.clone()
 2967    }
 2968
 2969    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2970        self.semantics_provider = provider;
 2971    }
 2972
 2973    pub fn set_edit_prediction_provider<T>(
 2974        &mut self,
 2975        provider: Option<Entity<T>>,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) where
 2979        T: EditPredictionProvider,
 2980    {
 2981        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2982            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2983                if this.focus_handle.is_focused(window) {
 2984                    this.update_visible_edit_prediction(window, cx);
 2985                }
 2986            }),
 2987            provider: Arc::new(provider),
 2988        });
 2989        self.update_edit_prediction_settings(cx);
 2990        self.refresh_edit_prediction(false, false, window, cx);
 2991    }
 2992
 2993    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2994        self.placeholder_display_map
 2995            .as_ref()
 2996            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2997    }
 2998
 2999    pub fn set_placeholder_text(
 3000        &mut self,
 3001        placeholder_text: &str,
 3002        window: &mut Window,
 3003        cx: &mut Context<Self>,
 3004    ) {
 3005        let multibuffer = cx
 3006            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3007
 3008        let style = window.text_style();
 3009
 3010        self.placeholder_display_map = Some(cx.new(|cx| {
 3011            DisplayMap::new(
 3012                multibuffer,
 3013                style.font(),
 3014                style.font_size.to_pixels(window.rem_size()),
 3015                None,
 3016                FILE_HEADER_HEIGHT,
 3017                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3018                Default::default(),
 3019                DiagnosticSeverity::Off,
 3020                cx,
 3021            )
 3022        }));
 3023        cx.notify();
 3024    }
 3025
 3026    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3027        self.cursor_shape = cursor_shape;
 3028
 3029        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3030        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3031
 3032        cx.notify();
 3033    }
 3034
 3035    pub fn cursor_shape(&self) -> CursorShape {
 3036        self.cursor_shape
 3037    }
 3038
 3039    pub fn set_current_line_highlight(
 3040        &mut self,
 3041        current_line_highlight: Option<CurrentLineHighlight>,
 3042    ) {
 3043        self.current_line_highlight = current_line_highlight;
 3044    }
 3045
 3046    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3047        self.collapse_matches = collapse_matches;
 3048    }
 3049
 3050    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3051        if self.collapse_matches {
 3052            return range.start..range.start;
 3053        }
 3054        range.clone()
 3055    }
 3056
 3057    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3058        self.display_map.read(cx).clip_at_line_ends
 3059    }
 3060
 3061    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3062        if self.display_map.read(cx).clip_at_line_ends != clip {
 3063            self.display_map
 3064                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3065        }
 3066    }
 3067
 3068    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3069        self.input_enabled = input_enabled;
 3070    }
 3071
 3072    pub fn set_edit_predictions_hidden_for_vim_mode(
 3073        &mut self,
 3074        hidden: bool,
 3075        window: &mut Window,
 3076        cx: &mut Context<Self>,
 3077    ) {
 3078        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3079            self.edit_predictions_hidden_for_vim_mode = hidden;
 3080            if hidden {
 3081                self.update_visible_edit_prediction(window, cx);
 3082            } else {
 3083                self.refresh_edit_prediction(true, false, window, cx);
 3084            }
 3085        }
 3086    }
 3087
 3088    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3089        self.menu_edit_predictions_policy = value;
 3090    }
 3091
 3092    pub fn set_autoindent(&mut self, autoindent: bool) {
 3093        if autoindent {
 3094            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3095        } else {
 3096            self.autoindent_mode = None;
 3097        }
 3098    }
 3099
 3100    pub fn read_only(&self, cx: &App) -> bool {
 3101        self.read_only || self.buffer.read(cx).read_only()
 3102    }
 3103
 3104    pub fn set_read_only(&mut self, read_only: bool) {
 3105        self.read_only = read_only;
 3106    }
 3107
 3108    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3109        self.use_autoclose = autoclose;
 3110    }
 3111
 3112    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3113        self.use_auto_surround = auto_surround;
 3114    }
 3115
 3116    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3117        self.auto_replace_emoji_shortcode = auto_replace;
 3118    }
 3119
 3120    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3121        self.buffer_serialization = should_serialize.then(|| {
 3122            BufferSerialization::new(
 3123                ProjectSettings::get_global(cx)
 3124                    .session
 3125                    .restore_unsaved_buffers,
 3126            )
 3127        })
 3128    }
 3129
 3130    fn should_serialize_buffer(&self) -> bool {
 3131        self.buffer_serialization.is_some()
 3132    }
 3133
 3134    pub fn toggle_edit_predictions(
 3135        &mut self,
 3136        _: &ToggleEditPrediction,
 3137        window: &mut Window,
 3138        cx: &mut Context<Self>,
 3139    ) {
 3140        if self.show_edit_predictions_override.is_some() {
 3141            self.set_show_edit_predictions(None, window, cx);
 3142        } else {
 3143            let show_edit_predictions = !self.edit_predictions_enabled();
 3144            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3145        }
 3146    }
 3147
 3148    pub fn set_show_edit_predictions(
 3149        &mut self,
 3150        show_edit_predictions: Option<bool>,
 3151        window: &mut Window,
 3152        cx: &mut Context<Self>,
 3153    ) {
 3154        self.show_edit_predictions_override = show_edit_predictions;
 3155        self.update_edit_prediction_settings(cx);
 3156
 3157        if let Some(false) = show_edit_predictions {
 3158            self.discard_edit_prediction(false, cx);
 3159        } else {
 3160            self.refresh_edit_prediction(false, true, window, cx);
 3161        }
 3162    }
 3163
 3164    fn edit_predictions_disabled_in_scope(
 3165        &self,
 3166        buffer: &Entity<Buffer>,
 3167        buffer_position: language::Anchor,
 3168        cx: &App,
 3169    ) -> bool {
 3170        let snapshot = buffer.read(cx).snapshot();
 3171        let settings = snapshot.settings_at(buffer_position, cx);
 3172
 3173        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3174            return false;
 3175        };
 3176
 3177        scope.override_name().is_some_and(|scope_name| {
 3178            settings
 3179                .edit_predictions_disabled_in
 3180                .iter()
 3181                .any(|s| s == scope_name)
 3182        })
 3183    }
 3184
 3185    pub fn set_use_modal_editing(&mut self, to: bool) {
 3186        self.use_modal_editing = to;
 3187    }
 3188
 3189    pub fn use_modal_editing(&self) -> bool {
 3190        self.use_modal_editing
 3191    }
 3192
 3193    fn selections_did_change(
 3194        &mut self,
 3195        local: bool,
 3196        old_cursor_position: &Anchor,
 3197        effects: SelectionEffects,
 3198        window: &mut Window,
 3199        cx: &mut Context<Self>,
 3200    ) {
 3201        window.invalidate_character_coordinates();
 3202
 3203        // Copy selections to primary selection buffer
 3204        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3205        if local {
 3206            let selections = self
 3207                .selections
 3208                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3209            let buffer_handle = self.buffer.read(cx).read(cx);
 3210
 3211            let mut text = String::new();
 3212            for (index, selection) in selections.iter().enumerate() {
 3213                let text_for_selection = buffer_handle
 3214                    .text_for_range(selection.start..selection.end)
 3215                    .collect::<String>();
 3216
 3217                text.push_str(&text_for_selection);
 3218                if index != selections.len() - 1 {
 3219                    text.push('\n');
 3220                }
 3221            }
 3222
 3223            if !text.is_empty() {
 3224                cx.write_to_primary(ClipboardItem::new_string(text));
 3225            }
 3226        }
 3227
 3228        let selection_anchors = self.selections.disjoint_anchors_arc();
 3229
 3230        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3231            self.buffer.update(cx, |buffer, cx| {
 3232                buffer.set_active_selections(
 3233                    &selection_anchors,
 3234                    self.selections.line_mode(),
 3235                    self.cursor_shape,
 3236                    cx,
 3237                )
 3238            });
 3239        }
 3240        let display_map = self
 3241            .display_map
 3242            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3243        let buffer = display_map.buffer_snapshot();
 3244        if self.selections.count() == 1 {
 3245            self.add_selections_state = None;
 3246        }
 3247        self.select_next_state = None;
 3248        self.select_prev_state = None;
 3249        self.select_syntax_node_history.try_clear();
 3250        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3251        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3252        self.take_rename(false, window, cx);
 3253
 3254        let newest_selection = self.selections.newest_anchor();
 3255        let new_cursor_position = newest_selection.head();
 3256        let selection_start = newest_selection.start;
 3257
 3258        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3259            self.push_to_nav_history(
 3260                *old_cursor_position,
 3261                Some(new_cursor_position.to_point(buffer)),
 3262                false,
 3263                effects.nav_history == Some(true),
 3264                cx,
 3265            );
 3266        }
 3267
 3268        if local {
 3269            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3270                self.register_buffer(buffer_id, cx);
 3271            }
 3272
 3273            let mut context_menu = self.context_menu.borrow_mut();
 3274            let completion_menu = match context_menu.as_ref() {
 3275                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3276                Some(CodeContextMenu::CodeActions(_)) => {
 3277                    *context_menu = None;
 3278                    None
 3279                }
 3280                None => None,
 3281            };
 3282            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3283            drop(context_menu);
 3284
 3285            if effects.completions
 3286                && let Some(completion_position) = completion_position
 3287            {
 3288                let start_offset = selection_start.to_offset(buffer);
 3289                let position_matches = start_offset == completion_position.to_offset(buffer);
 3290                let continue_showing = if position_matches {
 3291                    if self.snippet_stack.is_empty() {
 3292                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3293                            == Some(CharKind::Word)
 3294                    } else {
 3295                        // Snippet choices can be shown even when the cursor is in whitespace.
 3296                        // Dismissing the menu with actions like backspace is handled by
 3297                        // invalidation regions.
 3298                        true
 3299                    }
 3300                } else {
 3301                    false
 3302                };
 3303
 3304                if continue_showing {
 3305                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3306                } else {
 3307                    self.hide_context_menu(window, cx);
 3308                }
 3309            }
 3310
 3311            hide_hover(self, cx);
 3312
 3313            if old_cursor_position.to_display_point(&display_map).row()
 3314                != new_cursor_position.to_display_point(&display_map).row()
 3315            {
 3316                self.available_code_actions.take();
 3317            }
 3318            self.refresh_code_actions(window, cx);
 3319            self.refresh_document_highlights(cx);
 3320            refresh_linked_ranges(self, window, cx);
 3321
 3322            self.refresh_selected_text_highlights(false, window, cx);
 3323            self.refresh_matching_bracket_highlights(window, cx);
 3324            self.update_visible_edit_prediction(window, cx);
 3325            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3326            self.inline_blame_popover.take();
 3327            if self.git_blame_inline_enabled {
 3328                self.start_inline_blame_timer(window, cx);
 3329            }
 3330        }
 3331
 3332        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3333        cx.emit(EditorEvent::SelectionsChanged { local });
 3334
 3335        let selections = &self.selections.disjoint_anchors_arc();
 3336        if selections.len() == 1 {
 3337            cx.emit(SearchEvent::ActiveMatchChanged)
 3338        }
 3339        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3340            let inmemory_selections = selections
 3341                .iter()
 3342                .map(|s| {
 3343                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3344                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3345                })
 3346                .collect();
 3347            self.update_restoration_data(cx, |data| {
 3348                data.selections = inmemory_selections;
 3349            });
 3350
 3351            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3352                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3353            {
 3354                let snapshot = self.buffer().read(cx).snapshot(cx);
 3355                let selections = selections.clone();
 3356                let background_executor = cx.background_executor().clone();
 3357                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3358                self.serialize_selections = cx.background_spawn(async move {
 3359                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3360                    let db_selections = selections
 3361                        .iter()
 3362                        .map(|selection| {
 3363                            (
 3364                                selection.start.to_offset(&snapshot).0,
 3365                                selection.end.to_offset(&snapshot).0,
 3366                            )
 3367                        })
 3368                        .collect();
 3369
 3370                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3371                        .await
 3372                        .with_context(|| {
 3373                            format!(
 3374                                "persisting editor selections for editor {editor_id}, \
 3375                                workspace {workspace_id:?}"
 3376                            )
 3377                        })
 3378                        .log_err();
 3379                });
 3380            }
 3381        }
 3382
 3383        cx.notify();
 3384    }
 3385
 3386    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3387        use text::ToOffset as _;
 3388        use text::ToPoint as _;
 3389
 3390        if self.mode.is_minimap()
 3391            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3392        {
 3393            return;
 3394        }
 3395
 3396        if !self.buffer().read(cx).is_singleton() {
 3397            return;
 3398        }
 3399
 3400        let display_snapshot = self
 3401            .display_map
 3402            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3403        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3404            return;
 3405        };
 3406        let inmemory_folds = display_snapshot
 3407            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3408            .map(|fold| {
 3409                fold.range.start.text_anchor.to_point(&snapshot)
 3410                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3411            })
 3412            .collect();
 3413        self.update_restoration_data(cx, |data| {
 3414            data.folds = inmemory_folds;
 3415        });
 3416
 3417        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3418            return;
 3419        };
 3420        let background_executor = cx.background_executor().clone();
 3421        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3422        let db_folds = display_snapshot
 3423            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3424            .map(|fold| {
 3425                (
 3426                    fold.range.start.text_anchor.to_offset(&snapshot),
 3427                    fold.range.end.text_anchor.to_offset(&snapshot),
 3428                )
 3429            })
 3430            .collect();
 3431        self.serialize_folds = cx.background_spawn(async move {
 3432            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3433            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3434                .await
 3435                .with_context(|| {
 3436                    format!(
 3437                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3438                    )
 3439                })
 3440                .log_err();
 3441        });
 3442    }
 3443
 3444    pub fn sync_selections(
 3445        &mut self,
 3446        other: Entity<Editor>,
 3447        cx: &mut Context<Self>,
 3448    ) -> gpui::Subscription {
 3449        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3450        if !other_selections.is_empty() {
 3451            self.selections
 3452                .change_with(&self.display_snapshot(cx), |selections| {
 3453                    selections.select_anchors(other_selections);
 3454                });
 3455        }
 3456
 3457        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3458            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3459                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3460                if other_selections.is_empty() {
 3461                    return;
 3462                }
 3463                let snapshot = this.display_snapshot(cx);
 3464                this.selections.change_with(&snapshot, |selections| {
 3465                    selections.select_anchors(other_selections);
 3466                });
 3467            }
 3468        });
 3469
 3470        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3471            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3472                let these_selections = this.selections.disjoint_anchors().to_vec();
 3473                if these_selections.is_empty() {
 3474                    return;
 3475                }
 3476                other.update(cx, |other_editor, cx| {
 3477                    let snapshot = other_editor.display_snapshot(cx);
 3478                    other_editor
 3479                        .selections
 3480                        .change_with(&snapshot, |selections| {
 3481                            selections.select_anchors(these_selections);
 3482                        })
 3483                });
 3484            }
 3485        });
 3486
 3487        Subscription::join(other_subscription, this_subscription)
 3488    }
 3489
 3490    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3491        if self.buffer().read(cx).is_singleton() {
 3492            return;
 3493        }
 3494        let snapshot = self.buffer.read(cx).snapshot(cx);
 3495        let buffer_ids: HashSet<BufferId> = self
 3496            .selections
 3497            .disjoint_anchor_ranges()
 3498            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3499            .collect();
 3500        for buffer_id in buffer_ids {
 3501            self.unfold_buffer(buffer_id, cx);
 3502        }
 3503    }
 3504
 3505    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3506    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3507    /// effects of selection change occur at the end of the transaction.
 3508    pub fn change_selections<R>(
 3509        &mut self,
 3510        effects: SelectionEffects,
 3511        window: &mut Window,
 3512        cx: &mut Context<Self>,
 3513        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3514    ) -> R {
 3515        let snapshot = self.display_snapshot(cx);
 3516        if let Some(state) = &mut self.deferred_selection_effects_state {
 3517            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3518            state.effects.completions = effects.completions;
 3519            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3520            let (changed, result) = self.selections.change_with(&snapshot, change);
 3521            state.changed |= changed;
 3522            return result;
 3523        }
 3524        let mut state = DeferredSelectionEffectsState {
 3525            changed: false,
 3526            effects,
 3527            old_cursor_position: self.selections.newest_anchor().head(),
 3528            history_entry: SelectionHistoryEntry {
 3529                selections: self.selections.disjoint_anchors_arc(),
 3530                select_next_state: self.select_next_state.clone(),
 3531                select_prev_state: self.select_prev_state.clone(),
 3532                add_selections_state: self.add_selections_state.clone(),
 3533            },
 3534        };
 3535        let (changed, result) = self.selections.change_with(&snapshot, change);
 3536        state.changed = state.changed || changed;
 3537        if self.defer_selection_effects {
 3538            self.deferred_selection_effects_state = Some(state);
 3539        } else {
 3540            self.apply_selection_effects(state, window, cx);
 3541        }
 3542        result
 3543    }
 3544
 3545    /// Defers the effects of selection change, so that the effects of multiple calls to
 3546    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3547    /// to selection history and the state of popovers based on selection position aren't
 3548    /// erroneously updated.
 3549    pub fn with_selection_effects_deferred<R>(
 3550        &mut self,
 3551        window: &mut Window,
 3552        cx: &mut Context<Self>,
 3553        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3554    ) -> R {
 3555        let already_deferred = self.defer_selection_effects;
 3556        self.defer_selection_effects = true;
 3557        let result = update(self, window, cx);
 3558        if !already_deferred {
 3559            self.defer_selection_effects = false;
 3560            if let Some(state) = self.deferred_selection_effects_state.take() {
 3561                self.apply_selection_effects(state, window, cx);
 3562            }
 3563        }
 3564        result
 3565    }
 3566
 3567    fn apply_selection_effects(
 3568        &mut self,
 3569        state: DeferredSelectionEffectsState,
 3570        window: &mut Window,
 3571        cx: &mut Context<Self>,
 3572    ) {
 3573        if state.changed {
 3574            self.selection_history.push(state.history_entry);
 3575
 3576            if let Some(autoscroll) = state.effects.scroll {
 3577                self.request_autoscroll(autoscroll, cx);
 3578            }
 3579
 3580            let old_cursor_position = &state.old_cursor_position;
 3581
 3582            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3583
 3584            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3585                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3586            }
 3587        }
 3588    }
 3589
 3590    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3591    where
 3592        I: IntoIterator<Item = (Range<S>, T)>,
 3593        S: ToOffset,
 3594        T: Into<Arc<str>>,
 3595    {
 3596        if self.read_only(cx) {
 3597            return;
 3598        }
 3599
 3600        self.buffer
 3601            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3602    }
 3603
 3604    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3605    where
 3606        I: IntoIterator<Item = (Range<S>, T)>,
 3607        S: ToOffset,
 3608        T: Into<Arc<str>>,
 3609    {
 3610        if self.read_only(cx) {
 3611            return;
 3612        }
 3613
 3614        self.buffer.update(cx, |buffer, cx| {
 3615            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3616        });
 3617    }
 3618
 3619    pub fn edit_with_block_indent<I, S, T>(
 3620        &mut self,
 3621        edits: I,
 3622        original_indent_columns: Vec<Option<u32>>,
 3623        cx: &mut Context<Self>,
 3624    ) where
 3625        I: IntoIterator<Item = (Range<S>, T)>,
 3626        S: ToOffset,
 3627        T: Into<Arc<str>>,
 3628    {
 3629        if self.read_only(cx) {
 3630            return;
 3631        }
 3632
 3633        self.buffer.update(cx, |buffer, cx| {
 3634            buffer.edit(
 3635                edits,
 3636                Some(AutoindentMode::Block {
 3637                    original_indent_columns,
 3638                }),
 3639                cx,
 3640            )
 3641        });
 3642    }
 3643
 3644    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3645        self.hide_context_menu(window, cx);
 3646
 3647        match phase {
 3648            SelectPhase::Begin {
 3649                position,
 3650                add,
 3651                click_count,
 3652            } => self.begin_selection(position, add, click_count, window, cx),
 3653            SelectPhase::BeginColumnar {
 3654                position,
 3655                goal_column,
 3656                reset,
 3657                mode,
 3658            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3659            SelectPhase::Extend {
 3660                position,
 3661                click_count,
 3662            } => self.extend_selection(position, click_count, window, cx),
 3663            SelectPhase::Update {
 3664                position,
 3665                goal_column,
 3666                scroll_delta,
 3667            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3668            SelectPhase::End => self.end_selection(window, cx),
 3669        }
 3670    }
 3671
 3672    fn extend_selection(
 3673        &mut self,
 3674        position: DisplayPoint,
 3675        click_count: usize,
 3676        window: &mut Window,
 3677        cx: &mut Context<Self>,
 3678    ) {
 3679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3680        let tail = self
 3681            .selections
 3682            .newest::<MultiBufferOffset>(&display_map)
 3683            .tail();
 3684        let click_count = click_count.max(match self.selections.select_mode() {
 3685            SelectMode::Character => 1,
 3686            SelectMode::Word(_) => 2,
 3687            SelectMode::Line(_) => 3,
 3688            SelectMode::All => 4,
 3689        });
 3690        self.begin_selection(position, false, click_count, window, cx);
 3691
 3692        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3693
 3694        let current_selection = match self.selections.select_mode() {
 3695            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3696            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3697        };
 3698
 3699        let mut pending_selection = self
 3700            .selections
 3701            .pending_anchor()
 3702            .cloned()
 3703            .expect("extend_selection not called with pending selection");
 3704
 3705        if pending_selection
 3706            .start
 3707            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3708            == Ordering::Greater
 3709        {
 3710            pending_selection.start = current_selection.start;
 3711        }
 3712        if pending_selection
 3713            .end
 3714            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3715            == Ordering::Less
 3716        {
 3717            pending_selection.end = current_selection.end;
 3718            pending_selection.reversed = true;
 3719        }
 3720
 3721        let mut pending_mode = self.selections.pending_mode().unwrap();
 3722        match &mut pending_mode {
 3723            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3724            _ => {}
 3725        }
 3726
 3727        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3728            SelectionEffects::scroll(Autoscroll::fit())
 3729        } else {
 3730            SelectionEffects::no_scroll()
 3731        };
 3732
 3733        self.change_selections(effects, window, cx, |s| {
 3734            s.set_pending(pending_selection.clone(), pending_mode);
 3735            s.set_is_extending(true);
 3736        });
 3737    }
 3738
 3739    fn begin_selection(
 3740        &mut self,
 3741        position: DisplayPoint,
 3742        add: bool,
 3743        click_count: usize,
 3744        window: &mut Window,
 3745        cx: &mut Context<Self>,
 3746    ) {
 3747        if !self.focus_handle.is_focused(window) {
 3748            self.last_focused_descendant = None;
 3749            window.focus(&self.focus_handle);
 3750        }
 3751
 3752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3753        let buffer = display_map.buffer_snapshot();
 3754        let position = display_map.clip_point(position, Bias::Left);
 3755
 3756        let start;
 3757        let end;
 3758        let mode;
 3759        let mut auto_scroll;
 3760        match click_count {
 3761            1 => {
 3762                start = buffer.anchor_before(position.to_point(&display_map));
 3763                end = start;
 3764                mode = SelectMode::Character;
 3765                auto_scroll = true;
 3766            }
 3767            2 => {
 3768                let position = display_map
 3769                    .clip_point(position, Bias::Left)
 3770                    .to_offset(&display_map, Bias::Left);
 3771                let (range, _) = buffer.surrounding_word(position, None);
 3772                start = buffer.anchor_before(range.start);
 3773                end = buffer.anchor_before(range.end);
 3774                mode = SelectMode::Word(start..end);
 3775                auto_scroll = true;
 3776            }
 3777            3 => {
 3778                let position = display_map
 3779                    .clip_point(position, Bias::Left)
 3780                    .to_point(&display_map);
 3781                let line_start = display_map.prev_line_boundary(position).0;
 3782                let next_line_start = buffer.clip_point(
 3783                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3784                    Bias::Left,
 3785                );
 3786                start = buffer.anchor_before(line_start);
 3787                end = buffer.anchor_before(next_line_start);
 3788                mode = SelectMode::Line(start..end);
 3789                auto_scroll = true;
 3790            }
 3791            _ => {
 3792                start = buffer.anchor_before(MultiBufferOffset(0));
 3793                end = buffer.anchor_before(buffer.len());
 3794                mode = SelectMode::All;
 3795                auto_scroll = false;
 3796            }
 3797        }
 3798        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3799
 3800        let point_to_delete: Option<usize> = {
 3801            let selected_points: Vec<Selection<Point>> =
 3802                self.selections.disjoint_in_range(start..end, &display_map);
 3803
 3804            if !add || click_count > 1 {
 3805                None
 3806            } else if !selected_points.is_empty() {
 3807                Some(selected_points[0].id)
 3808            } else {
 3809                let clicked_point_already_selected =
 3810                    self.selections.disjoint_anchors().iter().find(|selection| {
 3811                        selection.start.to_point(buffer) == start.to_point(buffer)
 3812                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3813                    });
 3814
 3815                clicked_point_already_selected.map(|selection| selection.id)
 3816            }
 3817        };
 3818
 3819        let selections_count = self.selections.count();
 3820        let effects = if auto_scroll {
 3821            SelectionEffects::default()
 3822        } else {
 3823            SelectionEffects::no_scroll()
 3824        };
 3825
 3826        self.change_selections(effects, window, cx, |s| {
 3827            if let Some(point_to_delete) = point_to_delete {
 3828                s.delete(point_to_delete);
 3829
 3830                if selections_count == 1 {
 3831                    s.set_pending_anchor_range(start..end, mode);
 3832                }
 3833            } else {
 3834                if !add {
 3835                    s.clear_disjoint();
 3836                }
 3837
 3838                s.set_pending_anchor_range(start..end, mode);
 3839            }
 3840        });
 3841    }
 3842
 3843    fn begin_columnar_selection(
 3844        &mut self,
 3845        position: DisplayPoint,
 3846        goal_column: u32,
 3847        reset: bool,
 3848        mode: ColumnarMode,
 3849        window: &mut Window,
 3850        cx: &mut Context<Self>,
 3851    ) {
 3852        if !self.focus_handle.is_focused(window) {
 3853            self.last_focused_descendant = None;
 3854            window.focus(&self.focus_handle);
 3855        }
 3856
 3857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3858
 3859        if reset {
 3860            let pointer_position = display_map
 3861                .buffer_snapshot()
 3862                .anchor_before(position.to_point(&display_map));
 3863
 3864            self.change_selections(
 3865                SelectionEffects::scroll(Autoscroll::newest()),
 3866                window,
 3867                cx,
 3868                |s| {
 3869                    s.clear_disjoint();
 3870                    s.set_pending_anchor_range(
 3871                        pointer_position..pointer_position,
 3872                        SelectMode::Character,
 3873                    );
 3874                },
 3875            );
 3876        };
 3877
 3878        let tail = self.selections.newest::<Point>(&display_map).tail();
 3879        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3880        self.columnar_selection_state = match mode {
 3881            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3882                selection_tail: selection_anchor,
 3883                display_point: if reset {
 3884                    if position.column() != goal_column {
 3885                        Some(DisplayPoint::new(position.row(), goal_column))
 3886                    } else {
 3887                        None
 3888                    }
 3889                } else {
 3890                    None
 3891                },
 3892            }),
 3893            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3894                selection_tail: selection_anchor,
 3895            }),
 3896        };
 3897
 3898        if !reset {
 3899            self.select_columns(position, goal_column, &display_map, window, cx);
 3900        }
 3901    }
 3902
 3903    fn update_selection(
 3904        &mut self,
 3905        position: DisplayPoint,
 3906        goal_column: u32,
 3907        scroll_delta: gpui::Point<f32>,
 3908        window: &mut Window,
 3909        cx: &mut Context<Self>,
 3910    ) {
 3911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3912
 3913        if self.columnar_selection_state.is_some() {
 3914            self.select_columns(position, goal_column, &display_map, window, cx);
 3915        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3916            let buffer = display_map.buffer_snapshot();
 3917            let head;
 3918            let tail;
 3919            let mode = self.selections.pending_mode().unwrap();
 3920            match &mode {
 3921                SelectMode::Character => {
 3922                    head = position.to_point(&display_map);
 3923                    tail = pending.tail().to_point(buffer);
 3924                }
 3925                SelectMode::Word(original_range) => {
 3926                    let offset = display_map
 3927                        .clip_point(position, Bias::Left)
 3928                        .to_offset(&display_map, Bias::Left);
 3929                    let original_range = original_range.to_offset(buffer);
 3930
 3931                    let head_offset = if buffer.is_inside_word(offset, None)
 3932                        || original_range.contains(&offset)
 3933                    {
 3934                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3935                        if word_range.start < original_range.start {
 3936                            word_range.start
 3937                        } else {
 3938                            word_range.end
 3939                        }
 3940                    } else {
 3941                        offset
 3942                    };
 3943
 3944                    head = head_offset.to_point(buffer);
 3945                    if head_offset <= original_range.start {
 3946                        tail = original_range.end.to_point(buffer);
 3947                    } else {
 3948                        tail = original_range.start.to_point(buffer);
 3949                    }
 3950                }
 3951                SelectMode::Line(original_range) => {
 3952                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3953
 3954                    let position = display_map
 3955                        .clip_point(position, Bias::Left)
 3956                        .to_point(&display_map);
 3957                    let line_start = display_map.prev_line_boundary(position).0;
 3958                    let next_line_start = buffer.clip_point(
 3959                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3960                        Bias::Left,
 3961                    );
 3962
 3963                    if line_start < original_range.start {
 3964                        head = line_start
 3965                    } else {
 3966                        head = next_line_start
 3967                    }
 3968
 3969                    if head <= original_range.start {
 3970                        tail = original_range.end;
 3971                    } else {
 3972                        tail = original_range.start;
 3973                    }
 3974                }
 3975                SelectMode::All => {
 3976                    return;
 3977                }
 3978            };
 3979
 3980            if head < tail {
 3981                pending.start = buffer.anchor_before(head);
 3982                pending.end = buffer.anchor_before(tail);
 3983                pending.reversed = true;
 3984            } else {
 3985                pending.start = buffer.anchor_before(tail);
 3986                pending.end = buffer.anchor_before(head);
 3987                pending.reversed = false;
 3988            }
 3989
 3990            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3991                s.set_pending(pending.clone(), mode);
 3992            });
 3993        } else {
 3994            log::error!("update_selection dispatched with no pending selection");
 3995            return;
 3996        }
 3997
 3998        self.apply_scroll_delta(scroll_delta, window, cx);
 3999        cx.notify();
 4000    }
 4001
 4002    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4003        self.columnar_selection_state.take();
 4004        if let Some(pending_mode) = self.selections.pending_mode() {
 4005            let selections = self
 4006                .selections
 4007                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4008            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4009                s.select(selections);
 4010                s.clear_pending();
 4011                if s.is_extending() {
 4012                    s.set_is_extending(false);
 4013                } else {
 4014                    s.set_select_mode(pending_mode);
 4015                }
 4016            });
 4017        }
 4018    }
 4019
 4020    fn select_columns(
 4021        &mut self,
 4022        head: DisplayPoint,
 4023        goal_column: u32,
 4024        display_map: &DisplaySnapshot,
 4025        window: &mut Window,
 4026        cx: &mut Context<Self>,
 4027    ) {
 4028        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4029            return;
 4030        };
 4031
 4032        let tail = match columnar_state {
 4033            ColumnarSelectionState::FromMouse {
 4034                selection_tail,
 4035                display_point,
 4036            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4037            ColumnarSelectionState::FromSelection { selection_tail } => {
 4038                selection_tail.to_display_point(display_map)
 4039            }
 4040        };
 4041
 4042        let start_row = cmp::min(tail.row(), head.row());
 4043        let end_row = cmp::max(tail.row(), head.row());
 4044        let start_column = cmp::min(tail.column(), goal_column);
 4045        let end_column = cmp::max(tail.column(), goal_column);
 4046        let reversed = start_column < tail.column();
 4047
 4048        let selection_ranges = (start_row.0..=end_row.0)
 4049            .map(DisplayRow)
 4050            .filter_map(|row| {
 4051                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4052                    || start_column <= display_map.line_len(row))
 4053                    && !display_map.is_block_line(row)
 4054                {
 4055                    let start = display_map
 4056                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4057                        .to_point(display_map);
 4058                    let end = display_map
 4059                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4060                        .to_point(display_map);
 4061                    if reversed {
 4062                        Some(end..start)
 4063                    } else {
 4064                        Some(start..end)
 4065                    }
 4066                } else {
 4067                    None
 4068                }
 4069            })
 4070            .collect::<Vec<_>>();
 4071        if selection_ranges.is_empty() {
 4072            return;
 4073        }
 4074
 4075        let ranges = match columnar_state {
 4076            ColumnarSelectionState::FromMouse { .. } => {
 4077                let mut non_empty_ranges = selection_ranges
 4078                    .iter()
 4079                    .filter(|selection_range| selection_range.start != selection_range.end)
 4080                    .peekable();
 4081                if non_empty_ranges.peek().is_some() {
 4082                    non_empty_ranges.cloned().collect()
 4083                } else {
 4084                    selection_ranges
 4085                }
 4086            }
 4087            _ => selection_ranges,
 4088        };
 4089
 4090        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4091            s.select_ranges(ranges);
 4092        });
 4093        cx.notify();
 4094    }
 4095
 4096    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4097        self.selections
 4098            .all_adjusted(snapshot)
 4099            .iter()
 4100            .any(|selection| !selection.is_empty())
 4101    }
 4102
 4103    pub fn has_pending_nonempty_selection(&self) -> bool {
 4104        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4105            Some(Selection { start, end, .. }) => start != end,
 4106            None => false,
 4107        };
 4108
 4109        pending_nonempty_selection
 4110            || (self.columnar_selection_state.is_some()
 4111                && self.selections.disjoint_anchors().len() > 1)
 4112    }
 4113
 4114    pub fn has_pending_selection(&self) -> bool {
 4115        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4116    }
 4117
 4118    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4119        self.selection_mark_mode = false;
 4120        self.selection_drag_state = SelectionDragState::None;
 4121
 4122        if self.dismiss_menus_and_popups(true, window, cx) {
 4123            cx.notify();
 4124            return;
 4125        }
 4126        if self.clear_expanded_diff_hunks(cx) {
 4127            cx.notify();
 4128            return;
 4129        }
 4130        if self.show_git_blame_gutter {
 4131            self.show_git_blame_gutter = false;
 4132            cx.notify();
 4133            return;
 4134        }
 4135
 4136        if self.mode.is_full()
 4137            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4138        {
 4139            cx.notify();
 4140            return;
 4141        }
 4142
 4143        cx.propagate();
 4144    }
 4145
 4146    pub fn dismiss_menus_and_popups(
 4147        &mut self,
 4148        is_user_requested: bool,
 4149        window: &mut Window,
 4150        cx: &mut Context<Self>,
 4151    ) -> bool {
 4152        let mut dismissed = false;
 4153
 4154        dismissed |= self.take_rename(false, window, cx).is_some();
 4155        dismissed |= self.hide_blame_popover(true, cx);
 4156        dismissed |= hide_hover(self, cx);
 4157        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4158        dismissed |= self.hide_context_menu(window, cx).is_some();
 4159        dismissed |= self.mouse_context_menu.take().is_some();
 4160        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4161        dismissed |= self.snippet_stack.pop().is_some();
 4162
 4163        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4164            self.dismiss_diagnostics(cx);
 4165            dismissed = true;
 4166        }
 4167
 4168        dismissed
 4169    }
 4170
 4171    fn linked_editing_ranges_for(
 4172        &self,
 4173        selection: Range<text::Anchor>,
 4174        cx: &App,
 4175    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4176        if self.linked_edit_ranges.is_empty() {
 4177            return None;
 4178        }
 4179        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4180            selection.end.buffer_id.and_then(|end_buffer_id| {
 4181                if selection.start.buffer_id != Some(end_buffer_id) {
 4182                    return None;
 4183                }
 4184                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4185                let snapshot = buffer.read(cx).snapshot();
 4186                self.linked_edit_ranges
 4187                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4188                    .map(|ranges| (ranges, snapshot, buffer))
 4189            })?;
 4190        use text::ToOffset as TO;
 4191        // find offset from the start of current range to current cursor position
 4192        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4193
 4194        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4195        let start_difference = start_offset - start_byte_offset;
 4196        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4197        let end_difference = end_offset - start_byte_offset;
 4198        // Current range has associated linked ranges.
 4199        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4200        for range in linked_ranges.iter() {
 4201            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4202            let end_offset = start_offset + end_difference;
 4203            let start_offset = start_offset + start_difference;
 4204            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4205                continue;
 4206            }
 4207            if self.selections.disjoint_anchor_ranges().any(|s| {
 4208                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4209                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4210                {
 4211                    return false;
 4212                }
 4213                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4214                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4215            }) {
 4216                continue;
 4217            }
 4218            let start = buffer_snapshot.anchor_after(start_offset);
 4219            let end = buffer_snapshot.anchor_after(end_offset);
 4220            linked_edits
 4221                .entry(buffer.clone())
 4222                .or_default()
 4223                .push(start..end);
 4224        }
 4225        Some(linked_edits)
 4226    }
 4227
 4228    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4229        let text: Arc<str> = text.into();
 4230
 4231        if self.read_only(cx) {
 4232            return;
 4233        }
 4234
 4235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4236
 4237        self.unfold_buffers_with_selections(cx);
 4238
 4239        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4240        let mut bracket_inserted = false;
 4241        let mut edits = Vec::new();
 4242        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4243        let mut new_selections = Vec::with_capacity(selections.len());
 4244        let mut new_autoclose_regions = Vec::new();
 4245        let snapshot = self.buffer.read(cx).read(cx);
 4246        let mut clear_linked_edit_ranges = false;
 4247
 4248        for (selection, autoclose_region) in
 4249            self.selections_with_autoclose_regions(selections, &snapshot)
 4250        {
 4251            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4252                // Determine if the inserted text matches the opening or closing
 4253                // bracket of any of this language's bracket pairs.
 4254                let mut bracket_pair = None;
 4255                let mut is_bracket_pair_start = false;
 4256                let mut is_bracket_pair_end = false;
 4257                if !text.is_empty() {
 4258                    let mut bracket_pair_matching_end = None;
 4259                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4260                    //  and they are removing the character that triggered IME popup.
 4261                    for (pair, enabled) in scope.brackets() {
 4262                        if !pair.close && !pair.surround {
 4263                            continue;
 4264                        }
 4265
 4266                        if enabled && pair.start.ends_with(text.as_ref()) {
 4267                            let prefix_len = pair.start.len() - text.len();
 4268                            let preceding_text_matches_prefix = prefix_len == 0
 4269                                || (selection.start.column >= (prefix_len as u32)
 4270                                    && snapshot.contains_str_at(
 4271                                        Point::new(
 4272                                            selection.start.row,
 4273                                            selection.start.column - (prefix_len as u32),
 4274                                        ),
 4275                                        &pair.start[..prefix_len],
 4276                                    ));
 4277                            if preceding_text_matches_prefix {
 4278                                bracket_pair = Some(pair.clone());
 4279                                is_bracket_pair_start = true;
 4280                                break;
 4281                            }
 4282                        }
 4283                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4284                        {
 4285                            // take first bracket pair matching end, but don't break in case a later bracket
 4286                            // pair matches start
 4287                            bracket_pair_matching_end = Some(pair.clone());
 4288                        }
 4289                    }
 4290                    if let Some(end) = bracket_pair_matching_end
 4291                        && bracket_pair.is_none()
 4292                    {
 4293                        bracket_pair = Some(end);
 4294                        is_bracket_pair_end = true;
 4295                    }
 4296                }
 4297
 4298                if let Some(bracket_pair) = bracket_pair {
 4299                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4300                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4301                    let auto_surround =
 4302                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4303                    if selection.is_empty() {
 4304                        if is_bracket_pair_start {
 4305                            // If the inserted text is a suffix of an opening bracket and the
 4306                            // selection is preceded by the rest of the opening bracket, then
 4307                            // insert the closing bracket.
 4308                            let following_text_allows_autoclose = snapshot
 4309                                .chars_at(selection.start)
 4310                                .next()
 4311                                .is_none_or(|c| scope.should_autoclose_before(c));
 4312
 4313                            let preceding_text_allows_autoclose = selection.start.column == 0
 4314                                || snapshot
 4315                                    .reversed_chars_at(selection.start)
 4316                                    .next()
 4317                                    .is_none_or(|c| {
 4318                                        bracket_pair.start != bracket_pair.end
 4319                                            || !snapshot
 4320                                                .char_classifier_at(selection.start)
 4321                                                .is_word(c)
 4322                                    });
 4323
 4324                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4325                                && bracket_pair.start.len() == 1
 4326                            {
 4327                                let target = bracket_pair.start.chars().next().unwrap();
 4328                                let current_line_count = snapshot
 4329                                    .reversed_chars_at(selection.start)
 4330                                    .take_while(|&c| c != '\n')
 4331                                    .filter(|&c| c == target)
 4332                                    .count();
 4333                                current_line_count % 2 == 1
 4334                            } else {
 4335                                false
 4336                            };
 4337
 4338                            if autoclose
 4339                                && bracket_pair.close
 4340                                && following_text_allows_autoclose
 4341                                && preceding_text_allows_autoclose
 4342                                && !is_closing_quote
 4343                            {
 4344                                let anchor = snapshot.anchor_before(selection.end);
 4345                                new_selections.push((selection.map(|_| anchor), text.len()));
 4346                                new_autoclose_regions.push((
 4347                                    anchor,
 4348                                    text.len(),
 4349                                    selection.id,
 4350                                    bracket_pair.clone(),
 4351                                ));
 4352                                edits.push((
 4353                                    selection.range(),
 4354                                    format!("{}{}", text, bracket_pair.end).into(),
 4355                                ));
 4356                                bracket_inserted = true;
 4357                                continue;
 4358                            }
 4359                        }
 4360
 4361                        if let Some(region) = autoclose_region {
 4362                            // If the selection is followed by an auto-inserted closing bracket,
 4363                            // then don't insert that closing bracket again; just move the selection
 4364                            // past the closing bracket.
 4365                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4366                                && text.as_ref() == region.pair.end.as_str()
 4367                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4368                            if should_skip {
 4369                                let anchor = snapshot.anchor_after(selection.end);
 4370                                new_selections
 4371                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4372                                continue;
 4373                            }
 4374                        }
 4375
 4376                        let always_treat_brackets_as_autoclosed = snapshot
 4377                            .language_settings_at(selection.start, cx)
 4378                            .always_treat_brackets_as_autoclosed;
 4379                        if always_treat_brackets_as_autoclosed
 4380                            && is_bracket_pair_end
 4381                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4382                        {
 4383                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4384                            // and the inserted text is a closing bracket and the selection is followed
 4385                            // by the closing bracket then move the selection past the closing bracket.
 4386                            let anchor = snapshot.anchor_after(selection.end);
 4387                            new_selections.push((selection.map(|_| anchor), text.len()));
 4388                            continue;
 4389                        }
 4390                    }
 4391                    // If an opening bracket is 1 character long and is typed while
 4392                    // text is selected, then surround that text with the bracket pair.
 4393                    else if auto_surround
 4394                        && bracket_pair.surround
 4395                        && is_bracket_pair_start
 4396                        && bracket_pair.start.chars().count() == 1
 4397                    {
 4398                        edits.push((selection.start..selection.start, text.clone()));
 4399                        edits.push((
 4400                            selection.end..selection.end,
 4401                            bracket_pair.end.as_str().into(),
 4402                        ));
 4403                        bracket_inserted = true;
 4404                        new_selections.push((
 4405                            Selection {
 4406                                id: selection.id,
 4407                                start: snapshot.anchor_after(selection.start),
 4408                                end: snapshot.anchor_before(selection.end),
 4409                                reversed: selection.reversed,
 4410                                goal: selection.goal,
 4411                            },
 4412                            0,
 4413                        ));
 4414                        continue;
 4415                    }
 4416                }
 4417            }
 4418
 4419            if self.auto_replace_emoji_shortcode
 4420                && selection.is_empty()
 4421                && text.as_ref().ends_with(':')
 4422                && let Some(possible_emoji_short_code) =
 4423                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4424                && !possible_emoji_short_code.is_empty()
 4425                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4426            {
 4427                let emoji_shortcode_start = Point::new(
 4428                    selection.start.row,
 4429                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4430                );
 4431
 4432                // Remove shortcode from buffer
 4433                edits.push((
 4434                    emoji_shortcode_start..selection.start,
 4435                    "".to_string().into(),
 4436                ));
 4437                new_selections.push((
 4438                    Selection {
 4439                        id: selection.id,
 4440                        start: snapshot.anchor_after(emoji_shortcode_start),
 4441                        end: snapshot.anchor_before(selection.start),
 4442                        reversed: selection.reversed,
 4443                        goal: selection.goal,
 4444                    },
 4445                    0,
 4446                ));
 4447
 4448                // Insert emoji
 4449                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4450                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4451                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4452
 4453                continue;
 4454            }
 4455
 4456            // If not handling any auto-close operation, then just replace the selected
 4457            // text with the given input and move the selection to the end of the
 4458            // newly inserted text.
 4459            let anchor = snapshot.anchor_after(selection.end);
 4460            if !self.linked_edit_ranges.is_empty() {
 4461                let start_anchor = snapshot.anchor_before(selection.start);
 4462
 4463                let is_word_char = text.chars().next().is_none_or(|char| {
 4464                    let classifier = snapshot
 4465                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4466                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4467                    classifier.is_word(char)
 4468                });
 4469
 4470                if is_word_char {
 4471                    if let Some(ranges) = self
 4472                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4473                    {
 4474                        for (buffer, edits) in ranges {
 4475                            linked_edits
 4476                                .entry(buffer.clone())
 4477                                .or_default()
 4478                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4479                        }
 4480                    }
 4481                } else {
 4482                    clear_linked_edit_ranges = true;
 4483                }
 4484            }
 4485
 4486            new_selections.push((selection.map(|_| anchor), 0));
 4487            edits.push((selection.start..selection.end, text.clone()));
 4488        }
 4489
 4490        drop(snapshot);
 4491
 4492        self.transact(window, cx, |this, window, cx| {
 4493            if clear_linked_edit_ranges {
 4494                this.linked_edit_ranges.clear();
 4495            }
 4496            let initial_buffer_versions =
 4497                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4498
 4499            this.buffer.update(cx, |buffer, cx| {
 4500                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4501            });
 4502            for (buffer, edits) in linked_edits {
 4503                buffer.update(cx, |buffer, cx| {
 4504                    let snapshot = buffer.snapshot();
 4505                    let edits = edits
 4506                        .into_iter()
 4507                        .map(|(range, text)| {
 4508                            use text::ToPoint as TP;
 4509                            let end_point = TP::to_point(&range.end, &snapshot);
 4510                            let start_point = TP::to_point(&range.start, &snapshot);
 4511                            (start_point..end_point, text)
 4512                        })
 4513                        .sorted_by_key(|(range, _)| range.start);
 4514                    buffer.edit(edits, None, cx);
 4515                })
 4516            }
 4517            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4518            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4519            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4520            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4521                new_anchor_selections,
 4522                &map,
 4523            )
 4524            .zip(new_selection_deltas)
 4525            .map(|(selection, delta)| Selection {
 4526                id: selection.id,
 4527                start: selection.start + delta,
 4528                end: selection.end + delta,
 4529                reversed: selection.reversed,
 4530                goal: SelectionGoal::None,
 4531            })
 4532            .collect::<Vec<_>>();
 4533
 4534            let mut i = 0;
 4535            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4536                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4537                let start = map.buffer_snapshot().anchor_before(position);
 4538                let end = map.buffer_snapshot().anchor_after(position);
 4539                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4540                    match existing_state
 4541                        .range
 4542                        .start
 4543                        .cmp(&start, map.buffer_snapshot())
 4544                    {
 4545                        Ordering::Less => i += 1,
 4546                        Ordering::Greater => break,
 4547                        Ordering::Equal => {
 4548                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4549                                Ordering::Less => i += 1,
 4550                                Ordering::Equal => break,
 4551                                Ordering::Greater => break,
 4552                            }
 4553                        }
 4554                    }
 4555                }
 4556                this.autoclose_regions.insert(
 4557                    i,
 4558                    AutocloseRegion {
 4559                        selection_id,
 4560                        range: start..end,
 4561                        pair,
 4562                    },
 4563                );
 4564            }
 4565
 4566            let had_active_edit_prediction = this.has_active_edit_prediction();
 4567            this.change_selections(
 4568                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4569                window,
 4570                cx,
 4571                |s| s.select(new_selections),
 4572            );
 4573
 4574            if !bracket_inserted
 4575                && let Some(on_type_format_task) =
 4576                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4577            {
 4578                on_type_format_task.detach_and_log_err(cx);
 4579            }
 4580
 4581            let editor_settings = EditorSettings::get_global(cx);
 4582            if bracket_inserted
 4583                && (editor_settings.auto_signature_help
 4584                    || editor_settings.show_signature_help_after_edits)
 4585            {
 4586                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4587            }
 4588
 4589            let trigger_in_words =
 4590                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4591            if this.hard_wrap.is_some() {
 4592                let latest: Range<Point> = this.selections.newest(&map).range();
 4593                if latest.is_empty()
 4594                    && this
 4595                        .buffer()
 4596                        .read(cx)
 4597                        .snapshot(cx)
 4598                        .line_len(MultiBufferRow(latest.start.row))
 4599                        == latest.start.column
 4600                {
 4601                    this.rewrap_impl(
 4602                        RewrapOptions {
 4603                            override_language_settings: true,
 4604                            preserve_existing_whitespace: true,
 4605                        },
 4606                        cx,
 4607                    )
 4608                }
 4609            }
 4610            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4611            refresh_linked_ranges(this, window, cx);
 4612            this.refresh_edit_prediction(true, false, window, cx);
 4613            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4614        });
 4615    }
 4616
 4617    fn find_possible_emoji_shortcode_at_position(
 4618        snapshot: &MultiBufferSnapshot,
 4619        position: Point,
 4620    ) -> Option<String> {
 4621        let mut chars = Vec::new();
 4622        let mut found_colon = false;
 4623        for char in snapshot.reversed_chars_at(position).take(100) {
 4624            // Found a possible emoji shortcode in the middle of the buffer
 4625            if found_colon {
 4626                if char.is_whitespace() {
 4627                    chars.reverse();
 4628                    return Some(chars.iter().collect());
 4629                }
 4630                // If the previous character is not a whitespace, we are in the middle of a word
 4631                // and we only want to complete the shortcode if the word is made up of other emojis
 4632                let mut containing_word = String::new();
 4633                for ch in snapshot
 4634                    .reversed_chars_at(position)
 4635                    .skip(chars.len() + 1)
 4636                    .take(100)
 4637                {
 4638                    if ch.is_whitespace() {
 4639                        break;
 4640                    }
 4641                    containing_word.push(ch);
 4642                }
 4643                let containing_word = containing_word.chars().rev().collect::<String>();
 4644                if util::word_consists_of_emojis(containing_word.as_str()) {
 4645                    chars.reverse();
 4646                    return Some(chars.iter().collect());
 4647                }
 4648            }
 4649
 4650            if char.is_whitespace() || !char.is_ascii() {
 4651                return None;
 4652            }
 4653            if char == ':' {
 4654                found_colon = true;
 4655            } else {
 4656                chars.push(char);
 4657            }
 4658        }
 4659        // Found a possible emoji shortcode at the beginning of the buffer
 4660        chars.reverse();
 4661        Some(chars.iter().collect())
 4662    }
 4663
 4664    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4666        self.transact(window, cx, |this, window, cx| {
 4667            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4668                let selections = this
 4669                    .selections
 4670                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4671                let multi_buffer = this.buffer.read(cx);
 4672                let buffer = multi_buffer.snapshot(cx);
 4673                selections
 4674                    .iter()
 4675                    .map(|selection| {
 4676                        let start_point = selection.start.to_point(&buffer);
 4677                        let mut existing_indent =
 4678                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4679                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4680                        let start = selection.start;
 4681                        let end = selection.end;
 4682                        let selection_is_empty = start == end;
 4683                        let language_scope = buffer.language_scope_at(start);
 4684                        let (
 4685                            comment_delimiter,
 4686                            doc_delimiter,
 4687                            insert_extra_newline,
 4688                            indent_on_newline,
 4689                            indent_on_extra_newline,
 4690                        ) = if let Some(language) = &language_scope {
 4691                            let mut insert_extra_newline =
 4692                                insert_extra_newline_brackets(&buffer, start..end, language)
 4693                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4694
 4695                            // Comment extension on newline is allowed only for cursor selections
 4696                            let comment_delimiter = maybe!({
 4697                                if !selection_is_empty {
 4698                                    return None;
 4699                                }
 4700
 4701                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4702                                    return None;
 4703                                }
 4704
 4705                                let delimiters = language.line_comment_prefixes();
 4706                                let max_len_of_delimiter =
 4707                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4708                                let (snapshot, range) =
 4709                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4710
 4711                                let num_of_whitespaces = snapshot
 4712                                    .chars_for_range(range.clone())
 4713                                    .take_while(|c| c.is_whitespace())
 4714                                    .count();
 4715                                let comment_candidate = snapshot
 4716                                    .chars_for_range(range.clone())
 4717                                    .skip(num_of_whitespaces)
 4718                                    .take(max_len_of_delimiter)
 4719                                    .collect::<String>();
 4720                                let (delimiter, trimmed_len) = delimiters
 4721                                    .iter()
 4722                                    .filter_map(|delimiter| {
 4723                                        let prefix = delimiter.trim_end();
 4724                                        if comment_candidate.starts_with(prefix) {
 4725                                            Some((delimiter, prefix.len()))
 4726                                        } else {
 4727                                            None
 4728                                        }
 4729                                    })
 4730                                    .max_by_key(|(_, len)| *len)?;
 4731
 4732                                if let Some(BlockCommentConfig {
 4733                                    start: block_start, ..
 4734                                }) = language.block_comment()
 4735                                {
 4736                                    let block_start_trimmed = block_start.trim_end();
 4737                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4738                                        let line_content = snapshot
 4739                                            .chars_for_range(range)
 4740                                            .skip(num_of_whitespaces)
 4741                                            .take(block_start_trimmed.len())
 4742                                            .collect::<String>();
 4743
 4744                                        if line_content.starts_with(block_start_trimmed) {
 4745                                            return None;
 4746                                        }
 4747                                    }
 4748                                }
 4749
 4750                                let cursor_is_placed_after_comment_marker =
 4751                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4752                                if cursor_is_placed_after_comment_marker {
 4753                                    Some(delimiter.clone())
 4754                                } else {
 4755                                    None
 4756                                }
 4757                            });
 4758
 4759                            let mut indent_on_newline = IndentSize::spaces(0);
 4760                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4761
 4762                            let doc_delimiter = maybe!({
 4763                                if !selection_is_empty {
 4764                                    return None;
 4765                                }
 4766
 4767                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4768                                    return None;
 4769                                }
 4770
 4771                                let BlockCommentConfig {
 4772                                    start: start_tag,
 4773                                    end: end_tag,
 4774                                    prefix: delimiter,
 4775                                    tab_size: len,
 4776                                } = language.documentation_comment()?;
 4777                                let is_within_block_comment = buffer
 4778                                    .language_scope_at(start_point)
 4779                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4780                                if !is_within_block_comment {
 4781                                    return None;
 4782                                }
 4783
 4784                                let (snapshot, range) =
 4785                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4786
 4787                                let num_of_whitespaces = snapshot
 4788                                    .chars_for_range(range.clone())
 4789                                    .take_while(|c| c.is_whitespace())
 4790                                    .count();
 4791
 4792                                // 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.
 4793                                let column = start_point.column;
 4794                                let cursor_is_after_start_tag = {
 4795                                    let start_tag_len = start_tag.len();
 4796                                    let start_tag_line = snapshot
 4797                                        .chars_for_range(range.clone())
 4798                                        .skip(num_of_whitespaces)
 4799                                        .take(start_tag_len)
 4800                                        .collect::<String>();
 4801                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4802                                        num_of_whitespaces + start_tag_len <= column as usize
 4803                                    } else {
 4804                                        false
 4805                                    }
 4806                                };
 4807
 4808                                let cursor_is_after_delimiter = {
 4809                                    let delimiter_trim = delimiter.trim_end();
 4810                                    let delimiter_line = snapshot
 4811                                        .chars_for_range(range.clone())
 4812                                        .skip(num_of_whitespaces)
 4813                                        .take(delimiter_trim.len())
 4814                                        .collect::<String>();
 4815                                    if delimiter_line.starts_with(delimiter_trim) {
 4816                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4817                                    } else {
 4818                                        false
 4819                                    }
 4820                                };
 4821
 4822                                let cursor_is_before_end_tag_if_exists = {
 4823                                    let mut char_position = 0u32;
 4824                                    let mut end_tag_offset = None;
 4825
 4826                                    'outer: for chunk in snapshot.text_for_range(range) {
 4827                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4828                                            let chars_before_match =
 4829                                                chunk[..byte_pos].chars().count() as u32;
 4830                                            end_tag_offset =
 4831                                                Some(char_position + chars_before_match);
 4832                                            break 'outer;
 4833                                        }
 4834                                        char_position += chunk.chars().count() as u32;
 4835                                    }
 4836
 4837                                    if let Some(end_tag_offset) = end_tag_offset {
 4838                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4839                                        if cursor_is_after_start_tag {
 4840                                            if cursor_is_before_end_tag {
 4841                                                insert_extra_newline = true;
 4842                                            }
 4843                                            let cursor_is_at_start_of_end_tag =
 4844                                                column == end_tag_offset;
 4845                                            if cursor_is_at_start_of_end_tag {
 4846                                                indent_on_extra_newline.len = *len;
 4847                                            }
 4848                                        }
 4849                                        cursor_is_before_end_tag
 4850                                    } else {
 4851                                        true
 4852                                    }
 4853                                };
 4854
 4855                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4856                                    && cursor_is_before_end_tag_if_exists
 4857                                {
 4858                                    if cursor_is_after_start_tag {
 4859                                        indent_on_newline.len = *len;
 4860                                    }
 4861                                    Some(delimiter.clone())
 4862                                } else {
 4863                                    None
 4864                                }
 4865                            });
 4866
 4867                            (
 4868                                comment_delimiter,
 4869                                doc_delimiter,
 4870                                insert_extra_newline,
 4871                                indent_on_newline,
 4872                                indent_on_extra_newline,
 4873                            )
 4874                        } else {
 4875                            (
 4876                                None,
 4877                                None,
 4878                                false,
 4879                                IndentSize::default(),
 4880                                IndentSize::default(),
 4881                            )
 4882                        };
 4883
 4884                        let prevent_auto_indent = doc_delimiter.is_some();
 4885                        let delimiter = comment_delimiter.or(doc_delimiter);
 4886
 4887                        let capacity_for_delimiter =
 4888                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4889                        let mut new_text = String::with_capacity(
 4890                            1 + capacity_for_delimiter
 4891                                + existing_indent.len as usize
 4892                                + indent_on_newline.len as usize
 4893                                + indent_on_extra_newline.len as usize,
 4894                        );
 4895                        new_text.push('\n');
 4896                        new_text.extend(existing_indent.chars());
 4897                        new_text.extend(indent_on_newline.chars());
 4898
 4899                        if let Some(delimiter) = &delimiter {
 4900                            new_text.push_str(delimiter);
 4901                        }
 4902
 4903                        if insert_extra_newline {
 4904                            new_text.push('\n');
 4905                            new_text.extend(existing_indent.chars());
 4906                            new_text.extend(indent_on_extra_newline.chars());
 4907                        }
 4908
 4909                        let anchor = buffer.anchor_after(end);
 4910                        let new_selection = selection.map(|_| anchor);
 4911                        (
 4912                            ((start..end, new_text), prevent_auto_indent),
 4913                            (insert_extra_newline, new_selection),
 4914                        )
 4915                    })
 4916                    .unzip()
 4917            };
 4918
 4919            let mut auto_indent_edits = Vec::new();
 4920            let mut edits = Vec::new();
 4921            for (edit, prevent_auto_indent) in edits_with_flags {
 4922                if prevent_auto_indent {
 4923                    edits.push(edit);
 4924                } else {
 4925                    auto_indent_edits.push(edit);
 4926                }
 4927            }
 4928            if !edits.is_empty() {
 4929                this.edit(edits, cx);
 4930            }
 4931            if !auto_indent_edits.is_empty() {
 4932                this.edit_with_autoindent(auto_indent_edits, cx);
 4933            }
 4934
 4935            let buffer = this.buffer.read(cx).snapshot(cx);
 4936            let new_selections = selection_info
 4937                .into_iter()
 4938                .map(|(extra_newline_inserted, new_selection)| {
 4939                    let mut cursor = new_selection.end.to_point(&buffer);
 4940                    if extra_newline_inserted {
 4941                        cursor.row -= 1;
 4942                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4943                    }
 4944                    new_selection.map(|_| cursor)
 4945                })
 4946                .collect();
 4947
 4948            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4949            this.refresh_edit_prediction(true, false, window, cx);
 4950        });
 4951    }
 4952
 4953    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4955
 4956        let buffer = self.buffer.read(cx);
 4957        let snapshot = buffer.snapshot(cx);
 4958
 4959        let mut edits = Vec::new();
 4960        let mut rows = Vec::new();
 4961
 4962        for (rows_inserted, selection) in self
 4963            .selections
 4964            .all_adjusted(&self.display_snapshot(cx))
 4965            .into_iter()
 4966            .enumerate()
 4967        {
 4968            let cursor = selection.head();
 4969            let row = cursor.row;
 4970
 4971            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4972
 4973            let newline = "\n".to_string();
 4974            edits.push((start_of_line..start_of_line, newline));
 4975
 4976            rows.push(row + rows_inserted as u32);
 4977        }
 4978
 4979        self.transact(window, cx, |editor, window, cx| {
 4980            editor.edit(edits, cx);
 4981
 4982            editor.change_selections(Default::default(), window, cx, |s| {
 4983                let mut index = 0;
 4984                s.move_cursors_with(|map, _, _| {
 4985                    let row = rows[index];
 4986                    index += 1;
 4987
 4988                    let point = Point::new(row, 0);
 4989                    let boundary = map.next_line_boundary(point).1;
 4990                    let clipped = map.clip_point(boundary, Bias::Left);
 4991
 4992                    (clipped, SelectionGoal::None)
 4993                });
 4994            });
 4995
 4996            let mut indent_edits = Vec::new();
 4997            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4998            for row in rows {
 4999                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5000                for (row, indent) in indents {
 5001                    if indent.len == 0 {
 5002                        continue;
 5003                    }
 5004
 5005                    let text = match indent.kind {
 5006                        IndentKind::Space => " ".repeat(indent.len as usize),
 5007                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5008                    };
 5009                    let point = Point::new(row.0, 0);
 5010                    indent_edits.push((point..point, text));
 5011                }
 5012            }
 5013            editor.edit(indent_edits, cx);
 5014        });
 5015    }
 5016
 5017    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5019
 5020        let buffer = self.buffer.read(cx);
 5021        let snapshot = buffer.snapshot(cx);
 5022
 5023        let mut edits = Vec::new();
 5024        let mut rows = Vec::new();
 5025        let mut rows_inserted = 0;
 5026
 5027        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5028            let cursor = selection.head();
 5029            let row = cursor.row;
 5030
 5031            let point = Point::new(row + 1, 0);
 5032            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5033
 5034            let newline = "\n".to_string();
 5035            edits.push((start_of_line..start_of_line, newline));
 5036
 5037            rows_inserted += 1;
 5038            rows.push(row + rows_inserted);
 5039        }
 5040
 5041        self.transact(window, cx, |editor, window, cx| {
 5042            editor.edit(edits, cx);
 5043
 5044            editor.change_selections(Default::default(), window, cx, |s| {
 5045                let mut index = 0;
 5046                s.move_cursors_with(|map, _, _| {
 5047                    let row = rows[index];
 5048                    index += 1;
 5049
 5050                    let point = Point::new(row, 0);
 5051                    let boundary = map.next_line_boundary(point).1;
 5052                    let clipped = map.clip_point(boundary, Bias::Left);
 5053
 5054                    (clipped, SelectionGoal::None)
 5055                });
 5056            });
 5057
 5058            let mut indent_edits = Vec::new();
 5059            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5060            for row in rows {
 5061                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5062                for (row, indent) in indents {
 5063                    if indent.len == 0 {
 5064                        continue;
 5065                    }
 5066
 5067                    let text = match indent.kind {
 5068                        IndentKind::Space => " ".repeat(indent.len as usize),
 5069                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5070                    };
 5071                    let point = Point::new(row.0, 0);
 5072                    indent_edits.push((point..point, text));
 5073                }
 5074            }
 5075            editor.edit(indent_edits, cx);
 5076        });
 5077    }
 5078
 5079    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5080        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5081            original_indent_columns: Vec::new(),
 5082        });
 5083        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5084    }
 5085
 5086    fn insert_with_autoindent_mode(
 5087        &mut self,
 5088        text: &str,
 5089        autoindent_mode: Option<AutoindentMode>,
 5090        window: &mut Window,
 5091        cx: &mut Context<Self>,
 5092    ) {
 5093        if self.read_only(cx) {
 5094            return;
 5095        }
 5096
 5097        let text: Arc<str> = text.into();
 5098        self.transact(window, cx, |this, window, cx| {
 5099            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5100            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5101                let anchors = {
 5102                    let snapshot = buffer.read(cx);
 5103                    old_selections
 5104                        .iter()
 5105                        .map(|s| {
 5106                            let anchor = snapshot.anchor_after(s.head());
 5107                            s.map(|_| anchor)
 5108                        })
 5109                        .collect::<Vec<_>>()
 5110                };
 5111                buffer.edit(
 5112                    old_selections
 5113                        .iter()
 5114                        .map(|s| (s.start..s.end, text.clone())),
 5115                    autoindent_mode,
 5116                    cx,
 5117                );
 5118                anchors
 5119            });
 5120
 5121            this.change_selections(Default::default(), window, cx, |s| {
 5122                s.select_anchors(selection_anchors);
 5123            });
 5124
 5125            cx.notify();
 5126        });
 5127    }
 5128
 5129    fn trigger_completion_on_input(
 5130        &mut self,
 5131        text: &str,
 5132        trigger_in_words: bool,
 5133        window: &mut Window,
 5134        cx: &mut Context<Self>,
 5135    ) {
 5136        let completions_source = self
 5137            .context_menu
 5138            .borrow()
 5139            .as_ref()
 5140            .and_then(|menu| match menu {
 5141                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5142                CodeContextMenu::CodeActions(_) => None,
 5143            });
 5144
 5145        match completions_source {
 5146            Some(CompletionsMenuSource::Words { .. }) => {
 5147                self.open_or_update_completions_menu(
 5148                    Some(CompletionsMenuSource::Words {
 5149                        ignore_threshold: false,
 5150                    }),
 5151                    None,
 5152                    trigger_in_words,
 5153                    window,
 5154                    cx,
 5155                );
 5156            }
 5157            _ => self.open_or_update_completions_menu(
 5158                None,
 5159                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5160                true,
 5161                window,
 5162                cx,
 5163            ),
 5164        }
 5165    }
 5166
 5167    /// If any empty selections is touching the start of its innermost containing autoclose
 5168    /// region, expand it to select the brackets.
 5169    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5170        let selections = self
 5171            .selections
 5172            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5173        let buffer = self.buffer.read(cx).read(cx);
 5174        let new_selections = self
 5175            .selections_with_autoclose_regions(selections, &buffer)
 5176            .map(|(mut selection, region)| {
 5177                if !selection.is_empty() {
 5178                    return selection;
 5179                }
 5180
 5181                if let Some(region) = region {
 5182                    let mut range = region.range.to_offset(&buffer);
 5183                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5184                        range.start -= region.pair.start.len();
 5185                        if buffer.contains_str_at(range.start, &region.pair.start)
 5186                            && buffer.contains_str_at(range.end, &region.pair.end)
 5187                        {
 5188                            range.end += region.pair.end.len();
 5189                            selection.start = range.start;
 5190                            selection.end = range.end;
 5191
 5192                            return selection;
 5193                        }
 5194                    }
 5195                }
 5196
 5197                let always_treat_brackets_as_autoclosed = buffer
 5198                    .language_settings_at(selection.start, cx)
 5199                    .always_treat_brackets_as_autoclosed;
 5200
 5201                if !always_treat_brackets_as_autoclosed {
 5202                    return selection;
 5203                }
 5204
 5205                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5206                    for (pair, enabled) in scope.brackets() {
 5207                        if !enabled || !pair.close {
 5208                            continue;
 5209                        }
 5210
 5211                        if buffer.contains_str_at(selection.start, &pair.end) {
 5212                            let pair_start_len = pair.start.len();
 5213                            if buffer.contains_str_at(
 5214                                selection.start.saturating_sub_usize(pair_start_len),
 5215                                &pair.start,
 5216                            ) {
 5217                                selection.start -= pair_start_len;
 5218                                selection.end += pair.end.len();
 5219
 5220                                return selection;
 5221                            }
 5222                        }
 5223                    }
 5224                }
 5225
 5226                selection
 5227            })
 5228            .collect();
 5229
 5230        drop(buffer);
 5231        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5232            selections.select(new_selections)
 5233        });
 5234    }
 5235
 5236    /// Iterate the given selections, and for each one, find the smallest surrounding
 5237    /// autoclose region. This uses the ordering of the selections and the autoclose
 5238    /// regions to avoid repeated comparisons.
 5239    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5240        &'a self,
 5241        selections: impl IntoIterator<Item = Selection<D>>,
 5242        buffer: &'a MultiBufferSnapshot,
 5243    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5244        let mut i = 0;
 5245        let mut regions = self.autoclose_regions.as_slice();
 5246        selections.into_iter().map(move |selection| {
 5247            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5248
 5249            let mut enclosing = None;
 5250            while let Some(pair_state) = regions.get(i) {
 5251                if pair_state.range.end.to_offset(buffer) < range.start {
 5252                    regions = &regions[i + 1..];
 5253                    i = 0;
 5254                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5255                    break;
 5256                } else {
 5257                    if pair_state.selection_id == selection.id {
 5258                        enclosing = Some(pair_state);
 5259                    }
 5260                    i += 1;
 5261                }
 5262            }
 5263
 5264            (selection, enclosing)
 5265        })
 5266    }
 5267
 5268    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5269    fn invalidate_autoclose_regions(
 5270        &mut self,
 5271        mut selections: &[Selection<Anchor>],
 5272        buffer: &MultiBufferSnapshot,
 5273    ) {
 5274        self.autoclose_regions.retain(|state| {
 5275            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5276                return false;
 5277            }
 5278
 5279            let mut i = 0;
 5280            while let Some(selection) = selections.get(i) {
 5281                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5282                    selections = &selections[1..];
 5283                    continue;
 5284                }
 5285                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5286                    break;
 5287                }
 5288                if selection.id == state.selection_id {
 5289                    return true;
 5290                } else {
 5291                    i += 1;
 5292                }
 5293            }
 5294            false
 5295        });
 5296    }
 5297
 5298    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5299        let offset = position.to_offset(buffer);
 5300        let (word_range, kind) =
 5301            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5302        if offset > word_range.start && kind == Some(CharKind::Word) {
 5303            Some(
 5304                buffer
 5305                    .text_for_range(word_range.start..offset)
 5306                    .collect::<String>(),
 5307            )
 5308        } else {
 5309            None
 5310        }
 5311    }
 5312
 5313    pub fn visible_excerpts(
 5314        &self,
 5315        lsp_related_only: bool,
 5316        cx: &mut Context<Editor>,
 5317    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5318        let project = self.project().cloned();
 5319        let multi_buffer = self.buffer().read(cx);
 5320        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5321        let multi_buffer_visible_start = self
 5322            .scroll_manager
 5323            .anchor()
 5324            .anchor
 5325            .to_point(&multi_buffer_snapshot);
 5326        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5327            multi_buffer_visible_start
 5328                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5329            Bias::Left,
 5330        );
 5331        multi_buffer_snapshot
 5332            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5333            .into_iter()
 5334            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5335            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5336                if !lsp_related_only {
 5337                    return Some((
 5338                        excerpt_id,
 5339                        (
 5340                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5341                            buffer.version().clone(),
 5342                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5343                        ),
 5344                    ));
 5345                }
 5346
 5347                let project = project.as_ref()?.read(cx);
 5348                let buffer_file = project::File::from_dyn(buffer.file())?;
 5349                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5350                let worktree_entry = buffer_worktree
 5351                    .read(cx)
 5352                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5353                if worktree_entry.is_ignored {
 5354                    None
 5355                } else {
 5356                    Some((
 5357                        excerpt_id,
 5358                        (
 5359                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5360                            buffer.version().clone(),
 5361                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5362                        ),
 5363                    ))
 5364                }
 5365            })
 5366            .collect()
 5367    }
 5368
 5369    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5370        TextLayoutDetails {
 5371            text_system: window.text_system().clone(),
 5372            editor_style: self.style.clone().unwrap(),
 5373            rem_size: window.rem_size(),
 5374            scroll_anchor: self.scroll_manager.anchor(),
 5375            visible_rows: self.visible_line_count(),
 5376            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5377        }
 5378    }
 5379
 5380    fn trigger_on_type_formatting(
 5381        &self,
 5382        input: String,
 5383        window: &mut Window,
 5384        cx: &mut Context<Self>,
 5385    ) -> Option<Task<Result<()>>> {
 5386        if input.len() != 1 {
 5387            return None;
 5388        }
 5389
 5390        let project = self.project()?;
 5391        let position = self.selections.newest_anchor().head();
 5392        let (buffer, buffer_position) = self
 5393            .buffer
 5394            .read(cx)
 5395            .text_anchor_for_position(position, cx)?;
 5396
 5397        let settings = language_settings::language_settings(
 5398            buffer
 5399                .read(cx)
 5400                .language_at(buffer_position)
 5401                .map(|l| l.name()),
 5402            buffer.read(cx).file(),
 5403            cx,
 5404        );
 5405        if !settings.use_on_type_format {
 5406            return None;
 5407        }
 5408
 5409        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5410        // hence we do LSP request & edit on host side only — add formats to host's history.
 5411        let push_to_lsp_host_history = true;
 5412        // If this is not the host, append its history with new edits.
 5413        let push_to_client_history = project.read(cx).is_via_collab();
 5414
 5415        let on_type_formatting = project.update(cx, |project, cx| {
 5416            project.on_type_format(
 5417                buffer.clone(),
 5418                buffer_position,
 5419                input,
 5420                push_to_lsp_host_history,
 5421                cx,
 5422            )
 5423        });
 5424        Some(cx.spawn_in(window, async move |editor, cx| {
 5425            if let Some(transaction) = on_type_formatting.await? {
 5426                if push_to_client_history {
 5427                    buffer
 5428                        .update(cx, |buffer, _| {
 5429                            buffer.push_transaction(transaction, Instant::now());
 5430                            buffer.finalize_last_transaction();
 5431                        })
 5432                        .ok();
 5433                }
 5434                editor.update(cx, |editor, cx| {
 5435                    editor.refresh_document_highlights(cx);
 5436                })?;
 5437            }
 5438            Ok(())
 5439        }))
 5440    }
 5441
 5442    pub fn show_word_completions(
 5443        &mut self,
 5444        _: &ShowWordCompletions,
 5445        window: &mut Window,
 5446        cx: &mut Context<Self>,
 5447    ) {
 5448        self.open_or_update_completions_menu(
 5449            Some(CompletionsMenuSource::Words {
 5450                ignore_threshold: true,
 5451            }),
 5452            None,
 5453            false,
 5454            window,
 5455            cx,
 5456        );
 5457    }
 5458
 5459    pub fn show_completions(
 5460        &mut self,
 5461        _: &ShowCompletions,
 5462        window: &mut Window,
 5463        cx: &mut Context<Self>,
 5464    ) {
 5465        self.open_or_update_completions_menu(None, None, false, window, cx);
 5466    }
 5467
 5468    fn open_or_update_completions_menu(
 5469        &mut self,
 5470        requested_source: Option<CompletionsMenuSource>,
 5471        trigger: Option<String>,
 5472        trigger_in_words: bool,
 5473        window: &mut Window,
 5474        cx: &mut Context<Self>,
 5475    ) {
 5476        if self.pending_rename.is_some() {
 5477            return;
 5478        }
 5479
 5480        let completions_source = self
 5481            .context_menu
 5482            .borrow()
 5483            .as_ref()
 5484            .and_then(|menu| match menu {
 5485                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5486                CodeContextMenu::CodeActions(_) => None,
 5487            });
 5488
 5489        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5490
 5491        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5492        // inserted and selected. To handle that case, the start of the selection is used so that
 5493        // the menu starts with all choices.
 5494        let position = self
 5495            .selections
 5496            .newest_anchor()
 5497            .start
 5498            .bias_right(&multibuffer_snapshot);
 5499        if position.diff_base_anchor.is_some() {
 5500            return;
 5501        }
 5502        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5503        let Some(buffer) = buffer_position
 5504            .text_anchor
 5505            .buffer_id
 5506            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5507        else {
 5508            return;
 5509        };
 5510        let buffer_snapshot = buffer.read(cx).snapshot();
 5511
 5512        let query: Option<Arc<String>> =
 5513            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5514                .map(|query| query.into());
 5515
 5516        drop(multibuffer_snapshot);
 5517
 5518        // Hide the current completions menu when query is empty. Without this, cached
 5519        // completions from before the trigger char may be reused (#32774).
 5520        if query.is_none() {
 5521            let menu_is_open = matches!(
 5522                self.context_menu.borrow().as_ref(),
 5523                Some(CodeContextMenu::Completions(_))
 5524            );
 5525            if menu_is_open {
 5526                self.hide_context_menu(window, cx);
 5527            }
 5528        }
 5529
 5530        let mut ignore_word_threshold = false;
 5531        let provider = match requested_source {
 5532            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5533            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5534                ignore_word_threshold = ignore_threshold;
 5535                None
 5536            }
 5537            Some(CompletionsMenuSource::SnippetChoices)
 5538            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5539                log::error!("bug: SnippetChoices requested_source is not handled");
 5540                None
 5541            }
 5542        };
 5543
 5544        let sort_completions = provider
 5545            .as_ref()
 5546            .is_some_and(|provider| provider.sort_completions());
 5547
 5548        let filter_completions = provider
 5549            .as_ref()
 5550            .is_none_or(|provider| provider.filter_completions());
 5551
 5552        let was_snippets_only = matches!(
 5553            completions_source,
 5554            Some(CompletionsMenuSource::SnippetsOnly)
 5555        );
 5556
 5557        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5558            if filter_completions {
 5559                menu.filter(
 5560                    query.clone().unwrap_or_default(),
 5561                    buffer_position.text_anchor,
 5562                    &buffer,
 5563                    provider.clone(),
 5564                    window,
 5565                    cx,
 5566                );
 5567            }
 5568            // When `is_incomplete` is false, no need to re-query completions when the current query
 5569            // is a suffix of the initial query.
 5570            let was_complete = !menu.is_incomplete;
 5571            if was_complete && !was_snippets_only {
 5572                // If the new query is a suffix of the old query (typing more characters) and
 5573                // the previous result was complete, the existing completions can be filtered.
 5574                //
 5575                // Note that snippet completions are always complete.
 5576                let query_matches = match (&menu.initial_query, &query) {
 5577                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5578                    (None, _) => true,
 5579                    _ => false,
 5580                };
 5581                if query_matches {
 5582                    let position_matches = if menu.initial_position == position {
 5583                        true
 5584                    } else {
 5585                        let snapshot = self.buffer.read(cx).read(cx);
 5586                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5587                    };
 5588                    if position_matches {
 5589                        return;
 5590                    }
 5591                }
 5592            }
 5593        };
 5594
 5595        let Anchor {
 5596            excerpt_id: buffer_excerpt_id,
 5597            text_anchor: buffer_position,
 5598            ..
 5599        } = buffer_position;
 5600
 5601        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5602            buffer_snapshot.surrounding_word(buffer_position, None)
 5603        {
 5604            let word_to_exclude = buffer_snapshot
 5605                .text_for_range(word_range.clone())
 5606                .collect::<String>();
 5607            (
 5608                buffer_snapshot.anchor_before(word_range.start)
 5609                    ..buffer_snapshot.anchor_after(buffer_position),
 5610                Some(word_to_exclude),
 5611            )
 5612        } else {
 5613            (buffer_position..buffer_position, None)
 5614        };
 5615
 5616        let language = buffer_snapshot
 5617            .language_at(buffer_position)
 5618            .map(|language| language.name());
 5619
 5620        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5621            .completions
 5622            .clone();
 5623
 5624        let show_completion_documentation = buffer_snapshot
 5625            .settings_at(buffer_position, cx)
 5626            .show_completion_documentation;
 5627
 5628        // The document can be large, so stay in reasonable bounds when searching for words,
 5629        // otherwise completion pop-up might be slow to appear.
 5630        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5631        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5632        let min_word_search = buffer_snapshot.clip_point(
 5633            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5634            Bias::Left,
 5635        );
 5636        let max_word_search = buffer_snapshot.clip_point(
 5637            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5638            Bias::Right,
 5639        );
 5640        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5641            ..buffer_snapshot.point_to_offset(max_word_search);
 5642
 5643        let skip_digits = query
 5644            .as_ref()
 5645            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5646
 5647        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5648            trigger.as_ref().is_none_or(|trigger| {
 5649                provider.is_completion_trigger(
 5650                    &buffer,
 5651                    position.text_anchor,
 5652                    trigger,
 5653                    trigger_in_words,
 5654                    completions_source.is_some(),
 5655                    cx,
 5656                )
 5657            })
 5658        });
 5659
 5660        let provider_responses = if let Some(provider) = &provider
 5661            && load_provider_completions
 5662        {
 5663            let trigger_character =
 5664                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5665            let completion_context = CompletionContext {
 5666                trigger_kind: match &trigger_character {
 5667                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5668                    None => CompletionTriggerKind::INVOKED,
 5669                },
 5670                trigger_character,
 5671            };
 5672
 5673            provider.completions(
 5674                buffer_excerpt_id,
 5675                &buffer,
 5676                buffer_position,
 5677                completion_context,
 5678                window,
 5679                cx,
 5680            )
 5681        } else {
 5682            Task::ready(Ok(Vec::new()))
 5683        };
 5684
 5685        let load_word_completions = if !self.word_completions_enabled {
 5686            false
 5687        } else if requested_source
 5688            == Some(CompletionsMenuSource::Words {
 5689                ignore_threshold: true,
 5690            })
 5691        {
 5692            true
 5693        } else {
 5694            load_provider_completions
 5695                && completion_settings.words != WordsCompletionMode::Disabled
 5696                && (ignore_word_threshold || {
 5697                    let words_min_length = completion_settings.words_min_length;
 5698                    // check whether word has at least `words_min_length` characters
 5699                    let query_chars = query.iter().flat_map(|q| q.chars());
 5700                    query_chars.take(words_min_length).count() == words_min_length
 5701                })
 5702        };
 5703
 5704        let mut words = if load_word_completions {
 5705            cx.background_spawn({
 5706                let buffer_snapshot = buffer_snapshot.clone();
 5707                async move {
 5708                    buffer_snapshot.words_in_range(WordsQuery {
 5709                        fuzzy_contents: None,
 5710                        range: word_search_range,
 5711                        skip_digits,
 5712                    })
 5713                }
 5714            })
 5715        } else {
 5716            Task::ready(BTreeMap::default())
 5717        };
 5718
 5719        let snippets = if let Some(provider) = &provider
 5720            && provider.show_snippets()
 5721            && let Some(project) = self.project()
 5722        {
 5723            let char_classifier = buffer_snapshot
 5724                .char_classifier_at(buffer_position)
 5725                .scope_context(Some(CharScopeContext::Completion));
 5726            project.update(cx, |project, cx| {
 5727                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5728            })
 5729        } else {
 5730            Task::ready(Ok(CompletionResponse {
 5731                completions: Vec::new(),
 5732                display_options: Default::default(),
 5733                is_incomplete: false,
 5734            }))
 5735        };
 5736
 5737        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5738
 5739        let id = post_inc(&mut self.next_completion_id);
 5740        let task = cx.spawn_in(window, async move |editor, cx| {
 5741            let Ok(()) = editor.update(cx, |this, _| {
 5742                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5743            }) else {
 5744                return;
 5745            };
 5746
 5747            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5748            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5749            let mut completions = Vec::new();
 5750            let mut is_incomplete = false;
 5751            let mut display_options: Option<CompletionDisplayOptions> = None;
 5752            if let Some(provider_responses) = provider_responses.await.log_err()
 5753                && !provider_responses.is_empty()
 5754            {
 5755                for response in provider_responses {
 5756                    completions.extend(response.completions);
 5757                    is_incomplete = is_incomplete || response.is_incomplete;
 5758                    match display_options.as_mut() {
 5759                        None => {
 5760                            display_options = Some(response.display_options);
 5761                        }
 5762                        Some(options) => options.merge(&response.display_options),
 5763                    }
 5764                }
 5765                if completion_settings.words == WordsCompletionMode::Fallback {
 5766                    words = Task::ready(BTreeMap::default());
 5767                }
 5768            }
 5769            let display_options = display_options.unwrap_or_default();
 5770
 5771            let mut words = words.await;
 5772            if let Some(word_to_exclude) = &word_to_exclude {
 5773                words.remove(word_to_exclude);
 5774            }
 5775            for lsp_completion in &completions {
 5776                words.remove(&lsp_completion.new_text);
 5777            }
 5778            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5779                replace_range: word_replace_range.clone(),
 5780                new_text: word.clone(),
 5781                label: CodeLabel::plain(word, None),
 5782                match_start: None,
 5783                snippet_deduplication_key: None,
 5784                icon_path: None,
 5785                documentation: None,
 5786                source: CompletionSource::BufferWord {
 5787                    word_range,
 5788                    resolved: false,
 5789                },
 5790                insert_text_mode: Some(InsertTextMode::AS_IS),
 5791                confirm: None,
 5792            }));
 5793
 5794            completions.extend(
 5795                snippets
 5796                    .await
 5797                    .into_iter()
 5798                    .flat_map(|response| response.completions),
 5799            );
 5800
 5801            let menu = if completions.is_empty() {
 5802                None
 5803            } else {
 5804                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5805                    let languages = editor
 5806                        .workspace
 5807                        .as_ref()
 5808                        .and_then(|(workspace, _)| workspace.upgrade())
 5809                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5810                    let menu = CompletionsMenu::new(
 5811                        id,
 5812                        requested_source.unwrap_or(if load_provider_completions {
 5813                            CompletionsMenuSource::Normal
 5814                        } else {
 5815                            CompletionsMenuSource::SnippetsOnly
 5816                        }),
 5817                        sort_completions,
 5818                        show_completion_documentation,
 5819                        position,
 5820                        query.clone(),
 5821                        is_incomplete,
 5822                        buffer.clone(),
 5823                        completions.into(),
 5824                        display_options,
 5825                        snippet_sort_order,
 5826                        languages,
 5827                        language,
 5828                        cx,
 5829                    );
 5830
 5831                    let query = if filter_completions { query } else { None };
 5832                    let matches_task = menu.do_async_filtering(
 5833                        query.unwrap_or_default(),
 5834                        buffer_position,
 5835                        &buffer,
 5836                        cx,
 5837                    );
 5838                    (menu, matches_task)
 5839                }) else {
 5840                    return;
 5841                };
 5842
 5843                let matches = matches_task.await;
 5844
 5845                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5846                    // Newer menu already set, so exit.
 5847                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5848                        editor.context_menu.borrow().as_ref()
 5849                        && prev_menu.id > id
 5850                    {
 5851                        return;
 5852                    };
 5853
 5854                    // Only valid to take prev_menu because either the new menu is immediately set
 5855                    // below, or the menu is hidden.
 5856                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5857                        editor.context_menu.borrow_mut().take()
 5858                    {
 5859                        let position_matches =
 5860                            if prev_menu.initial_position == menu.initial_position {
 5861                                true
 5862                            } else {
 5863                                let snapshot = editor.buffer.read(cx).read(cx);
 5864                                prev_menu.initial_position.to_offset(&snapshot)
 5865                                    == menu.initial_position.to_offset(&snapshot)
 5866                            };
 5867                        if position_matches {
 5868                            // Preserve markdown cache before `set_filter_results` because it will
 5869                            // try to populate the documentation cache.
 5870                            menu.preserve_markdown_cache(prev_menu);
 5871                        }
 5872                    };
 5873
 5874                    menu.set_filter_results(matches, provider, window, cx);
 5875                }) else {
 5876                    return;
 5877                };
 5878
 5879                menu.visible().then_some(menu)
 5880            };
 5881
 5882            editor
 5883                .update_in(cx, |editor, window, cx| {
 5884                    if editor.focus_handle.is_focused(window)
 5885                        && let Some(menu) = menu
 5886                    {
 5887                        *editor.context_menu.borrow_mut() =
 5888                            Some(CodeContextMenu::Completions(menu));
 5889
 5890                        crate::hover_popover::hide_hover(editor, cx);
 5891                        if editor.show_edit_predictions_in_menu() {
 5892                            editor.update_visible_edit_prediction(window, cx);
 5893                        } else {
 5894                            editor.discard_edit_prediction(false, cx);
 5895                        }
 5896
 5897                        cx.notify();
 5898                        return;
 5899                    }
 5900
 5901                    if editor.completion_tasks.len() <= 1 {
 5902                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5903                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5904                        // If it was already hidden and we don't show edit predictions in the menu,
 5905                        // we should also show the edit prediction when available.
 5906                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5907                            editor.update_visible_edit_prediction(window, cx);
 5908                        }
 5909                    }
 5910                })
 5911                .ok();
 5912        });
 5913
 5914        self.completion_tasks.push((id, task));
 5915    }
 5916
 5917    #[cfg(feature = "test-support")]
 5918    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5919        let menu = self.context_menu.borrow();
 5920        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5921            let completions = menu.completions.borrow();
 5922            Some(completions.to_vec())
 5923        } else {
 5924            None
 5925        }
 5926    }
 5927
 5928    pub fn with_completions_menu_matching_id<R>(
 5929        &self,
 5930        id: CompletionId,
 5931        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5932    ) -> R {
 5933        let mut context_menu = self.context_menu.borrow_mut();
 5934        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5935            return f(None);
 5936        };
 5937        if completions_menu.id != id {
 5938            return f(None);
 5939        }
 5940        f(Some(completions_menu))
 5941    }
 5942
 5943    pub fn confirm_completion(
 5944        &mut self,
 5945        action: &ConfirmCompletion,
 5946        window: &mut Window,
 5947        cx: &mut Context<Self>,
 5948    ) -> Option<Task<Result<()>>> {
 5949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5950        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5951    }
 5952
 5953    pub fn confirm_completion_insert(
 5954        &mut self,
 5955        _: &ConfirmCompletionInsert,
 5956        window: &mut Window,
 5957        cx: &mut Context<Self>,
 5958    ) -> Option<Task<Result<()>>> {
 5959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5960        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5961    }
 5962
 5963    pub fn confirm_completion_replace(
 5964        &mut self,
 5965        _: &ConfirmCompletionReplace,
 5966        window: &mut Window,
 5967        cx: &mut Context<Self>,
 5968    ) -> Option<Task<Result<()>>> {
 5969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5970        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5971    }
 5972
 5973    pub fn compose_completion(
 5974        &mut self,
 5975        action: &ComposeCompletion,
 5976        window: &mut Window,
 5977        cx: &mut Context<Self>,
 5978    ) -> Option<Task<Result<()>>> {
 5979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5980        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5981    }
 5982
 5983    fn do_completion(
 5984        &mut self,
 5985        item_ix: Option<usize>,
 5986        intent: CompletionIntent,
 5987        window: &mut Window,
 5988        cx: &mut Context<Editor>,
 5989    ) -> Option<Task<Result<()>>> {
 5990        use language::ToOffset as _;
 5991
 5992        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5993        else {
 5994            return None;
 5995        };
 5996
 5997        let candidate_id = {
 5998            let entries = completions_menu.entries.borrow();
 5999            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6000            if self.show_edit_predictions_in_menu() {
 6001                self.discard_edit_prediction(true, cx);
 6002            }
 6003            mat.candidate_id
 6004        };
 6005
 6006        let completion = completions_menu
 6007            .completions
 6008            .borrow()
 6009            .get(candidate_id)?
 6010            .clone();
 6011        cx.stop_propagation();
 6012
 6013        let buffer_handle = completions_menu.buffer.clone();
 6014
 6015        let CompletionEdit {
 6016            new_text,
 6017            snippet,
 6018            replace_range,
 6019        } = process_completion_for_edit(
 6020            &completion,
 6021            intent,
 6022            &buffer_handle,
 6023            &completions_menu.initial_position.text_anchor,
 6024            cx,
 6025        );
 6026
 6027        let buffer = buffer_handle.read(cx);
 6028        let snapshot = self.buffer.read(cx).snapshot(cx);
 6029        let newest_anchor = self.selections.newest_anchor();
 6030        let replace_range_multibuffer = {
 6031            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6032            excerpt.map_range_from_buffer(replace_range.clone())
 6033        };
 6034        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6035            return None;
 6036        }
 6037
 6038        let old_text = buffer
 6039            .text_for_range(replace_range.clone())
 6040            .collect::<String>();
 6041        let lookbehind = newest_anchor
 6042            .start
 6043            .text_anchor
 6044            .to_offset(buffer)
 6045            .saturating_sub(replace_range.start.0);
 6046        let lookahead = replace_range
 6047            .end
 6048            .0
 6049            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6050        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6051        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6052
 6053        let selections = self
 6054            .selections
 6055            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6056        let mut ranges = Vec::new();
 6057        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6058
 6059        for selection in &selections {
 6060            let range = if selection.id == newest_anchor.id {
 6061                replace_range_multibuffer.clone()
 6062            } else {
 6063                let mut range = selection.range();
 6064
 6065                // if prefix is present, don't duplicate it
 6066                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6067                    range.start = range.start.saturating_sub_usize(lookbehind);
 6068
 6069                    // if suffix is also present, mimic the newest cursor and replace it
 6070                    if selection.id != newest_anchor.id
 6071                        && snapshot.contains_str_at(range.end, suffix)
 6072                    {
 6073                        range.end += lookahead;
 6074                    }
 6075                }
 6076                range
 6077            };
 6078
 6079            ranges.push(range.clone());
 6080
 6081            if !self.linked_edit_ranges.is_empty() {
 6082                let start_anchor = snapshot.anchor_before(range.start);
 6083                let end_anchor = snapshot.anchor_after(range.end);
 6084                if let Some(ranges) = self
 6085                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6086                {
 6087                    for (buffer, edits) in ranges {
 6088                        linked_edits
 6089                            .entry(buffer.clone())
 6090                            .or_default()
 6091                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6092                    }
 6093                }
 6094            }
 6095        }
 6096
 6097        let common_prefix_len = old_text
 6098            .chars()
 6099            .zip(new_text.chars())
 6100            .take_while(|(a, b)| a == b)
 6101            .map(|(a, _)| a.len_utf8())
 6102            .sum::<usize>();
 6103
 6104        cx.emit(EditorEvent::InputHandled {
 6105            utf16_range_to_replace: None,
 6106            text: new_text[common_prefix_len..].into(),
 6107        });
 6108
 6109        self.transact(window, cx, |editor, window, cx| {
 6110            if let Some(mut snippet) = snippet {
 6111                snippet.text = new_text.to_string();
 6112                editor
 6113                    .insert_snippet(&ranges, snippet, window, cx)
 6114                    .log_err();
 6115            } else {
 6116                editor.buffer.update(cx, |multi_buffer, cx| {
 6117                    let auto_indent = match completion.insert_text_mode {
 6118                        Some(InsertTextMode::AS_IS) => None,
 6119                        _ => editor.autoindent_mode.clone(),
 6120                    };
 6121                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6122                    multi_buffer.edit(edits, auto_indent, cx);
 6123                });
 6124            }
 6125            for (buffer, edits) in linked_edits {
 6126                buffer.update(cx, |buffer, cx| {
 6127                    let snapshot = buffer.snapshot();
 6128                    let edits = edits
 6129                        .into_iter()
 6130                        .map(|(range, text)| {
 6131                            use text::ToPoint as TP;
 6132                            let end_point = TP::to_point(&range.end, &snapshot);
 6133                            let start_point = TP::to_point(&range.start, &snapshot);
 6134                            (start_point..end_point, text)
 6135                        })
 6136                        .sorted_by_key(|(range, _)| range.start);
 6137                    buffer.edit(edits, None, cx);
 6138                })
 6139            }
 6140
 6141            editor.refresh_edit_prediction(true, false, window, cx);
 6142        });
 6143        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6144
 6145        let show_new_completions_on_confirm = completion
 6146            .confirm
 6147            .as_ref()
 6148            .is_some_and(|confirm| confirm(intent, window, cx));
 6149        if show_new_completions_on_confirm {
 6150            self.open_or_update_completions_menu(None, None, false, window, cx);
 6151        }
 6152
 6153        let provider = self.completion_provider.as_ref()?;
 6154        drop(completion);
 6155        let apply_edits = provider.apply_additional_edits_for_completion(
 6156            buffer_handle,
 6157            completions_menu.completions.clone(),
 6158            candidate_id,
 6159            true,
 6160            cx,
 6161        );
 6162
 6163        let editor_settings = EditorSettings::get_global(cx);
 6164        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6165            // After the code completion is finished, users often want to know what signatures are needed.
 6166            // so we should automatically call signature_help
 6167            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6168        }
 6169
 6170        Some(cx.foreground_executor().spawn(async move {
 6171            apply_edits.await?;
 6172            Ok(())
 6173        }))
 6174    }
 6175
 6176    pub fn toggle_code_actions(
 6177        &mut self,
 6178        action: &ToggleCodeActions,
 6179        window: &mut Window,
 6180        cx: &mut Context<Self>,
 6181    ) {
 6182        let quick_launch = action.quick_launch;
 6183        let mut context_menu = self.context_menu.borrow_mut();
 6184        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6185            if code_actions.deployed_from == action.deployed_from {
 6186                // Toggle if we're selecting the same one
 6187                *context_menu = None;
 6188                cx.notify();
 6189                return;
 6190            } else {
 6191                // Otherwise, clear it and start a new one
 6192                *context_menu = None;
 6193                cx.notify();
 6194            }
 6195        }
 6196        drop(context_menu);
 6197        let snapshot = self.snapshot(window, cx);
 6198        let deployed_from = action.deployed_from.clone();
 6199        let action = action.clone();
 6200        self.completion_tasks.clear();
 6201        self.discard_edit_prediction(false, cx);
 6202
 6203        let multibuffer_point = match &action.deployed_from {
 6204            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6205                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6206            }
 6207            _ => self
 6208                .selections
 6209                .newest::<Point>(&snapshot.display_snapshot)
 6210                .head(),
 6211        };
 6212        let Some((buffer, buffer_row)) = snapshot
 6213            .buffer_snapshot()
 6214            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6215            .and_then(|(buffer_snapshot, range)| {
 6216                self.buffer()
 6217                    .read(cx)
 6218                    .buffer(buffer_snapshot.remote_id())
 6219                    .map(|buffer| (buffer, range.start.row))
 6220            })
 6221        else {
 6222            return;
 6223        };
 6224        let buffer_id = buffer.read(cx).remote_id();
 6225        let tasks = self
 6226            .tasks
 6227            .get(&(buffer_id, buffer_row))
 6228            .map(|t| Arc::new(t.to_owned()));
 6229
 6230        if !self.focus_handle.is_focused(window) {
 6231            return;
 6232        }
 6233        let project = self.project.clone();
 6234
 6235        let code_actions_task = match deployed_from {
 6236            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6237            _ => self.code_actions(buffer_row, window, cx),
 6238        };
 6239
 6240        let runnable_task = match deployed_from {
 6241            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6242            _ => {
 6243                let mut task_context_task = Task::ready(None);
 6244                if let Some(tasks) = &tasks
 6245                    && let Some(project) = project
 6246                {
 6247                    task_context_task =
 6248                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6249                }
 6250
 6251                cx.spawn_in(window, {
 6252                    let buffer = buffer.clone();
 6253                    async move |editor, cx| {
 6254                        let task_context = task_context_task.await;
 6255
 6256                        let resolved_tasks =
 6257                            tasks
 6258                                .zip(task_context.clone())
 6259                                .map(|(tasks, task_context)| ResolvedTasks {
 6260                                    templates: tasks.resolve(&task_context).collect(),
 6261                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6262                                        multibuffer_point.row,
 6263                                        tasks.column,
 6264                                    )),
 6265                                });
 6266                        let debug_scenarios = editor
 6267                            .update(cx, |editor, cx| {
 6268                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6269                            })?
 6270                            .await;
 6271                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6272                    }
 6273                })
 6274            }
 6275        };
 6276
 6277        cx.spawn_in(window, async move |editor, cx| {
 6278            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6279            let code_actions = code_actions_task.await;
 6280            let spawn_straight_away = quick_launch
 6281                && resolved_tasks
 6282                    .as_ref()
 6283                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6284                && code_actions
 6285                    .as_ref()
 6286                    .is_none_or(|actions| actions.is_empty())
 6287                && debug_scenarios.is_empty();
 6288
 6289            editor.update_in(cx, |editor, window, cx| {
 6290                crate::hover_popover::hide_hover(editor, cx);
 6291                let actions = CodeActionContents::new(
 6292                    resolved_tasks,
 6293                    code_actions,
 6294                    debug_scenarios,
 6295                    task_context.unwrap_or_default(),
 6296                );
 6297
 6298                // Don't show the menu if there are no actions available
 6299                if actions.is_empty() {
 6300                    cx.notify();
 6301                    return Task::ready(Ok(()));
 6302                }
 6303
 6304                *editor.context_menu.borrow_mut() =
 6305                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6306                        buffer,
 6307                        actions,
 6308                        selected_item: Default::default(),
 6309                        scroll_handle: UniformListScrollHandle::default(),
 6310                        deployed_from,
 6311                    }));
 6312                cx.notify();
 6313                if spawn_straight_away
 6314                    && let Some(task) = editor.confirm_code_action(
 6315                        &ConfirmCodeAction { item_ix: Some(0) },
 6316                        window,
 6317                        cx,
 6318                    )
 6319                {
 6320                    return task;
 6321                }
 6322
 6323                Task::ready(Ok(()))
 6324            })
 6325        })
 6326        .detach_and_log_err(cx);
 6327    }
 6328
 6329    fn debug_scenarios(
 6330        &mut self,
 6331        resolved_tasks: &Option<ResolvedTasks>,
 6332        buffer: &Entity<Buffer>,
 6333        cx: &mut App,
 6334    ) -> Task<Vec<task::DebugScenario>> {
 6335        maybe!({
 6336            let project = self.project()?;
 6337            let dap_store = project.read(cx).dap_store();
 6338            let mut scenarios = vec![];
 6339            let resolved_tasks = resolved_tasks.as_ref()?;
 6340            let buffer = buffer.read(cx);
 6341            let language = buffer.language()?;
 6342            let file = buffer.file();
 6343            let debug_adapter = language_settings(language.name().into(), file, cx)
 6344                .debuggers
 6345                .first()
 6346                .map(SharedString::from)
 6347                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6348
 6349            dap_store.update(cx, |dap_store, cx| {
 6350                for (_, task) in &resolved_tasks.templates {
 6351                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6352                        task.original_task().clone(),
 6353                        debug_adapter.clone().into(),
 6354                        task.display_label().to_owned().into(),
 6355                        cx,
 6356                    );
 6357                    scenarios.push(maybe_scenario);
 6358                }
 6359            });
 6360            Some(cx.background_spawn(async move {
 6361                futures::future::join_all(scenarios)
 6362                    .await
 6363                    .into_iter()
 6364                    .flatten()
 6365                    .collect::<Vec<_>>()
 6366            }))
 6367        })
 6368        .unwrap_or_else(|| Task::ready(vec![]))
 6369    }
 6370
 6371    fn code_actions(
 6372        &mut self,
 6373        buffer_row: u32,
 6374        window: &mut Window,
 6375        cx: &mut Context<Self>,
 6376    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6377        let mut task = self.code_actions_task.take();
 6378        cx.spawn_in(window, async move |editor, cx| {
 6379            while let Some(prev_task) = task {
 6380                prev_task.await.log_err();
 6381                task = editor
 6382                    .update(cx, |this, _| this.code_actions_task.take())
 6383                    .ok()?;
 6384            }
 6385
 6386            editor
 6387                .update(cx, |editor, cx| {
 6388                    editor
 6389                        .available_code_actions
 6390                        .clone()
 6391                        .and_then(|(location, code_actions)| {
 6392                            let snapshot = location.buffer.read(cx).snapshot();
 6393                            let point_range = location.range.to_point(&snapshot);
 6394                            let point_range = point_range.start.row..=point_range.end.row;
 6395                            if point_range.contains(&buffer_row) {
 6396                                Some(code_actions)
 6397                            } else {
 6398                                None
 6399                            }
 6400                        })
 6401                })
 6402                .ok()
 6403                .flatten()
 6404        })
 6405    }
 6406
 6407    pub fn confirm_code_action(
 6408        &mut self,
 6409        action: &ConfirmCodeAction,
 6410        window: &mut Window,
 6411        cx: &mut Context<Self>,
 6412    ) -> Option<Task<Result<()>>> {
 6413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6414
 6415        let actions_menu =
 6416            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6417                menu
 6418            } else {
 6419                return None;
 6420            };
 6421
 6422        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6423        let action = actions_menu.actions.get(action_ix)?;
 6424        let title = action.label();
 6425        let buffer = actions_menu.buffer;
 6426        let workspace = self.workspace()?;
 6427
 6428        match action {
 6429            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6430                workspace.update(cx, |workspace, cx| {
 6431                    workspace.schedule_resolved_task(
 6432                        task_source_kind,
 6433                        resolved_task,
 6434                        false,
 6435                        window,
 6436                        cx,
 6437                    );
 6438
 6439                    Some(Task::ready(Ok(())))
 6440                })
 6441            }
 6442            CodeActionsItem::CodeAction {
 6443                excerpt_id,
 6444                action,
 6445                provider,
 6446            } => {
 6447                let apply_code_action =
 6448                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6449                let workspace = workspace.downgrade();
 6450                Some(cx.spawn_in(window, async move |editor, cx| {
 6451                    let project_transaction = apply_code_action.await?;
 6452                    Self::open_project_transaction(
 6453                        &editor,
 6454                        workspace,
 6455                        project_transaction,
 6456                        title,
 6457                        cx,
 6458                    )
 6459                    .await
 6460                }))
 6461            }
 6462            CodeActionsItem::DebugScenario(scenario) => {
 6463                let context = actions_menu.actions.context;
 6464
 6465                workspace.update(cx, |workspace, cx| {
 6466                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6467                    workspace.start_debug_session(
 6468                        scenario,
 6469                        context,
 6470                        Some(buffer),
 6471                        None,
 6472                        window,
 6473                        cx,
 6474                    );
 6475                });
 6476                Some(Task::ready(Ok(())))
 6477            }
 6478        }
 6479    }
 6480
 6481    pub async fn open_project_transaction(
 6482        editor: &WeakEntity<Editor>,
 6483        workspace: WeakEntity<Workspace>,
 6484        transaction: ProjectTransaction,
 6485        title: String,
 6486        cx: &mut AsyncWindowContext,
 6487    ) -> Result<()> {
 6488        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6489        cx.update(|_, cx| {
 6490            entries.sort_unstable_by_key(|(buffer, _)| {
 6491                buffer.read(cx).file().map(|f| f.path().clone())
 6492            });
 6493        })?;
 6494        if entries.is_empty() {
 6495            return Ok(());
 6496        }
 6497
 6498        // If the project transaction's edits are all contained within this editor, then
 6499        // avoid opening a new editor to display them.
 6500
 6501        if let [(buffer, transaction)] = &*entries {
 6502            let excerpt = editor.update(cx, |editor, cx| {
 6503                editor
 6504                    .buffer()
 6505                    .read(cx)
 6506                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6507            })?;
 6508            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6509                && excerpted_buffer == *buffer
 6510            {
 6511                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6512                    let excerpt_range = excerpt_range.to_offset(buffer);
 6513                    buffer
 6514                        .edited_ranges_for_transaction::<usize>(transaction)
 6515                        .all(|range| {
 6516                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6517                        })
 6518                })?;
 6519
 6520                if all_edits_within_excerpt {
 6521                    return Ok(());
 6522                }
 6523            }
 6524        }
 6525
 6526        let mut ranges_to_highlight = Vec::new();
 6527        let excerpt_buffer = cx.new(|cx| {
 6528            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6529            for (buffer_handle, transaction) in &entries {
 6530                let edited_ranges = buffer_handle
 6531                    .read(cx)
 6532                    .edited_ranges_for_transaction::<Point>(transaction)
 6533                    .collect::<Vec<_>>();
 6534                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6535                    PathKey::for_buffer(buffer_handle, cx),
 6536                    buffer_handle.clone(),
 6537                    edited_ranges,
 6538                    multibuffer_context_lines(cx),
 6539                    cx,
 6540                );
 6541
 6542                ranges_to_highlight.extend(ranges);
 6543            }
 6544            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6545            multibuffer
 6546        })?;
 6547
 6548        workspace.update_in(cx, |workspace, window, cx| {
 6549            let project = workspace.project().clone();
 6550            let editor =
 6551                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6552            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6553            editor.update(cx, |editor, cx| {
 6554                editor.highlight_background::<Self>(
 6555                    &ranges_to_highlight,
 6556                    |theme| theme.colors().editor_highlighted_line_background,
 6557                    cx,
 6558                );
 6559            });
 6560        })?;
 6561
 6562        Ok(())
 6563    }
 6564
 6565    pub fn clear_code_action_providers(&mut self) {
 6566        self.code_action_providers.clear();
 6567        self.available_code_actions.take();
 6568    }
 6569
 6570    pub fn add_code_action_provider(
 6571        &mut self,
 6572        provider: Rc<dyn CodeActionProvider>,
 6573        window: &mut Window,
 6574        cx: &mut Context<Self>,
 6575    ) {
 6576        if self
 6577            .code_action_providers
 6578            .iter()
 6579            .any(|existing_provider| existing_provider.id() == provider.id())
 6580        {
 6581            return;
 6582        }
 6583
 6584        self.code_action_providers.push(provider);
 6585        self.refresh_code_actions(window, cx);
 6586    }
 6587
 6588    pub fn remove_code_action_provider(
 6589        &mut self,
 6590        id: Arc<str>,
 6591        window: &mut Window,
 6592        cx: &mut Context<Self>,
 6593    ) {
 6594        self.code_action_providers
 6595            .retain(|provider| provider.id() != id);
 6596        self.refresh_code_actions(window, cx);
 6597    }
 6598
 6599    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6600        !self.code_action_providers.is_empty()
 6601            && EditorSettings::get_global(cx).toolbar.code_actions
 6602    }
 6603
 6604    pub fn has_available_code_actions(&self) -> bool {
 6605        self.available_code_actions
 6606            .as_ref()
 6607            .is_some_and(|(_, actions)| !actions.is_empty())
 6608    }
 6609
 6610    fn render_inline_code_actions(
 6611        &self,
 6612        icon_size: ui::IconSize,
 6613        display_row: DisplayRow,
 6614        is_active: bool,
 6615        cx: &mut Context<Self>,
 6616    ) -> AnyElement {
 6617        let show_tooltip = !self.context_menu_visible();
 6618        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6619            .icon_size(icon_size)
 6620            .shape(ui::IconButtonShape::Square)
 6621            .icon_color(ui::Color::Hidden)
 6622            .toggle_state(is_active)
 6623            .when(show_tooltip, |this| {
 6624                this.tooltip({
 6625                    let focus_handle = self.focus_handle.clone();
 6626                    move |_window, cx| {
 6627                        Tooltip::for_action_in(
 6628                            "Toggle Code Actions",
 6629                            &ToggleCodeActions {
 6630                                deployed_from: None,
 6631                                quick_launch: false,
 6632                            },
 6633                            &focus_handle,
 6634                            cx,
 6635                        )
 6636                    }
 6637                })
 6638            })
 6639            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6640                window.focus(&editor.focus_handle(cx));
 6641                editor.toggle_code_actions(
 6642                    &crate::actions::ToggleCodeActions {
 6643                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6644                            display_row,
 6645                        )),
 6646                        quick_launch: false,
 6647                    },
 6648                    window,
 6649                    cx,
 6650                );
 6651            }))
 6652            .into_any_element()
 6653    }
 6654
 6655    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6656        &self.context_menu
 6657    }
 6658
 6659    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6660        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6661            cx.background_executor()
 6662                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6663                .await;
 6664
 6665            let (start_buffer, start, _, end, newest_selection) = this
 6666                .update(cx, |this, cx| {
 6667                    let newest_selection = this.selections.newest_anchor().clone();
 6668                    if newest_selection.head().diff_base_anchor.is_some() {
 6669                        return None;
 6670                    }
 6671                    let display_snapshot = this.display_snapshot(cx);
 6672                    let newest_selection_adjusted =
 6673                        this.selections.newest_adjusted(&display_snapshot);
 6674                    let buffer = this.buffer.read(cx);
 6675
 6676                    let (start_buffer, start) =
 6677                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6678                    let (end_buffer, end) =
 6679                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6680
 6681                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6682                })?
 6683                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6684                .context(
 6685                    "Expected selection to lie in a single buffer when refreshing code actions",
 6686                )?;
 6687            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6688                let providers = this.code_action_providers.clone();
 6689                let tasks = this
 6690                    .code_action_providers
 6691                    .iter()
 6692                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6693                    .collect::<Vec<_>>();
 6694                (providers, tasks)
 6695            })?;
 6696
 6697            let mut actions = Vec::new();
 6698            for (provider, provider_actions) in
 6699                providers.into_iter().zip(future::join_all(tasks).await)
 6700            {
 6701                if let Some(provider_actions) = provider_actions.log_err() {
 6702                    actions.extend(provider_actions.into_iter().map(|action| {
 6703                        AvailableCodeAction {
 6704                            excerpt_id: newest_selection.start.excerpt_id,
 6705                            action,
 6706                            provider: provider.clone(),
 6707                        }
 6708                    }));
 6709                }
 6710            }
 6711
 6712            this.update(cx, |this, cx| {
 6713                this.available_code_actions = if actions.is_empty() {
 6714                    None
 6715                } else {
 6716                    Some((
 6717                        Location {
 6718                            buffer: start_buffer,
 6719                            range: start..end,
 6720                        },
 6721                        actions.into(),
 6722                    ))
 6723                };
 6724                cx.notify();
 6725            })
 6726        }));
 6727    }
 6728
 6729    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6730        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6731            self.show_git_blame_inline = false;
 6732
 6733            self.show_git_blame_inline_delay_task =
 6734                Some(cx.spawn_in(window, async move |this, cx| {
 6735                    cx.background_executor().timer(delay).await;
 6736
 6737                    this.update(cx, |this, cx| {
 6738                        this.show_git_blame_inline = true;
 6739                        cx.notify();
 6740                    })
 6741                    .log_err();
 6742                }));
 6743        }
 6744    }
 6745
 6746    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6747        let snapshot = self.snapshot(window, cx);
 6748        let cursor = self
 6749            .selections
 6750            .newest::<Point>(&snapshot.display_snapshot)
 6751            .head();
 6752        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6753        else {
 6754            return;
 6755        };
 6756
 6757        let Some(blame) = self.blame.as_ref() else {
 6758            return;
 6759        };
 6760
 6761        let row_info = RowInfo {
 6762            buffer_id: Some(buffer.remote_id()),
 6763            buffer_row: Some(point.row),
 6764            ..Default::default()
 6765        };
 6766        let Some((buffer, blame_entry)) = blame
 6767            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6768            .flatten()
 6769        else {
 6770            return;
 6771        };
 6772
 6773        let anchor = self.selections.newest_anchor().head();
 6774        let position = self.to_pixel_point(anchor, &snapshot, window);
 6775        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6776            self.show_blame_popover(
 6777                buffer,
 6778                &blame_entry,
 6779                position + last_bounds.origin,
 6780                true,
 6781                cx,
 6782            );
 6783        };
 6784    }
 6785
 6786    fn show_blame_popover(
 6787        &mut self,
 6788        buffer: BufferId,
 6789        blame_entry: &BlameEntry,
 6790        position: gpui::Point<Pixels>,
 6791        ignore_timeout: bool,
 6792        cx: &mut Context<Self>,
 6793    ) {
 6794        if let Some(state) = &mut self.inline_blame_popover {
 6795            state.hide_task.take();
 6796        } else {
 6797            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6798            let blame_entry = blame_entry.clone();
 6799            let show_task = cx.spawn(async move |editor, cx| {
 6800                if !ignore_timeout {
 6801                    cx.background_executor()
 6802                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6803                        .await;
 6804                }
 6805                editor
 6806                    .update(cx, |editor, cx| {
 6807                        editor.inline_blame_popover_show_task.take();
 6808                        let Some(blame) = editor.blame.as_ref() else {
 6809                            return;
 6810                        };
 6811                        let blame = blame.read(cx);
 6812                        let details = blame.details_for_entry(buffer, &blame_entry);
 6813                        let markdown = cx.new(|cx| {
 6814                            Markdown::new(
 6815                                details
 6816                                    .as_ref()
 6817                                    .map(|message| message.message.clone())
 6818                                    .unwrap_or_default(),
 6819                                None,
 6820                                None,
 6821                                cx,
 6822                            )
 6823                        });
 6824                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6825                            position,
 6826                            hide_task: None,
 6827                            popover_bounds: None,
 6828                            popover_state: InlineBlamePopoverState {
 6829                                scroll_handle: ScrollHandle::new(),
 6830                                commit_message: details,
 6831                                markdown,
 6832                            },
 6833                            keyboard_grace: ignore_timeout,
 6834                        });
 6835                        cx.notify();
 6836                    })
 6837                    .ok();
 6838            });
 6839            self.inline_blame_popover_show_task = Some(show_task);
 6840        }
 6841    }
 6842
 6843    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6844        self.inline_blame_popover_show_task.take();
 6845        if let Some(state) = &mut self.inline_blame_popover {
 6846            let hide_task = cx.spawn(async move |editor, cx| {
 6847                if !ignore_timeout {
 6848                    cx.background_executor()
 6849                        .timer(std::time::Duration::from_millis(100))
 6850                        .await;
 6851                }
 6852                editor
 6853                    .update(cx, |editor, cx| {
 6854                        editor.inline_blame_popover.take();
 6855                        cx.notify();
 6856                    })
 6857                    .ok();
 6858            });
 6859            state.hide_task = Some(hide_task);
 6860            true
 6861        } else {
 6862            false
 6863        }
 6864    }
 6865
 6866    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6867        if self.pending_rename.is_some() {
 6868            return None;
 6869        }
 6870
 6871        let provider = self.semantics_provider.clone()?;
 6872        let buffer = self.buffer.read(cx);
 6873        let newest_selection = self.selections.newest_anchor().clone();
 6874        let cursor_position = newest_selection.head();
 6875        let (cursor_buffer, cursor_buffer_position) =
 6876            buffer.text_anchor_for_position(cursor_position, cx)?;
 6877        let (tail_buffer, tail_buffer_position) =
 6878            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6879        if cursor_buffer != tail_buffer {
 6880            return None;
 6881        }
 6882
 6883        let snapshot = cursor_buffer.read(cx).snapshot();
 6884        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6885        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6886        if start_word_range != end_word_range {
 6887            self.document_highlights_task.take();
 6888            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6889            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6890            return None;
 6891        }
 6892
 6893        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6894        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6895            cx.background_executor()
 6896                .timer(Duration::from_millis(debounce))
 6897                .await;
 6898
 6899            let highlights = if let Some(highlights) = cx
 6900                .update(|cx| {
 6901                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6902                })
 6903                .ok()
 6904                .flatten()
 6905            {
 6906                highlights.await.log_err()
 6907            } else {
 6908                None
 6909            };
 6910
 6911            if let Some(highlights) = highlights {
 6912                this.update(cx, |this, cx| {
 6913                    if this.pending_rename.is_some() {
 6914                        return;
 6915                    }
 6916
 6917                    let buffer = this.buffer.read(cx);
 6918                    if buffer
 6919                        .text_anchor_for_position(cursor_position, cx)
 6920                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6921                    {
 6922                        return;
 6923                    }
 6924
 6925                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6926                    let mut write_ranges = Vec::new();
 6927                    let mut read_ranges = Vec::new();
 6928                    for highlight in highlights {
 6929                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6930                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6931                        {
 6932                            let start = highlight
 6933                                .range
 6934                                .start
 6935                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6936                            let end = highlight
 6937                                .range
 6938                                .end
 6939                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6940                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6941                                continue;
 6942                            }
 6943
 6944                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 6945                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6946                                write_ranges.push(range);
 6947                            } else {
 6948                                read_ranges.push(range);
 6949                            }
 6950                        }
 6951                    }
 6952
 6953                    this.highlight_background::<DocumentHighlightRead>(
 6954                        &read_ranges,
 6955                        |theme| theme.colors().editor_document_highlight_read_background,
 6956                        cx,
 6957                    );
 6958                    this.highlight_background::<DocumentHighlightWrite>(
 6959                        &write_ranges,
 6960                        |theme| theme.colors().editor_document_highlight_write_background,
 6961                        cx,
 6962                    );
 6963                    cx.notify();
 6964                })
 6965                .log_err();
 6966            }
 6967        }));
 6968        None
 6969    }
 6970
 6971    fn prepare_highlight_query_from_selection(
 6972        &mut self,
 6973        window: &Window,
 6974        cx: &mut Context<Editor>,
 6975    ) -> Option<(String, Range<Anchor>)> {
 6976        if matches!(self.mode, EditorMode::SingleLine) {
 6977            return None;
 6978        }
 6979        if !EditorSettings::get_global(cx).selection_highlight {
 6980            return None;
 6981        }
 6982        if self.selections.count() != 1 || self.selections.line_mode() {
 6983            return None;
 6984        }
 6985        let snapshot = self.snapshot(window, cx);
 6986        let selection = self.selections.newest::<Point>(&snapshot);
 6987        // If the selection spans multiple rows OR it is empty
 6988        if selection.start.row != selection.end.row
 6989            || selection.start.column == selection.end.column
 6990        {
 6991            return None;
 6992        }
 6993        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6994        let query = snapshot
 6995            .buffer_snapshot()
 6996            .text_for_range(selection_anchor_range.clone())
 6997            .collect::<String>();
 6998        if query.trim().is_empty() {
 6999            return None;
 7000        }
 7001        Some((query, selection_anchor_range))
 7002    }
 7003
 7004    fn update_selection_occurrence_highlights(
 7005        &mut self,
 7006        query_text: String,
 7007        query_range: Range<Anchor>,
 7008        multi_buffer_range_to_query: Range<Point>,
 7009        use_debounce: bool,
 7010        window: &mut Window,
 7011        cx: &mut Context<Editor>,
 7012    ) -> Task<()> {
 7013        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7014        cx.spawn_in(window, async move |editor, cx| {
 7015            if use_debounce {
 7016                cx.background_executor()
 7017                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7018                    .await;
 7019            }
 7020            let match_task = cx.background_spawn(async move {
 7021                let buffer_ranges = multi_buffer_snapshot
 7022                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7023                    .into_iter()
 7024                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7025                let mut match_ranges = Vec::new();
 7026                let Ok(regex) = project::search::SearchQuery::text(
 7027                    query_text.clone(),
 7028                    false,
 7029                    false,
 7030                    false,
 7031                    Default::default(),
 7032                    Default::default(),
 7033                    false,
 7034                    None,
 7035                ) else {
 7036                    return Vec::default();
 7037                };
 7038                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7039                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7040                    match_ranges.extend(
 7041                        regex
 7042                            .search(
 7043                                buffer_snapshot,
 7044                                Some(search_range.start.0..search_range.end.0),
 7045                            )
 7046                            .await
 7047                            .into_iter()
 7048                            .filter_map(|match_range| {
 7049                                let match_start = buffer_snapshot
 7050                                    .anchor_after(search_range.start + match_range.start);
 7051                                let match_end = buffer_snapshot
 7052                                    .anchor_before(search_range.start + match_range.end);
 7053                                let match_anchor_range =
 7054                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7055                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7056                            }),
 7057                    );
 7058                }
 7059                match_ranges
 7060            });
 7061            let match_ranges = match_task.await;
 7062            editor
 7063                .update_in(cx, |editor, _, cx| {
 7064                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7065                    if !match_ranges.is_empty() {
 7066                        editor.highlight_background::<SelectedTextHighlight>(
 7067                            &match_ranges,
 7068                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7069                            cx,
 7070                        )
 7071                    }
 7072                })
 7073                .log_err();
 7074        })
 7075    }
 7076
 7077    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7078        struct NewlineFold;
 7079        let type_id = std::any::TypeId::of::<NewlineFold>();
 7080        if !self.mode.is_single_line() {
 7081            return;
 7082        }
 7083        let snapshot = self.snapshot(window, cx);
 7084        if snapshot.buffer_snapshot().max_point().row == 0 {
 7085            return;
 7086        }
 7087        let task = cx.background_spawn(async move {
 7088            let new_newlines = snapshot
 7089                .buffer_chars_at(MultiBufferOffset(0))
 7090                .filter_map(|(c, i)| {
 7091                    if c == '\n' {
 7092                        Some(
 7093                            snapshot.buffer_snapshot().anchor_after(i)
 7094                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7095                        )
 7096                    } else {
 7097                        None
 7098                    }
 7099                })
 7100                .collect::<Vec<_>>();
 7101            let existing_newlines = snapshot
 7102                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7103                .filter_map(|fold| {
 7104                    if fold.placeholder.type_tag == Some(type_id) {
 7105                        Some(fold.range.start..fold.range.end)
 7106                    } else {
 7107                        None
 7108                    }
 7109                })
 7110                .collect::<Vec<_>>();
 7111
 7112            (new_newlines, existing_newlines)
 7113        });
 7114        self.folding_newlines = cx.spawn(async move |this, cx| {
 7115            let (new_newlines, existing_newlines) = task.await;
 7116            if new_newlines == existing_newlines {
 7117                return;
 7118            }
 7119            let placeholder = FoldPlaceholder {
 7120                render: Arc::new(move |_, _, cx| {
 7121                    div()
 7122                        .bg(cx.theme().status().hint_background)
 7123                        .border_b_1()
 7124                        .size_full()
 7125                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7126                        .border_color(cx.theme().status().hint)
 7127                        .child("\\n")
 7128                        .into_any()
 7129                }),
 7130                constrain_width: false,
 7131                merge_adjacent: false,
 7132                type_tag: Some(type_id),
 7133            };
 7134            let creases = new_newlines
 7135                .into_iter()
 7136                .map(|range| Crease::simple(range, placeholder.clone()))
 7137                .collect();
 7138            this.update(cx, |this, cx| {
 7139                this.display_map.update(cx, |display_map, cx| {
 7140                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7141                    display_map.fold(creases, cx);
 7142                });
 7143            })
 7144            .ok();
 7145        });
 7146    }
 7147
 7148    fn refresh_selected_text_highlights(
 7149        &mut self,
 7150        on_buffer_edit: bool,
 7151        window: &mut Window,
 7152        cx: &mut Context<Editor>,
 7153    ) {
 7154        let Some((query_text, query_range)) =
 7155            self.prepare_highlight_query_from_selection(window, cx)
 7156        else {
 7157            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7158            self.quick_selection_highlight_task.take();
 7159            self.debounced_selection_highlight_task.take();
 7160            return;
 7161        };
 7162        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7163        if on_buffer_edit
 7164            || self
 7165                .quick_selection_highlight_task
 7166                .as_ref()
 7167                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7168        {
 7169            let multi_buffer_visible_start = self
 7170                .scroll_manager
 7171                .anchor()
 7172                .anchor
 7173                .to_point(&multi_buffer_snapshot);
 7174            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7175                multi_buffer_visible_start
 7176                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7177                Bias::Left,
 7178            );
 7179            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7180            self.quick_selection_highlight_task = Some((
 7181                query_range.clone(),
 7182                self.update_selection_occurrence_highlights(
 7183                    query_text.clone(),
 7184                    query_range.clone(),
 7185                    multi_buffer_visible_range,
 7186                    false,
 7187                    window,
 7188                    cx,
 7189                ),
 7190            ));
 7191        }
 7192        if on_buffer_edit
 7193            || self
 7194                .debounced_selection_highlight_task
 7195                .as_ref()
 7196                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7197        {
 7198            let multi_buffer_start = multi_buffer_snapshot
 7199                .anchor_before(MultiBufferOffset(0))
 7200                .to_point(&multi_buffer_snapshot);
 7201            let multi_buffer_end = multi_buffer_snapshot
 7202                .anchor_after(multi_buffer_snapshot.len())
 7203                .to_point(&multi_buffer_snapshot);
 7204            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7205            self.debounced_selection_highlight_task = Some((
 7206                query_range.clone(),
 7207                self.update_selection_occurrence_highlights(
 7208                    query_text,
 7209                    query_range,
 7210                    multi_buffer_full_range,
 7211                    true,
 7212                    window,
 7213                    cx,
 7214                ),
 7215            ));
 7216        }
 7217    }
 7218
 7219    pub fn refresh_edit_prediction(
 7220        &mut self,
 7221        debounce: bool,
 7222        user_requested: bool,
 7223        window: &mut Window,
 7224        cx: &mut Context<Self>,
 7225    ) -> Option<()> {
 7226        if DisableAiSettings::get_global(cx).disable_ai {
 7227            return None;
 7228        }
 7229
 7230        let provider = self.edit_prediction_provider()?;
 7231        let cursor = self.selections.newest_anchor().head();
 7232        let (buffer, cursor_buffer_position) =
 7233            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7234
 7235        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7236            self.discard_edit_prediction(false, cx);
 7237            return None;
 7238        }
 7239
 7240        self.update_visible_edit_prediction(window, cx);
 7241
 7242        if !user_requested
 7243            && (!self.should_show_edit_predictions()
 7244                || !self.is_focused(window)
 7245                || buffer.read(cx).is_empty())
 7246        {
 7247            self.discard_edit_prediction(false, cx);
 7248            return None;
 7249        }
 7250
 7251        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7252        Some(())
 7253    }
 7254
 7255    fn show_edit_predictions_in_menu(&self) -> bool {
 7256        match self.edit_prediction_settings {
 7257            EditPredictionSettings::Disabled => false,
 7258            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7259        }
 7260    }
 7261
 7262    pub fn edit_predictions_enabled(&self) -> bool {
 7263        match self.edit_prediction_settings {
 7264            EditPredictionSettings::Disabled => false,
 7265            EditPredictionSettings::Enabled { .. } => true,
 7266        }
 7267    }
 7268
 7269    fn edit_prediction_requires_modifier(&self) -> bool {
 7270        match self.edit_prediction_settings {
 7271            EditPredictionSettings::Disabled => false,
 7272            EditPredictionSettings::Enabled {
 7273                preview_requires_modifier,
 7274                ..
 7275            } => preview_requires_modifier,
 7276        }
 7277    }
 7278
 7279    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7280        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7281            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7282            self.discard_edit_prediction(false, cx);
 7283        } else {
 7284            let selection = self.selections.newest_anchor();
 7285            let cursor = selection.head();
 7286
 7287            if let Some((buffer, cursor_buffer_position)) =
 7288                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7289            {
 7290                self.edit_prediction_settings =
 7291                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7292            }
 7293        }
 7294    }
 7295
 7296    fn edit_prediction_settings_at_position(
 7297        &self,
 7298        buffer: &Entity<Buffer>,
 7299        buffer_position: language::Anchor,
 7300        cx: &App,
 7301    ) -> EditPredictionSettings {
 7302        if !self.mode.is_full()
 7303            || !self.show_edit_predictions_override.unwrap_or(true)
 7304            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7305        {
 7306            return EditPredictionSettings::Disabled;
 7307        }
 7308
 7309        let buffer = buffer.read(cx);
 7310
 7311        let file = buffer.file();
 7312
 7313        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7314            return EditPredictionSettings::Disabled;
 7315        };
 7316
 7317        let by_provider = matches!(
 7318            self.menu_edit_predictions_policy,
 7319            MenuEditPredictionsPolicy::ByProvider
 7320        );
 7321
 7322        let show_in_menu = by_provider
 7323            && self
 7324                .edit_prediction_provider
 7325                .as_ref()
 7326                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7327
 7328        let preview_requires_modifier =
 7329            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7330
 7331        EditPredictionSettings::Enabled {
 7332            show_in_menu,
 7333            preview_requires_modifier,
 7334        }
 7335    }
 7336
 7337    fn should_show_edit_predictions(&self) -> bool {
 7338        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7339    }
 7340
 7341    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7342        matches!(
 7343            self.edit_prediction_preview,
 7344            EditPredictionPreview::Active { .. }
 7345        )
 7346    }
 7347
 7348    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7349        let cursor = self.selections.newest_anchor().head();
 7350        if let Some((buffer, cursor_position)) =
 7351            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7352        {
 7353            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7354        } else {
 7355            false
 7356        }
 7357    }
 7358
 7359    pub fn supports_minimap(&self, cx: &App) -> bool {
 7360        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7361    }
 7362
 7363    fn edit_predictions_enabled_in_buffer(
 7364        &self,
 7365        buffer: &Entity<Buffer>,
 7366        buffer_position: language::Anchor,
 7367        cx: &App,
 7368    ) -> bool {
 7369        maybe!({
 7370            if self.read_only(cx) {
 7371                return Some(false);
 7372            }
 7373            let provider = self.edit_prediction_provider()?;
 7374            if !provider.is_enabled(buffer, buffer_position, cx) {
 7375                return Some(false);
 7376            }
 7377            let buffer = buffer.read(cx);
 7378            let Some(file) = buffer.file() else {
 7379                return Some(true);
 7380            };
 7381            let settings = all_language_settings(Some(file), cx);
 7382            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7383        })
 7384        .unwrap_or(false)
 7385    }
 7386
 7387    fn cycle_edit_prediction(
 7388        &mut self,
 7389        direction: Direction,
 7390        window: &mut Window,
 7391        cx: &mut Context<Self>,
 7392    ) -> Option<()> {
 7393        let provider = self.edit_prediction_provider()?;
 7394        let cursor = self.selections.newest_anchor().head();
 7395        let (buffer, cursor_buffer_position) =
 7396            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7397        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7398            return None;
 7399        }
 7400
 7401        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7402        self.update_visible_edit_prediction(window, cx);
 7403
 7404        Some(())
 7405    }
 7406
 7407    pub fn show_edit_prediction(
 7408        &mut self,
 7409        _: &ShowEditPrediction,
 7410        window: &mut Window,
 7411        cx: &mut Context<Self>,
 7412    ) {
 7413        if !self.has_active_edit_prediction() {
 7414            self.refresh_edit_prediction(false, true, window, cx);
 7415            return;
 7416        }
 7417
 7418        self.update_visible_edit_prediction(window, cx);
 7419    }
 7420
 7421    pub fn display_cursor_names(
 7422        &mut self,
 7423        _: &DisplayCursorNames,
 7424        window: &mut Window,
 7425        cx: &mut Context<Self>,
 7426    ) {
 7427        self.show_cursor_names(window, cx);
 7428    }
 7429
 7430    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7431        self.show_cursor_names = true;
 7432        cx.notify();
 7433        cx.spawn_in(window, async move |this, cx| {
 7434            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7435            this.update(cx, |this, cx| {
 7436                this.show_cursor_names = false;
 7437                cx.notify()
 7438            })
 7439            .ok()
 7440        })
 7441        .detach();
 7442    }
 7443
 7444    pub fn next_edit_prediction(
 7445        &mut self,
 7446        _: &NextEditPrediction,
 7447        window: &mut Window,
 7448        cx: &mut Context<Self>,
 7449    ) {
 7450        if self.has_active_edit_prediction() {
 7451            self.cycle_edit_prediction(Direction::Next, window, cx);
 7452        } else {
 7453            let is_copilot_disabled = self
 7454                .refresh_edit_prediction(false, true, window, cx)
 7455                .is_none();
 7456            if is_copilot_disabled {
 7457                cx.propagate();
 7458            }
 7459        }
 7460    }
 7461
 7462    pub fn previous_edit_prediction(
 7463        &mut self,
 7464        _: &PreviousEditPrediction,
 7465        window: &mut Window,
 7466        cx: &mut Context<Self>,
 7467    ) {
 7468        if self.has_active_edit_prediction() {
 7469            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7470        } else {
 7471            let is_copilot_disabled = self
 7472                .refresh_edit_prediction(false, true, window, cx)
 7473                .is_none();
 7474            if is_copilot_disabled {
 7475                cx.propagate();
 7476            }
 7477        }
 7478    }
 7479
 7480    pub fn accept_edit_prediction(
 7481        &mut self,
 7482        _: &AcceptEditPrediction,
 7483        window: &mut Window,
 7484        cx: &mut Context<Self>,
 7485    ) {
 7486        if self.show_edit_predictions_in_menu() {
 7487            self.hide_context_menu(window, cx);
 7488        }
 7489
 7490        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7491            return;
 7492        };
 7493
 7494        match &active_edit_prediction.completion {
 7495            EditPrediction::MoveWithin { target, .. } => {
 7496                let target = *target;
 7497
 7498                if let Some(position_map) = &self.last_position_map {
 7499                    if position_map
 7500                        .visible_row_range
 7501                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7502                        || !self.edit_prediction_requires_modifier()
 7503                    {
 7504                        self.unfold_ranges(&[target..target], true, false, cx);
 7505                        // Note that this is also done in vim's handler of the Tab action.
 7506                        self.change_selections(
 7507                            SelectionEffects::scroll(Autoscroll::newest()),
 7508                            window,
 7509                            cx,
 7510                            |selections| {
 7511                                selections.select_anchor_ranges([target..target]);
 7512                            },
 7513                        );
 7514                        self.clear_row_highlights::<EditPredictionPreview>();
 7515
 7516                        self.edit_prediction_preview
 7517                            .set_previous_scroll_position(None);
 7518                    } else {
 7519                        self.edit_prediction_preview
 7520                            .set_previous_scroll_position(Some(
 7521                                position_map.snapshot.scroll_anchor,
 7522                            ));
 7523
 7524                        self.highlight_rows::<EditPredictionPreview>(
 7525                            target..target,
 7526                            cx.theme().colors().editor_highlighted_line_background,
 7527                            RowHighlightOptions {
 7528                                autoscroll: true,
 7529                                ..Default::default()
 7530                            },
 7531                            cx,
 7532                        );
 7533                        self.request_autoscroll(Autoscroll::fit(), cx);
 7534                    }
 7535                }
 7536            }
 7537            EditPrediction::MoveOutside { snapshot, target } => {
 7538                if let Some(workspace) = self.workspace() {
 7539                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7540                        .detach_and_log_err(cx);
 7541                }
 7542            }
 7543            EditPrediction::Edit { edits, .. } => {
 7544                self.report_edit_prediction_event(
 7545                    active_edit_prediction.completion_id.clone(),
 7546                    true,
 7547                    cx,
 7548                );
 7549
 7550                if let Some(provider) = self.edit_prediction_provider() {
 7551                    provider.accept(cx);
 7552                }
 7553
 7554                // Store the transaction ID and selections before applying the edit
 7555                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7556
 7557                let snapshot = self.buffer.read(cx).snapshot(cx);
 7558                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7559
 7560                self.buffer.update(cx, |buffer, cx| {
 7561                    buffer.edit(edits.iter().cloned(), None, cx)
 7562                });
 7563
 7564                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7565                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7566                });
 7567
 7568                let selections = self.selections.disjoint_anchors_arc();
 7569                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7570                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7571                    if has_new_transaction {
 7572                        self.selection_history
 7573                            .insert_transaction(transaction_id_now, selections);
 7574                    }
 7575                }
 7576
 7577                self.update_visible_edit_prediction(window, cx);
 7578                if self.active_edit_prediction.is_none() {
 7579                    self.refresh_edit_prediction(true, true, window, cx);
 7580                }
 7581
 7582                cx.notify();
 7583            }
 7584        }
 7585
 7586        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7587    }
 7588
 7589    pub fn accept_partial_edit_prediction(
 7590        &mut self,
 7591        _: &AcceptPartialEditPrediction,
 7592        window: &mut Window,
 7593        cx: &mut Context<Self>,
 7594    ) {
 7595        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7596            return;
 7597        };
 7598        if self.selections.count() != 1 {
 7599            return;
 7600        }
 7601
 7602        match &active_edit_prediction.completion {
 7603            EditPrediction::MoveWithin { target, .. } => {
 7604                let target = *target;
 7605                self.change_selections(
 7606                    SelectionEffects::scroll(Autoscroll::newest()),
 7607                    window,
 7608                    cx,
 7609                    |selections| {
 7610                        selections.select_anchor_ranges([target..target]);
 7611                    },
 7612                );
 7613            }
 7614            EditPrediction::MoveOutside { snapshot, target } => {
 7615                if let Some(workspace) = self.workspace() {
 7616                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7617                        .detach_and_log_err(cx);
 7618                }
 7619            }
 7620            EditPrediction::Edit { edits, .. } => {
 7621                self.report_edit_prediction_event(
 7622                    active_edit_prediction.completion_id.clone(),
 7623                    true,
 7624                    cx,
 7625                );
 7626
 7627                // Find an insertion that starts at the cursor position.
 7628                let snapshot = self.buffer.read(cx).snapshot(cx);
 7629                let cursor_offset = self
 7630                    .selections
 7631                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7632                    .head();
 7633                let insertion = edits.iter().find_map(|(range, text)| {
 7634                    let range = range.to_offset(&snapshot);
 7635                    if range.is_empty() && range.start == cursor_offset {
 7636                        Some(text)
 7637                    } else {
 7638                        None
 7639                    }
 7640                });
 7641
 7642                if let Some(text) = insertion {
 7643                    let mut partial_completion = text
 7644                        .chars()
 7645                        .by_ref()
 7646                        .take_while(|c| c.is_alphabetic())
 7647                        .collect::<String>();
 7648                    if partial_completion.is_empty() {
 7649                        partial_completion = text
 7650                            .chars()
 7651                            .by_ref()
 7652                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7653                            .collect::<String>();
 7654                    }
 7655
 7656                    cx.emit(EditorEvent::InputHandled {
 7657                        utf16_range_to_replace: None,
 7658                        text: partial_completion.clone().into(),
 7659                    });
 7660
 7661                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7662
 7663                    self.refresh_edit_prediction(true, true, window, cx);
 7664                    cx.notify();
 7665                } else {
 7666                    self.accept_edit_prediction(&Default::default(), window, cx);
 7667                }
 7668            }
 7669        }
 7670    }
 7671
 7672    fn discard_edit_prediction(
 7673        &mut self,
 7674        should_report_edit_prediction_event: bool,
 7675        cx: &mut Context<Self>,
 7676    ) -> bool {
 7677        if should_report_edit_prediction_event {
 7678            let completion_id = self
 7679                .active_edit_prediction
 7680                .as_ref()
 7681                .and_then(|active_completion| active_completion.completion_id.clone());
 7682
 7683            self.report_edit_prediction_event(completion_id, false, cx);
 7684        }
 7685
 7686        if let Some(provider) = self.edit_prediction_provider() {
 7687            provider.discard(cx);
 7688        }
 7689
 7690        self.take_active_edit_prediction(cx)
 7691    }
 7692
 7693    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7694        let Some(provider) = self.edit_prediction_provider() else {
 7695            return;
 7696        };
 7697
 7698        let Some((_, buffer, _)) = self
 7699            .buffer
 7700            .read(cx)
 7701            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7702        else {
 7703            return;
 7704        };
 7705
 7706        let extension = buffer
 7707            .read(cx)
 7708            .file()
 7709            .and_then(|file| Some(file.path().extension()?.to_string()));
 7710
 7711        let event_type = match accepted {
 7712            true => "Edit Prediction Accepted",
 7713            false => "Edit Prediction Discarded",
 7714        };
 7715        telemetry::event!(
 7716            event_type,
 7717            provider = provider.name(),
 7718            prediction_id = id,
 7719            suggestion_accepted = accepted,
 7720            file_extension = extension,
 7721        );
 7722    }
 7723
 7724    fn open_editor_at_anchor(
 7725        snapshot: &language::BufferSnapshot,
 7726        target: language::Anchor,
 7727        workspace: &Entity<Workspace>,
 7728        window: &mut Window,
 7729        cx: &mut App,
 7730    ) -> Task<Result<()>> {
 7731        workspace.update(cx, |workspace, cx| {
 7732            let path = snapshot.file().map(|file| file.full_path(cx));
 7733            let Some(path) =
 7734                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7735            else {
 7736                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7737            };
 7738            let target = text::ToPoint::to_point(&target, snapshot);
 7739            let item = workspace.open_path(path, None, true, window, cx);
 7740            window.spawn(cx, async move |cx| {
 7741                let Some(editor) = item.await?.downcast::<Editor>() else {
 7742                    return Ok(());
 7743                };
 7744                editor
 7745                    .update_in(cx, |editor, window, cx| {
 7746                        editor.go_to_singleton_buffer_point(target, window, cx);
 7747                    })
 7748                    .ok();
 7749                anyhow::Ok(())
 7750            })
 7751        })
 7752    }
 7753
 7754    pub fn has_active_edit_prediction(&self) -> bool {
 7755        self.active_edit_prediction.is_some()
 7756    }
 7757
 7758    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7759        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7760            return false;
 7761        };
 7762
 7763        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7764        self.clear_highlights::<EditPredictionHighlight>(cx);
 7765        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7766        true
 7767    }
 7768
 7769    /// Returns true when we're displaying the edit prediction popover below the cursor
 7770    /// like we are not previewing and the LSP autocomplete menu is visible
 7771    /// or we are in `when_holding_modifier` mode.
 7772    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7773        if self.edit_prediction_preview_is_active()
 7774            || !self.show_edit_predictions_in_menu()
 7775            || !self.edit_predictions_enabled()
 7776        {
 7777            return false;
 7778        }
 7779
 7780        if self.has_visible_completions_menu() {
 7781            return true;
 7782        }
 7783
 7784        has_completion && self.edit_prediction_requires_modifier()
 7785    }
 7786
 7787    fn handle_modifiers_changed(
 7788        &mut self,
 7789        modifiers: Modifiers,
 7790        position_map: &PositionMap,
 7791        window: &mut Window,
 7792        cx: &mut Context<Self>,
 7793    ) {
 7794        // Ensure that the edit prediction preview is updated, even when not
 7795        // enabled, if there's an active edit prediction preview.
 7796        if self.show_edit_predictions_in_menu()
 7797            || matches!(
 7798                self.edit_prediction_preview,
 7799                EditPredictionPreview::Active { .. }
 7800            )
 7801        {
 7802            self.update_edit_prediction_preview(&modifiers, window, cx);
 7803        }
 7804
 7805        self.update_selection_mode(&modifiers, position_map, window, cx);
 7806
 7807        let mouse_position = window.mouse_position();
 7808        if !position_map.text_hitbox.is_hovered(window) {
 7809            return;
 7810        }
 7811
 7812        self.update_hovered_link(
 7813            position_map.point_for_position(mouse_position),
 7814            &position_map.snapshot,
 7815            modifiers,
 7816            window,
 7817            cx,
 7818        )
 7819    }
 7820
 7821    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7822        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7823            MultiCursorModifier::Alt => modifiers.secondary(),
 7824            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7825        }
 7826    }
 7827
 7828    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7829        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7830            MultiCursorModifier::Alt => modifiers.alt,
 7831            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7832        }
 7833    }
 7834
 7835    fn columnar_selection_mode(
 7836        modifiers: &Modifiers,
 7837        cx: &mut Context<Self>,
 7838    ) -> Option<ColumnarMode> {
 7839        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7840            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7841                Some(ColumnarMode::FromMouse)
 7842            } else if Self::is_alt_pressed(modifiers, cx) {
 7843                Some(ColumnarMode::FromSelection)
 7844            } else {
 7845                None
 7846            }
 7847        } else {
 7848            None
 7849        }
 7850    }
 7851
 7852    fn update_selection_mode(
 7853        &mut self,
 7854        modifiers: &Modifiers,
 7855        position_map: &PositionMap,
 7856        window: &mut Window,
 7857        cx: &mut Context<Self>,
 7858    ) {
 7859        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7860            return;
 7861        };
 7862        if self.selections.pending_anchor().is_none() {
 7863            return;
 7864        }
 7865
 7866        let mouse_position = window.mouse_position();
 7867        let point_for_position = position_map.point_for_position(mouse_position);
 7868        let position = point_for_position.previous_valid;
 7869
 7870        self.select(
 7871            SelectPhase::BeginColumnar {
 7872                position,
 7873                reset: false,
 7874                mode,
 7875                goal_column: point_for_position.exact_unclipped.column(),
 7876            },
 7877            window,
 7878            cx,
 7879        );
 7880    }
 7881
 7882    fn update_edit_prediction_preview(
 7883        &mut self,
 7884        modifiers: &Modifiers,
 7885        window: &mut Window,
 7886        cx: &mut Context<Self>,
 7887    ) {
 7888        let mut modifiers_held = false;
 7889        if let Some(accept_keystroke) = self
 7890            .accept_edit_prediction_keybind(false, window, cx)
 7891            .keystroke()
 7892        {
 7893            modifiers_held = modifiers_held
 7894                || (accept_keystroke.modifiers() == modifiers
 7895                    && accept_keystroke.modifiers().modified());
 7896        };
 7897        if let Some(accept_partial_keystroke) = self
 7898            .accept_edit_prediction_keybind(true, window, cx)
 7899            .keystroke()
 7900        {
 7901            modifiers_held = modifiers_held
 7902                || (accept_partial_keystroke.modifiers() == modifiers
 7903                    && accept_partial_keystroke.modifiers().modified());
 7904        }
 7905
 7906        if modifiers_held {
 7907            if matches!(
 7908                self.edit_prediction_preview,
 7909                EditPredictionPreview::Inactive { .. }
 7910            ) {
 7911                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7912                    provider.provider.did_show(cx)
 7913                }
 7914
 7915                self.edit_prediction_preview = EditPredictionPreview::Active {
 7916                    previous_scroll_position: None,
 7917                    since: Instant::now(),
 7918                };
 7919
 7920                self.update_visible_edit_prediction(window, cx);
 7921                cx.notify();
 7922            }
 7923        } else if let EditPredictionPreview::Active {
 7924            previous_scroll_position,
 7925            since,
 7926        } = self.edit_prediction_preview
 7927        {
 7928            if let (Some(previous_scroll_position), Some(position_map)) =
 7929                (previous_scroll_position, self.last_position_map.as_ref())
 7930            {
 7931                self.set_scroll_position(
 7932                    previous_scroll_position
 7933                        .scroll_position(&position_map.snapshot.display_snapshot),
 7934                    window,
 7935                    cx,
 7936                );
 7937            }
 7938
 7939            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7940                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7941            };
 7942            self.clear_row_highlights::<EditPredictionPreview>();
 7943            self.update_visible_edit_prediction(window, cx);
 7944            cx.notify();
 7945        }
 7946    }
 7947
 7948    fn update_visible_edit_prediction(
 7949        &mut self,
 7950        _window: &mut Window,
 7951        cx: &mut Context<Self>,
 7952    ) -> Option<()> {
 7953        if DisableAiSettings::get_global(cx).disable_ai {
 7954            return None;
 7955        }
 7956
 7957        if self.ime_transaction.is_some() {
 7958            self.discard_edit_prediction(false, cx);
 7959            return None;
 7960        }
 7961
 7962        let selection = self.selections.newest_anchor();
 7963        let cursor = selection.head();
 7964        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7965        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7966        let excerpt_id = cursor.excerpt_id;
 7967
 7968        let show_in_menu = self.show_edit_predictions_in_menu();
 7969        let completions_menu_has_precedence = !show_in_menu
 7970            && (self.context_menu.borrow().is_some()
 7971                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7972
 7973        if completions_menu_has_precedence
 7974            || !offset_selection.is_empty()
 7975            || self
 7976                .active_edit_prediction
 7977                .as_ref()
 7978                .is_some_and(|completion| {
 7979                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7980                        return false;
 7981                    };
 7982                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7983                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7984                    !invalidation_range.contains(&offset_selection.head())
 7985                })
 7986        {
 7987            self.discard_edit_prediction(false, cx);
 7988            return None;
 7989        }
 7990
 7991        self.take_active_edit_prediction(cx);
 7992        let Some(provider) = self.edit_prediction_provider() else {
 7993            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7994            return None;
 7995        };
 7996
 7997        let (buffer, cursor_buffer_position) =
 7998            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7999
 8000        self.edit_prediction_settings =
 8001            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8002
 8003        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8004
 8005        if self.edit_prediction_indent_conflict {
 8006            let cursor_point = cursor.to_point(&multibuffer);
 8007
 8008            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8009
 8010            if let Some((_, indent)) = indents.iter().next()
 8011                && indent.len == cursor_point.column
 8012            {
 8013                self.edit_prediction_indent_conflict = false;
 8014            }
 8015        }
 8016
 8017        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8018
 8019        let (completion_id, edits, edit_preview) = match edit_prediction {
 8020            edit_prediction::EditPrediction::Local {
 8021                id,
 8022                edits,
 8023                edit_preview,
 8024            } => (id, edits, edit_preview),
 8025            edit_prediction::EditPrediction::Jump {
 8026                id,
 8027                snapshot,
 8028                target,
 8029            } => {
 8030                self.stale_edit_prediction_in_menu = None;
 8031                self.active_edit_prediction = Some(EditPredictionState {
 8032                    inlay_ids: vec![],
 8033                    completion: EditPrediction::MoveOutside { snapshot, target },
 8034                    completion_id: id,
 8035                    invalidation_range: None,
 8036                });
 8037                cx.notify();
 8038                return Some(());
 8039            }
 8040        };
 8041
 8042        let edits = edits
 8043            .into_iter()
 8044            .flat_map(|(range, new_text)| {
 8045                Some((
 8046                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8047                    new_text,
 8048                ))
 8049            })
 8050            .collect::<Vec<_>>();
 8051        if edits.is_empty() {
 8052            return None;
 8053        }
 8054
 8055        let first_edit_start = edits.first().unwrap().0.start;
 8056        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8057        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8058
 8059        let last_edit_end = edits.last().unwrap().0.end;
 8060        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8061        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8062
 8063        let cursor_row = cursor.to_point(&multibuffer).row;
 8064
 8065        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8066
 8067        let mut inlay_ids = Vec::new();
 8068        let invalidation_row_range;
 8069        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8070            Some(cursor_row..edit_end_row)
 8071        } else if cursor_row > edit_end_row {
 8072            Some(edit_start_row..cursor_row)
 8073        } else {
 8074            None
 8075        };
 8076        let supports_jump = self
 8077            .edit_prediction_provider
 8078            .as_ref()
 8079            .map(|provider| provider.provider.supports_jump_to_edit())
 8080            .unwrap_or(true);
 8081
 8082        let is_move = supports_jump
 8083            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8084        let completion = if is_move {
 8085            invalidation_row_range =
 8086                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8087            let target = first_edit_start;
 8088            EditPrediction::MoveWithin { target, snapshot }
 8089        } else {
 8090            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8091                && !self.edit_predictions_hidden_for_vim_mode;
 8092
 8093            if show_completions_in_buffer {
 8094                if let Some(provider) = &self.edit_prediction_provider {
 8095                    provider.provider.did_show(cx);
 8096                }
 8097                if edits
 8098                    .iter()
 8099                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8100                {
 8101                    let mut inlays = Vec::new();
 8102                    for (range, new_text) in &edits {
 8103                        let inlay = Inlay::edit_prediction(
 8104                            post_inc(&mut self.next_inlay_id),
 8105                            range.start,
 8106                            new_text.as_ref(),
 8107                        );
 8108                        inlay_ids.push(inlay.id);
 8109                        inlays.push(inlay);
 8110                    }
 8111
 8112                    self.splice_inlays(&[], inlays, cx);
 8113                } else {
 8114                    let background_color = cx.theme().status().deleted_background;
 8115                    self.highlight_text::<EditPredictionHighlight>(
 8116                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8117                        HighlightStyle {
 8118                            background_color: Some(background_color),
 8119                            ..Default::default()
 8120                        },
 8121                        cx,
 8122                    );
 8123                }
 8124            }
 8125
 8126            invalidation_row_range = edit_start_row..edit_end_row;
 8127
 8128            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8129                if provider.show_tab_accept_marker() {
 8130                    EditDisplayMode::TabAccept
 8131                } else {
 8132                    EditDisplayMode::Inline
 8133                }
 8134            } else {
 8135                EditDisplayMode::DiffPopover
 8136            };
 8137
 8138            EditPrediction::Edit {
 8139                edits,
 8140                edit_preview,
 8141                display_mode,
 8142                snapshot,
 8143            }
 8144        };
 8145
 8146        let invalidation_range = multibuffer
 8147            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8148            ..multibuffer.anchor_after(Point::new(
 8149                invalidation_row_range.end,
 8150                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8151            ));
 8152
 8153        self.stale_edit_prediction_in_menu = None;
 8154        self.active_edit_prediction = Some(EditPredictionState {
 8155            inlay_ids,
 8156            completion,
 8157            completion_id,
 8158            invalidation_range: Some(invalidation_range),
 8159        });
 8160
 8161        cx.notify();
 8162
 8163        Some(())
 8164    }
 8165
 8166    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8167        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8168    }
 8169
 8170    fn clear_tasks(&mut self) {
 8171        self.tasks.clear()
 8172    }
 8173
 8174    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8175        if self.tasks.insert(key, value).is_some() {
 8176            // This case should hopefully be rare, but just in case...
 8177            log::error!(
 8178                "multiple different run targets found on a single line, only the last target will be rendered"
 8179            )
 8180        }
 8181    }
 8182
 8183    /// Get all display points of breakpoints that will be rendered within editor
 8184    ///
 8185    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8186    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8187    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8188    fn active_breakpoints(
 8189        &self,
 8190        range: Range<DisplayRow>,
 8191        window: &mut Window,
 8192        cx: &mut Context<Self>,
 8193    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8194        let mut breakpoint_display_points = HashMap::default();
 8195
 8196        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8197            return breakpoint_display_points;
 8198        };
 8199
 8200        let snapshot = self.snapshot(window, cx);
 8201
 8202        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8203        let Some(project) = self.project() else {
 8204            return breakpoint_display_points;
 8205        };
 8206
 8207        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8208            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8209
 8210        for (buffer_snapshot, range, excerpt_id) in
 8211            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8212        {
 8213            let Some(buffer) = project
 8214                .read(cx)
 8215                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8216            else {
 8217                continue;
 8218            };
 8219            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8220                &buffer,
 8221                Some(
 8222                    buffer_snapshot.anchor_before(range.start)
 8223                        ..buffer_snapshot.anchor_after(range.end),
 8224                ),
 8225                buffer_snapshot,
 8226                cx,
 8227            );
 8228            for (breakpoint, state) in breakpoints {
 8229                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8230                let position = multi_buffer_anchor
 8231                    .to_point(&multi_buffer_snapshot)
 8232                    .to_display_point(&snapshot);
 8233
 8234                breakpoint_display_points.insert(
 8235                    position.row(),
 8236                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8237                );
 8238            }
 8239        }
 8240
 8241        breakpoint_display_points
 8242    }
 8243
 8244    fn breakpoint_context_menu(
 8245        &self,
 8246        anchor: Anchor,
 8247        window: &mut Window,
 8248        cx: &mut Context<Self>,
 8249    ) -> Entity<ui::ContextMenu> {
 8250        let weak_editor = cx.weak_entity();
 8251        let focus_handle = self.focus_handle(cx);
 8252
 8253        let row = self
 8254            .buffer
 8255            .read(cx)
 8256            .snapshot(cx)
 8257            .summary_for_anchor::<Point>(&anchor)
 8258            .row;
 8259
 8260        let breakpoint = self
 8261            .breakpoint_at_row(row, window, cx)
 8262            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8263
 8264        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8265            "Edit Log Breakpoint"
 8266        } else {
 8267            "Set Log Breakpoint"
 8268        };
 8269
 8270        let condition_breakpoint_msg = if breakpoint
 8271            .as_ref()
 8272            .is_some_and(|bp| bp.1.condition.is_some())
 8273        {
 8274            "Edit Condition Breakpoint"
 8275        } else {
 8276            "Set Condition Breakpoint"
 8277        };
 8278
 8279        let hit_condition_breakpoint_msg = if breakpoint
 8280            .as_ref()
 8281            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8282        {
 8283            "Edit Hit Condition Breakpoint"
 8284        } else {
 8285            "Set Hit Condition Breakpoint"
 8286        };
 8287
 8288        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8289            "Unset Breakpoint"
 8290        } else {
 8291            "Set Breakpoint"
 8292        };
 8293
 8294        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8295
 8296        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8297            BreakpointState::Enabled => Some("Disable"),
 8298            BreakpointState::Disabled => Some("Enable"),
 8299        });
 8300
 8301        let (anchor, breakpoint) =
 8302            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8303
 8304        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8305            menu.on_blur_subscription(Subscription::new(|| {}))
 8306                .context(focus_handle)
 8307                .when(run_to_cursor, |this| {
 8308                    let weak_editor = weak_editor.clone();
 8309                    this.entry("Run to cursor", None, move |window, cx| {
 8310                        weak_editor
 8311                            .update(cx, |editor, cx| {
 8312                                editor.change_selections(
 8313                                    SelectionEffects::no_scroll(),
 8314                                    window,
 8315                                    cx,
 8316                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8317                                );
 8318                            })
 8319                            .ok();
 8320
 8321                        window.dispatch_action(Box::new(RunToCursor), cx);
 8322                    })
 8323                    .separator()
 8324                })
 8325                .when_some(toggle_state_msg, |this, msg| {
 8326                    this.entry(msg, None, {
 8327                        let weak_editor = weak_editor.clone();
 8328                        let breakpoint = breakpoint.clone();
 8329                        move |_window, cx| {
 8330                            weak_editor
 8331                                .update(cx, |this, cx| {
 8332                                    this.edit_breakpoint_at_anchor(
 8333                                        anchor,
 8334                                        breakpoint.as_ref().clone(),
 8335                                        BreakpointEditAction::InvertState,
 8336                                        cx,
 8337                                    );
 8338                                })
 8339                                .log_err();
 8340                        }
 8341                    })
 8342                })
 8343                .entry(set_breakpoint_msg, None, {
 8344                    let weak_editor = weak_editor.clone();
 8345                    let breakpoint = breakpoint.clone();
 8346                    move |_window, cx| {
 8347                        weak_editor
 8348                            .update(cx, |this, cx| {
 8349                                this.edit_breakpoint_at_anchor(
 8350                                    anchor,
 8351                                    breakpoint.as_ref().clone(),
 8352                                    BreakpointEditAction::Toggle,
 8353                                    cx,
 8354                                );
 8355                            })
 8356                            .log_err();
 8357                    }
 8358                })
 8359                .entry(log_breakpoint_msg, None, {
 8360                    let breakpoint = breakpoint.clone();
 8361                    let weak_editor = weak_editor.clone();
 8362                    move |window, cx| {
 8363                        weak_editor
 8364                            .update(cx, |this, cx| {
 8365                                this.add_edit_breakpoint_block(
 8366                                    anchor,
 8367                                    breakpoint.as_ref(),
 8368                                    BreakpointPromptEditAction::Log,
 8369                                    window,
 8370                                    cx,
 8371                                );
 8372                            })
 8373                            .log_err();
 8374                    }
 8375                })
 8376                .entry(condition_breakpoint_msg, None, {
 8377                    let breakpoint = breakpoint.clone();
 8378                    let weak_editor = weak_editor.clone();
 8379                    move |window, cx| {
 8380                        weak_editor
 8381                            .update(cx, |this, cx| {
 8382                                this.add_edit_breakpoint_block(
 8383                                    anchor,
 8384                                    breakpoint.as_ref(),
 8385                                    BreakpointPromptEditAction::Condition,
 8386                                    window,
 8387                                    cx,
 8388                                );
 8389                            })
 8390                            .log_err();
 8391                    }
 8392                })
 8393                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8394                    weak_editor
 8395                        .update(cx, |this, cx| {
 8396                            this.add_edit_breakpoint_block(
 8397                                anchor,
 8398                                breakpoint.as_ref(),
 8399                                BreakpointPromptEditAction::HitCondition,
 8400                                window,
 8401                                cx,
 8402                            );
 8403                        })
 8404                        .log_err();
 8405                })
 8406        })
 8407    }
 8408
 8409    fn render_breakpoint(
 8410        &self,
 8411        position: Anchor,
 8412        row: DisplayRow,
 8413        breakpoint: &Breakpoint,
 8414        state: Option<BreakpointSessionState>,
 8415        cx: &mut Context<Self>,
 8416    ) -> IconButton {
 8417        let is_rejected = state.is_some_and(|s| !s.verified);
 8418        // Is it a breakpoint that shows up when hovering over gutter?
 8419        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8420            (false, false),
 8421            |PhantomBreakpointIndicator {
 8422                 is_active,
 8423                 display_row,
 8424                 collides_with_existing_breakpoint,
 8425             }| {
 8426                (
 8427                    is_active && display_row == row,
 8428                    collides_with_existing_breakpoint,
 8429                )
 8430            },
 8431        );
 8432
 8433        let (color, icon) = {
 8434            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8435                (false, false) => ui::IconName::DebugBreakpoint,
 8436                (true, false) => ui::IconName::DebugLogBreakpoint,
 8437                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8438                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8439            };
 8440
 8441            let color = cx.theme().colors();
 8442
 8443            let color = if is_phantom {
 8444                if collides_with_existing {
 8445                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8446                } else {
 8447                    Color::Hint
 8448                }
 8449            } else if is_rejected {
 8450                Color::Disabled
 8451            } else {
 8452                Color::Debugger
 8453            };
 8454
 8455            (color, icon)
 8456        };
 8457
 8458        let breakpoint = Arc::from(breakpoint.clone());
 8459
 8460        let alt_as_text = gpui::Keystroke {
 8461            modifiers: Modifiers::secondary_key(),
 8462            ..Default::default()
 8463        };
 8464        let primary_action_text = if breakpoint.is_disabled() {
 8465            "Enable breakpoint"
 8466        } else if is_phantom && !collides_with_existing {
 8467            "Set breakpoint"
 8468        } else {
 8469            "Unset breakpoint"
 8470        };
 8471        let focus_handle = self.focus_handle.clone();
 8472
 8473        let meta = if is_rejected {
 8474            SharedString::from("No executable code is associated with this line.")
 8475        } else if collides_with_existing && !breakpoint.is_disabled() {
 8476            SharedString::from(format!(
 8477                "{alt_as_text}-click to disable,\nright-click for more options."
 8478            ))
 8479        } else {
 8480            SharedString::from("Right-click for more options.")
 8481        };
 8482        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8483            .icon_size(IconSize::XSmall)
 8484            .size(ui::ButtonSize::None)
 8485            .when(is_rejected, |this| {
 8486                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8487            })
 8488            .icon_color(color)
 8489            .style(ButtonStyle::Transparent)
 8490            .on_click(cx.listener({
 8491                move |editor, event: &ClickEvent, window, cx| {
 8492                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8493                        BreakpointEditAction::InvertState
 8494                    } else {
 8495                        BreakpointEditAction::Toggle
 8496                    };
 8497
 8498                    window.focus(&editor.focus_handle(cx));
 8499                    editor.edit_breakpoint_at_anchor(
 8500                        position,
 8501                        breakpoint.as_ref().clone(),
 8502                        edit_action,
 8503                        cx,
 8504                    );
 8505                }
 8506            }))
 8507            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8508                editor.set_breakpoint_context_menu(
 8509                    row,
 8510                    Some(position),
 8511                    event.position(),
 8512                    window,
 8513                    cx,
 8514                );
 8515            }))
 8516            .tooltip(move |_window, cx| {
 8517                Tooltip::with_meta_in(
 8518                    primary_action_text,
 8519                    Some(&ToggleBreakpoint),
 8520                    meta.clone(),
 8521                    &focus_handle,
 8522                    cx,
 8523                )
 8524            })
 8525    }
 8526
 8527    fn build_tasks_context(
 8528        project: &Entity<Project>,
 8529        buffer: &Entity<Buffer>,
 8530        buffer_row: u32,
 8531        tasks: &Arc<RunnableTasks>,
 8532        cx: &mut Context<Self>,
 8533    ) -> Task<Option<task::TaskContext>> {
 8534        let position = Point::new(buffer_row, tasks.column);
 8535        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8536        let location = Location {
 8537            buffer: buffer.clone(),
 8538            range: range_start..range_start,
 8539        };
 8540        // Fill in the environmental variables from the tree-sitter captures
 8541        let mut captured_task_variables = TaskVariables::default();
 8542        for (capture_name, value) in tasks.extra_variables.clone() {
 8543            captured_task_variables.insert(
 8544                task::VariableName::Custom(capture_name.into()),
 8545                value.clone(),
 8546            );
 8547        }
 8548        project.update(cx, |project, cx| {
 8549            project.task_store().update(cx, |task_store, cx| {
 8550                task_store.task_context_for_location(captured_task_variables, location, cx)
 8551            })
 8552        })
 8553    }
 8554
 8555    pub fn spawn_nearest_task(
 8556        &mut self,
 8557        action: &SpawnNearestTask,
 8558        window: &mut Window,
 8559        cx: &mut Context<Self>,
 8560    ) {
 8561        let Some((workspace, _)) = self.workspace.clone() else {
 8562            return;
 8563        };
 8564        let Some(project) = self.project.clone() else {
 8565            return;
 8566        };
 8567
 8568        // Try to find a closest, enclosing node using tree-sitter that has a task
 8569        let Some((buffer, buffer_row, tasks)) = self
 8570            .find_enclosing_node_task(cx)
 8571            // Or find the task that's closest in row-distance.
 8572            .or_else(|| self.find_closest_task(cx))
 8573        else {
 8574            return;
 8575        };
 8576
 8577        let reveal_strategy = action.reveal;
 8578        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8579        cx.spawn_in(window, async move |_, cx| {
 8580            let context = task_context.await?;
 8581            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8582
 8583            let resolved = &mut resolved_task.resolved;
 8584            resolved.reveal = reveal_strategy;
 8585
 8586            workspace
 8587                .update_in(cx, |workspace, window, cx| {
 8588                    workspace.schedule_resolved_task(
 8589                        task_source_kind,
 8590                        resolved_task,
 8591                        false,
 8592                        window,
 8593                        cx,
 8594                    );
 8595                })
 8596                .ok()
 8597        })
 8598        .detach();
 8599    }
 8600
 8601    fn find_closest_task(
 8602        &mut self,
 8603        cx: &mut Context<Self>,
 8604    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8605        let cursor_row = self
 8606            .selections
 8607            .newest_adjusted(&self.display_snapshot(cx))
 8608            .head()
 8609            .row;
 8610
 8611        let ((buffer_id, row), tasks) = self
 8612            .tasks
 8613            .iter()
 8614            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8615
 8616        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8617        let tasks = Arc::new(tasks.to_owned());
 8618        Some((buffer, *row, tasks))
 8619    }
 8620
 8621    fn find_enclosing_node_task(
 8622        &mut self,
 8623        cx: &mut Context<Self>,
 8624    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8625        let snapshot = self.buffer.read(cx).snapshot(cx);
 8626        let offset = self
 8627            .selections
 8628            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8629            .head();
 8630        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8631        let offset = excerpt.map_offset_to_buffer(offset);
 8632        let buffer_id = excerpt.buffer().remote_id();
 8633
 8634        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8635        let mut cursor = layer.node().walk();
 8636
 8637        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8638            if cursor.node().end_byte() == offset.0 {
 8639                cursor.goto_next_sibling();
 8640            }
 8641        }
 8642
 8643        // Ascend to the smallest ancestor that contains the range and has a task.
 8644        loop {
 8645            let node = cursor.node();
 8646            let node_range = node.byte_range();
 8647            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8648
 8649            // Check if this node contains our offset
 8650            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8651                // If it contains offset, check for task
 8652                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8653                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8654                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8655                }
 8656            }
 8657
 8658            if !cursor.goto_parent() {
 8659                break;
 8660            }
 8661        }
 8662        None
 8663    }
 8664
 8665    fn render_run_indicator(
 8666        &self,
 8667        _style: &EditorStyle,
 8668        is_active: bool,
 8669        row: DisplayRow,
 8670        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8671        cx: &mut Context<Self>,
 8672    ) -> IconButton {
 8673        let color = Color::Muted;
 8674        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8675
 8676        IconButton::new(
 8677            ("run_indicator", row.0 as usize),
 8678            ui::IconName::PlayOutlined,
 8679        )
 8680        .shape(ui::IconButtonShape::Square)
 8681        .icon_size(IconSize::XSmall)
 8682        .icon_color(color)
 8683        .toggle_state(is_active)
 8684        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8685            let quick_launch = match e {
 8686                ClickEvent::Keyboard(_) => true,
 8687                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8688            };
 8689
 8690            window.focus(&editor.focus_handle(cx));
 8691            editor.toggle_code_actions(
 8692                &ToggleCodeActions {
 8693                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8694                    quick_launch,
 8695                },
 8696                window,
 8697                cx,
 8698            );
 8699        }))
 8700        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8701            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8702        }))
 8703    }
 8704
 8705    pub fn context_menu_visible(&self) -> bool {
 8706        !self.edit_prediction_preview_is_active()
 8707            && self
 8708                .context_menu
 8709                .borrow()
 8710                .as_ref()
 8711                .is_some_and(|menu| menu.visible())
 8712    }
 8713
 8714    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8715        self.context_menu
 8716            .borrow()
 8717            .as_ref()
 8718            .map(|menu| menu.origin())
 8719    }
 8720
 8721    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8722        self.context_menu_options = Some(options);
 8723    }
 8724
 8725    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8726    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8727
 8728    fn render_edit_prediction_popover(
 8729        &mut self,
 8730        text_bounds: &Bounds<Pixels>,
 8731        content_origin: gpui::Point<Pixels>,
 8732        right_margin: Pixels,
 8733        editor_snapshot: &EditorSnapshot,
 8734        visible_row_range: Range<DisplayRow>,
 8735        scroll_top: ScrollOffset,
 8736        scroll_bottom: ScrollOffset,
 8737        line_layouts: &[LineWithInvisibles],
 8738        line_height: Pixels,
 8739        scroll_position: gpui::Point<ScrollOffset>,
 8740        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8741        newest_selection_head: Option<DisplayPoint>,
 8742        editor_width: Pixels,
 8743        style: &EditorStyle,
 8744        window: &mut Window,
 8745        cx: &mut App,
 8746    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8747        if self.mode().is_minimap() {
 8748            return None;
 8749        }
 8750        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8751
 8752        if self.edit_prediction_visible_in_cursor_popover(true) {
 8753            return None;
 8754        }
 8755
 8756        match &active_edit_prediction.completion {
 8757            EditPrediction::MoveWithin { target, .. } => {
 8758                let target_display_point = target.to_display_point(editor_snapshot);
 8759
 8760                if self.edit_prediction_requires_modifier() {
 8761                    if !self.edit_prediction_preview_is_active() {
 8762                        return None;
 8763                    }
 8764
 8765                    self.render_edit_prediction_modifier_jump_popover(
 8766                        text_bounds,
 8767                        content_origin,
 8768                        visible_row_range,
 8769                        line_layouts,
 8770                        line_height,
 8771                        scroll_pixel_position,
 8772                        newest_selection_head,
 8773                        target_display_point,
 8774                        window,
 8775                        cx,
 8776                    )
 8777                } else {
 8778                    self.render_edit_prediction_eager_jump_popover(
 8779                        text_bounds,
 8780                        content_origin,
 8781                        editor_snapshot,
 8782                        visible_row_range,
 8783                        scroll_top,
 8784                        scroll_bottom,
 8785                        line_height,
 8786                        scroll_pixel_position,
 8787                        target_display_point,
 8788                        editor_width,
 8789                        window,
 8790                        cx,
 8791                    )
 8792                }
 8793            }
 8794            EditPrediction::Edit {
 8795                display_mode: EditDisplayMode::Inline,
 8796                ..
 8797            } => None,
 8798            EditPrediction::Edit {
 8799                display_mode: EditDisplayMode::TabAccept,
 8800                edits,
 8801                ..
 8802            } => {
 8803                let range = &edits.first()?.0;
 8804                let target_display_point = range.end.to_display_point(editor_snapshot);
 8805
 8806                self.render_edit_prediction_end_of_line_popover(
 8807                    "Accept",
 8808                    editor_snapshot,
 8809                    visible_row_range,
 8810                    target_display_point,
 8811                    line_height,
 8812                    scroll_pixel_position,
 8813                    content_origin,
 8814                    editor_width,
 8815                    window,
 8816                    cx,
 8817                )
 8818            }
 8819            EditPrediction::Edit {
 8820                edits,
 8821                edit_preview,
 8822                display_mode: EditDisplayMode::DiffPopover,
 8823                snapshot,
 8824            } => self.render_edit_prediction_diff_popover(
 8825                text_bounds,
 8826                content_origin,
 8827                right_margin,
 8828                editor_snapshot,
 8829                visible_row_range,
 8830                line_layouts,
 8831                line_height,
 8832                scroll_position,
 8833                scroll_pixel_position,
 8834                newest_selection_head,
 8835                editor_width,
 8836                style,
 8837                edits,
 8838                edit_preview,
 8839                snapshot,
 8840                window,
 8841                cx,
 8842            ),
 8843            EditPrediction::MoveOutside { snapshot, .. } => {
 8844                let mut element = self
 8845                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8846                    .into_any();
 8847
 8848                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8849                let origin_x = text_bounds.size.width - size.width - px(30.);
 8850                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8851                element.prepaint_at(origin, window, cx);
 8852
 8853                Some((element, origin))
 8854            }
 8855        }
 8856    }
 8857
 8858    fn render_edit_prediction_modifier_jump_popover(
 8859        &mut self,
 8860        text_bounds: &Bounds<Pixels>,
 8861        content_origin: gpui::Point<Pixels>,
 8862        visible_row_range: Range<DisplayRow>,
 8863        line_layouts: &[LineWithInvisibles],
 8864        line_height: Pixels,
 8865        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8866        newest_selection_head: Option<DisplayPoint>,
 8867        target_display_point: DisplayPoint,
 8868        window: &mut Window,
 8869        cx: &mut App,
 8870    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8871        let scrolled_content_origin =
 8872            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8873
 8874        const SCROLL_PADDING_Y: Pixels = px(12.);
 8875
 8876        if target_display_point.row() < visible_row_range.start {
 8877            return self.render_edit_prediction_scroll_popover(
 8878                |_| SCROLL_PADDING_Y,
 8879                IconName::ArrowUp,
 8880                visible_row_range,
 8881                line_layouts,
 8882                newest_selection_head,
 8883                scrolled_content_origin,
 8884                window,
 8885                cx,
 8886            );
 8887        } else if target_display_point.row() >= visible_row_range.end {
 8888            return self.render_edit_prediction_scroll_popover(
 8889                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8890                IconName::ArrowDown,
 8891                visible_row_range,
 8892                line_layouts,
 8893                newest_selection_head,
 8894                scrolled_content_origin,
 8895                window,
 8896                cx,
 8897            );
 8898        }
 8899
 8900        const POLE_WIDTH: Pixels = px(2.);
 8901
 8902        let line_layout =
 8903            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8904        let target_column = target_display_point.column() as usize;
 8905
 8906        let target_x = line_layout.x_for_index(target_column);
 8907        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8908            - scroll_pixel_position.y;
 8909
 8910        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8911
 8912        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8913        border_color.l += 0.001;
 8914
 8915        let mut element = v_flex()
 8916            .items_end()
 8917            .when(flag_on_right, |el| el.items_start())
 8918            .child(if flag_on_right {
 8919                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8920                    .rounded_bl(px(0.))
 8921                    .rounded_tl(px(0.))
 8922                    .border_l_2()
 8923                    .border_color(border_color)
 8924            } else {
 8925                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8926                    .rounded_br(px(0.))
 8927                    .rounded_tr(px(0.))
 8928                    .border_r_2()
 8929                    .border_color(border_color)
 8930            })
 8931            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8932            .into_any();
 8933
 8934        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8935
 8936        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8937            - point(
 8938                if flag_on_right {
 8939                    POLE_WIDTH
 8940                } else {
 8941                    size.width - POLE_WIDTH
 8942                },
 8943                size.height - line_height,
 8944            );
 8945
 8946        origin.x = origin.x.max(content_origin.x);
 8947
 8948        element.prepaint_at(origin, window, cx);
 8949
 8950        Some((element, origin))
 8951    }
 8952
 8953    fn render_edit_prediction_scroll_popover(
 8954        &mut self,
 8955        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8956        scroll_icon: IconName,
 8957        visible_row_range: Range<DisplayRow>,
 8958        line_layouts: &[LineWithInvisibles],
 8959        newest_selection_head: Option<DisplayPoint>,
 8960        scrolled_content_origin: gpui::Point<Pixels>,
 8961        window: &mut Window,
 8962        cx: &mut App,
 8963    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8964        let mut element = self
 8965            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8966            .into_any();
 8967
 8968        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8969
 8970        let cursor = newest_selection_head?;
 8971        let cursor_row_layout =
 8972            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8973        let cursor_column = cursor.column() as usize;
 8974
 8975        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8976
 8977        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8978
 8979        element.prepaint_at(origin, window, cx);
 8980        Some((element, origin))
 8981    }
 8982
 8983    fn render_edit_prediction_eager_jump_popover(
 8984        &mut self,
 8985        text_bounds: &Bounds<Pixels>,
 8986        content_origin: gpui::Point<Pixels>,
 8987        editor_snapshot: &EditorSnapshot,
 8988        visible_row_range: Range<DisplayRow>,
 8989        scroll_top: ScrollOffset,
 8990        scroll_bottom: ScrollOffset,
 8991        line_height: Pixels,
 8992        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8993        target_display_point: DisplayPoint,
 8994        editor_width: Pixels,
 8995        window: &mut Window,
 8996        cx: &mut App,
 8997    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8998        if target_display_point.row().as_f64() < scroll_top {
 8999            let mut element = self
 9000                .render_edit_prediction_line_popover(
 9001                    "Jump to Edit",
 9002                    Some(IconName::ArrowUp),
 9003                    window,
 9004                    cx,
 9005                )
 9006                .into_any();
 9007
 9008            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9009            let offset = point(
 9010                (text_bounds.size.width - size.width) / 2.,
 9011                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9012            );
 9013
 9014            let origin = text_bounds.origin + offset;
 9015            element.prepaint_at(origin, window, cx);
 9016            Some((element, origin))
 9017        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9018            let mut element = self
 9019                .render_edit_prediction_line_popover(
 9020                    "Jump to Edit",
 9021                    Some(IconName::ArrowDown),
 9022                    window,
 9023                    cx,
 9024                )
 9025                .into_any();
 9026
 9027            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9028            let offset = point(
 9029                (text_bounds.size.width - size.width) / 2.,
 9030                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9031            );
 9032
 9033            let origin = text_bounds.origin + offset;
 9034            element.prepaint_at(origin, window, cx);
 9035            Some((element, origin))
 9036        } else {
 9037            self.render_edit_prediction_end_of_line_popover(
 9038                "Jump to Edit",
 9039                editor_snapshot,
 9040                visible_row_range,
 9041                target_display_point,
 9042                line_height,
 9043                scroll_pixel_position,
 9044                content_origin,
 9045                editor_width,
 9046                window,
 9047                cx,
 9048            )
 9049        }
 9050    }
 9051
 9052    fn render_edit_prediction_end_of_line_popover(
 9053        self: &mut Editor,
 9054        label: &'static str,
 9055        editor_snapshot: &EditorSnapshot,
 9056        visible_row_range: Range<DisplayRow>,
 9057        target_display_point: DisplayPoint,
 9058        line_height: Pixels,
 9059        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9060        content_origin: gpui::Point<Pixels>,
 9061        editor_width: Pixels,
 9062        window: &mut Window,
 9063        cx: &mut App,
 9064    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9065        let target_line_end = DisplayPoint::new(
 9066            target_display_point.row(),
 9067            editor_snapshot.line_len(target_display_point.row()),
 9068        );
 9069
 9070        let mut element = self
 9071            .render_edit_prediction_line_popover(label, None, window, cx)
 9072            .into_any();
 9073
 9074        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9075
 9076        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9077
 9078        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9079        let mut origin = start_point
 9080            + line_origin
 9081            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9082        origin.x = origin.x.max(content_origin.x);
 9083
 9084        let max_x = content_origin.x + editor_width - size.width;
 9085
 9086        if origin.x > max_x {
 9087            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9088
 9089            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9090                origin.y += offset;
 9091                IconName::ArrowUp
 9092            } else {
 9093                origin.y -= offset;
 9094                IconName::ArrowDown
 9095            };
 9096
 9097            element = self
 9098                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9099                .into_any();
 9100
 9101            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9102
 9103            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9104        }
 9105
 9106        element.prepaint_at(origin, window, cx);
 9107        Some((element, origin))
 9108    }
 9109
 9110    fn render_edit_prediction_diff_popover(
 9111        self: &Editor,
 9112        text_bounds: &Bounds<Pixels>,
 9113        content_origin: gpui::Point<Pixels>,
 9114        right_margin: Pixels,
 9115        editor_snapshot: &EditorSnapshot,
 9116        visible_row_range: Range<DisplayRow>,
 9117        line_layouts: &[LineWithInvisibles],
 9118        line_height: Pixels,
 9119        scroll_position: gpui::Point<ScrollOffset>,
 9120        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9121        newest_selection_head: Option<DisplayPoint>,
 9122        editor_width: Pixels,
 9123        style: &EditorStyle,
 9124        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9125        edit_preview: &Option<language::EditPreview>,
 9126        snapshot: &language::BufferSnapshot,
 9127        window: &mut Window,
 9128        cx: &mut App,
 9129    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9130        let edit_start = edits
 9131            .first()
 9132            .unwrap()
 9133            .0
 9134            .start
 9135            .to_display_point(editor_snapshot);
 9136        let edit_end = edits
 9137            .last()
 9138            .unwrap()
 9139            .0
 9140            .end
 9141            .to_display_point(editor_snapshot);
 9142
 9143        let is_visible = visible_row_range.contains(&edit_start.row())
 9144            || visible_row_range.contains(&edit_end.row());
 9145        if !is_visible {
 9146            return None;
 9147        }
 9148
 9149        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9150            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9151        } else {
 9152            // Fallback for providers without edit_preview
 9153            crate::edit_prediction_fallback_text(edits, cx)
 9154        };
 9155
 9156        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9157        let line_count = highlighted_edits.text.lines().count();
 9158
 9159        const BORDER_WIDTH: Pixels = px(1.);
 9160
 9161        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9162        let has_keybind = keybind.is_some();
 9163
 9164        let mut element = h_flex()
 9165            .items_start()
 9166            .child(
 9167                h_flex()
 9168                    .bg(cx.theme().colors().editor_background)
 9169                    .border(BORDER_WIDTH)
 9170                    .shadow_xs()
 9171                    .border_color(cx.theme().colors().border)
 9172                    .rounded_l_lg()
 9173                    .when(line_count > 1, |el| el.rounded_br_lg())
 9174                    .pr_1()
 9175                    .child(styled_text),
 9176            )
 9177            .child(
 9178                h_flex()
 9179                    .h(line_height + BORDER_WIDTH * 2.)
 9180                    .px_1p5()
 9181                    .gap_1()
 9182                    // Workaround: For some reason, there's a gap if we don't do this
 9183                    .ml(-BORDER_WIDTH)
 9184                    .shadow(vec![gpui::BoxShadow {
 9185                        color: gpui::black().opacity(0.05),
 9186                        offset: point(px(1.), px(1.)),
 9187                        blur_radius: px(2.),
 9188                        spread_radius: px(0.),
 9189                    }])
 9190                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9191                    .border(BORDER_WIDTH)
 9192                    .border_color(cx.theme().colors().border)
 9193                    .rounded_r_lg()
 9194                    .id("edit_prediction_diff_popover_keybind")
 9195                    .when(!has_keybind, |el| {
 9196                        let status_colors = cx.theme().status();
 9197
 9198                        el.bg(status_colors.error_background)
 9199                            .border_color(status_colors.error.opacity(0.6))
 9200                            .child(Icon::new(IconName::Info).color(Color::Error))
 9201                            .cursor_default()
 9202                            .hoverable_tooltip(move |_window, cx| {
 9203                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9204                            })
 9205                    })
 9206                    .children(keybind),
 9207            )
 9208            .into_any();
 9209
 9210        let longest_row =
 9211            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9212        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9213            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9214        } else {
 9215            layout_line(
 9216                longest_row,
 9217                editor_snapshot,
 9218                style,
 9219                editor_width,
 9220                |_| false,
 9221                window,
 9222                cx,
 9223            )
 9224            .width
 9225        };
 9226
 9227        let viewport_bounds =
 9228            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9229                right: -right_margin,
 9230                ..Default::default()
 9231            });
 9232
 9233        let x_after_longest = Pixels::from(
 9234            ScrollPixelOffset::from(
 9235                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9236            ) - scroll_pixel_position.x,
 9237        );
 9238
 9239        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9240
 9241        // Fully visible if it can be displayed within the window (allow overlapping other
 9242        // panes). However, this is only allowed if the popover starts within text_bounds.
 9243        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9244            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9245
 9246        let mut origin = if can_position_to_the_right {
 9247            point(
 9248                x_after_longest,
 9249                text_bounds.origin.y
 9250                    + Pixels::from(
 9251                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9252                            - scroll_pixel_position.y,
 9253                    ),
 9254            )
 9255        } else {
 9256            let cursor_row = newest_selection_head.map(|head| head.row());
 9257            let above_edit = edit_start
 9258                .row()
 9259                .0
 9260                .checked_sub(line_count as u32)
 9261                .map(DisplayRow);
 9262            let below_edit = Some(edit_end.row() + 1);
 9263            let above_cursor =
 9264                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9265            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9266
 9267            // Place the edit popover adjacent to the edit if there is a location
 9268            // available that is onscreen and does not obscure the cursor. Otherwise,
 9269            // place it adjacent to the cursor.
 9270            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9271                .into_iter()
 9272                .flatten()
 9273                .find(|&start_row| {
 9274                    let end_row = start_row + line_count as u32;
 9275                    visible_row_range.contains(&start_row)
 9276                        && visible_row_range.contains(&end_row)
 9277                        && cursor_row
 9278                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9279                })?;
 9280
 9281            content_origin
 9282                + point(
 9283                    Pixels::from(-scroll_pixel_position.x),
 9284                    Pixels::from(
 9285                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9286                    ),
 9287                )
 9288        };
 9289
 9290        origin.x -= BORDER_WIDTH;
 9291
 9292        window.defer_draw(element, origin, 1);
 9293
 9294        // Do not return an element, since it will already be drawn due to defer_draw.
 9295        None
 9296    }
 9297
 9298    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9299        px(30.)
 9300    }
 9301
 9302    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9303        if self.read_only(cx) {
 9304            cx.theme().players().read_only()
 9305        } else {
 9306            self.style.as_ref().unwrap().local_player
 9307        }
 9308    }
 9309
 9310    fn render_edit_prediction_accept_keybind(
 9311        &self,
 9312        window: &mut Window,
 9313        cx: &mut App,
 9314    ) -> Option<AnyElement> {
 9315        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9316        let accept_keystroke = accept_binding.keystroke()?;
 9317
 9318        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9319
 9320        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9321            Color::Accent
 9322        } else {
 9323            Color::Muted
 9324        };
 9325
 9326        h_flex()
 9327            .px_0p5()
 9328            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9329            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9330            .text_size(TextSize::XSmall.rems(cx))
 9331            .child(h_flex().children(ui::render_modifiers(
 9332                accept_keystroke.modifiers(),
 9333                PlatformStyle::platform(),
 9334                Some(modifiers_color),
 9335                Some(IconSize::XSmall.rems().into()),
 9336                true,
 9337            )))
 9338            .when(is_platform_style_mac, |parent| {
 9339                parent.child(accept_keystroke.key().to_string())
 9340            })
 9341            .when(!is_platform_style_mac, |parent| {
 9342                parent.child(
 9343                    Key::new(
 9344                        util::capitalize(accept_keystroke.key()),
 9345                        Some(Color::Default),
 9346                    )
 9347                    .size(Some(IconSize::XSmall.rems().into())),
 9348                )
 9349            })
 9350            .into_any()
 9351            .into()
 9352    }
 9353
 9354    fn render_edit_prediction_line_popover(
 9355        &self,
 9356        label: impl Into<SharedString>,
 9357        icon: Option<IconName>,
 9358        window: &mut Window,
 9359        cx: &mut App,
 9360    ) -> Stateful<Div> {
 9361        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9362
 9363        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9364        let has_keybind = keybind.is_some();
 9365
 9366        h_flex()
 9367            .id("ep-line-popover")
 9368            .py_0p5()
 9369            .pl_1()
 9370            .pr(padding_right)
 9371            .gap_1()
 9372            .rounded_md()
 9373            .border_1()
 9374            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9375            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9376            .shadow_xs()
 9377            .when(!has_keybind, |el| {
 9378                let status_colors = cx.theme().status();
 9379
 9380                el.bg(status_colors.error_background)
 9381                    .border_color(status_colors.error.opacity(0.6))
 9382                    .pl_2()
 9383                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9384                    .cursor_default()
 9385                    .hoverable_tooltip(move |_window, cx| {
 9386                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9387                    })
 9388            })
 9389            .children(keybind)
 9390            .child(
 9391                Label::new(label)
 9392                    .size(LabelSize::Small)
 9393                    .when(!has_keybind, |el| {
 9394                        el.color(cx.theme().status().error.into()).strikethrough()
 9395                    }),
 9396            )
 9397            .when(!has_keybind, |el| {
 9398                el.child(
 9399                    h_flex().ml_1().child(
 9400                        Icon::new(IconName::Info)
 9401                            .size(IconSize::Small)
 9402                            .color(cx.theme().status().error.into()),
 9403                    ),
 9404                )
 9405            })
 9406            .when_some(icon, |element, icon| {
 9407                element.child(
 9408                    div()
 9409                        .mt(px(1.5))
 9410                        .child(Icon::new(icon).size(IconSize::Small)),
 9411                )
 9412            })
 9413    }
 9414
 9415    fn render_edit_prediction_jump_outside_popover(
 9416        &self,
 9417        snapshot: &BufferSnapshot,
 9418        window: &mut Window,
 9419        cx: &mut App,
 9420    ) -> Stateful<Div> {
 9421        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9422        let has_keybind = keybind.is_some();
 9423
 9424        let file_name = snapshot
 9425            .file()
 9426            .map(|file| SharedString::new(file.file_name(cx)))
 9427            .unwrap_or(SharedString::new_static("untitled"));
 9428
 9429        h_flex()
 9430            .id("ep-jump-outside-popover")
 9431            .py_1()
 9432            .px_2()
 9433            .gap_1()
 9434            .rounded_md()
 9435            .border_1()
 9436            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9437            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9438            .shadow_xs()
 9439            .when(!has_keybind, |el| {
 9440                let status_colors = cx.theme().status();
 9441
 9442                el.bg(status_colors.error_background)
 9443                    .border_color(status_colors.error.opacity(0.6))
 9444                    .pl_2()
 9445                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9446                    .cursor_default()
 9447                    .hoverable_tooltip(move |_window, cx| {
 9448                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9449                    })
 9450            })
 9451            .children(keybind)
 9452            .child(
 9453                Label::new(file_name)
 9454                    .size(LabelSize::Small)
 9455                    .buffer_font(cx)
 9456                    .when(!has_keybind, |el| {
 9457                        el.color(cx.theme().status().error.into()).strikethrough()
 9458                    }),
 9459            )
 9460            .when(!has_keybind, |el| {
 9461                el.child(
 9462                    h_flex().ml_1().child(
 9463                        Icon::new(IconName::Info)
 9464                            .size(IconSize::Small)
 9465                            .color(cx.theme().status().error.into()),
 9466                    ),
 9467                )
 9468            })
 9469            .child(
 9470                div()
 9471                    .mt(px(1.5))
 9472                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9473            )
 9474    }
 9475
 9476    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9477        let accent_color = cx.theme().colors().text_accent;
 9478        let editor_bg_color = cx.theme().colors().editor_background;
 9479        editor_bg_color.blend(accent_color.opacity(0.1))
 9480    }
 9481
 9482    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9483        let accent_color = cx.theme().colors().text_accent;
 9484        let editor_bg_color = cx.theme().colors().editor_background;
 9485        editor_bg_color.blend(accent_color.opacity(0.6))
 9486    }
 9487    fn get_prediction_provider_icon_name(
 9488        provider: &Option<RegisteredEditPredictionProvider>,
 9489    ) -> IconName {
 9490        match provider {
 9491            Some(provider) => match provider.provider.name() {
 9492                "copilot" => IconName::Copilot,
 9493                "supermaven" => IconName::Supermaven,
 9494                _ => IconName::ZedPredict,
 9495            },
 9496            None => IconName::ZedPredict,
 9497        }
 9498    }
 9499
 9500    fn render_edit_prediction_cursor_popover(
 9501        &self,
 9502        min_width: Pixels,
 9503        max_width: Pixels,
 9504        cursor_point: Point,
 9505        style: &EditorStyle,
 9506        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9507        _window: &Window,
 9508        cx: &mut Context<Editor>,
 9509    ) -> Option<AnyElement> {
 9510        let provider = self.edit_prediction_provider.as_ref()?;
 9511        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9512
 9513        let is_refreshing = provider.provider.is_refreshing(cx);
 9514
 9515        fn pending_completion_container(icon: IconName) -> Div {
 9516            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9517        }
 9518
 9519        let completion = match &self.active_edit_prediction {
 9520            Some(prediction) => {
 9521                if !self.has_visible_completions_menu() {
 9522                    const RADIUS: Pixels = px(6.);
 9523                    const BORDER_WIDTH: Pixels = px(1.);
 9524
 9525                    return Some(
 9526                        h_flex()
 9527                            .elevation_2(cx)
 9528                            .border(BORDER_WIDTH)
 9529                            .border_color(cx.theme().colors().border)
 9530                            .when(accept_keystroke.is_none(), |el| {
 9531                                el.border_color(cx.theme().status().error)
 9532                            })
 9533                            .rounded(RADIUS)
 9534                            .rounded_tl(px(0.))
 9535                            .overflow_hidden()
 9536                            .child(div().px_1p5().child(match &prediction.completion {
 9537                                EditPrediction::MoveWithin { target, snapshot } => {
 9538                                    use text::ToPoint as _;
 9539                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9540                                    {
 9541                                        Icon::new(IconName::ZedPredictDown)
 9542                                    } else {
 9543                                        Icon::new(IconName::ZedPredictUp)
 9544                                    }
 9545                                }
 9546                                EditPrediction::MoveOutside { .. } => {
 9547                                    // TODO [zeta2] custom icon for external jump?
 9548                                    Icon::new(provider_icon)
 9549                                }
 9550                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9551                            }))
 9552                            .child(
 9553                                h_flex()
 9554                                    .gap_1()
 9555                                    .py_1()
 9556                                    .px_2()
 9557                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9558                                    .border_l_1()
 9559                                    .border_color(cx.theme().colors().border)
 9560                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9561                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9562                                        el.child(
 9563                                            Label::new("Hold")
 9564                                                .size(LabelSize::Small)
 9565                                                .when(accept_keystroke.is_none(), |el| {
 9566                                                    el.strikethrough()
 9567                                                })
 9568                                                .line_height_style(LineHeightStyle::UiLabel),
 9569                                        )
 9570                                    })
 9571                                    .id("edit_prediction_cursor_popover_keybind")
 9572                                    .when(accept_keystroke.is_none(), |el| {
 9573                                        let status_colors = cx.theme().status();
 9574
 9575                                        el.bg(status_colors.error_background)
 9576                                            .border_color(status_colors.error.opacity(0.6))
 9577                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9578                                            .cursor_default()
 9579                                            .hoverable_tooltip(move |_window, cx| {
 9580                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9581                                                    .into()
 9582                                            })
 9583                                    })
 9584                                    .when_some(
 9585                                        accept_keystroke.as_ref(),
 9586                                        |el, accept_keystroke| {
 9587                                            el.child(h_flex().children(ui::render_modifiers(
 9588                                                accept_keystroke.modifiers(),
 9589                                                PlatformStyle::platform(),
 9590                                                Some(Color::Default),
 9591                                                Some(IconSize::XSmall.rems().into()),
 9592                                                false,
 9593                                            )))
 9594                                        },
 9595                                    ),
 9596                            )
 9597                            .into_any(),
 9598                    );
 9599                }
 9600
 9601                self.render_edit_prediction_cursor_popover_preview(
 9602                    prediction,
 9603                    cursor_point,
 9604                    style,
 9605                    cx,
 9606                )?
 9607            }
 9608
 9609            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9610                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9611                    stale_completion,
 9612                    cursor_point,
 9613                    style,
 9614                    cx,
 9615                )?,
 9616
 9617                None => pending_completion_container(provider_icon)
 9618                    .child(Label::new("...").size(LabelSize::Small)),
 9619            },
 9620
 9621            None => pending_completion_container(provider_icon)
 9622                .child(Label::new("...").size(LabelSize::Small)),
 9623        };
 9624
 9625        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9626            completion
 9627                .with_animation(
 9628                    "loading-completion",
 9629                    Animation::new(Duration::from_secs(2))
 9630                        .repeat()
 9631                        .with_easing(pulsating_between(0.4, 0.8)),
 9632                    |label, delta| label.opacity(delta),
 9633                )
 9634                .into_any_element()
 9635        } else {
 9636            completion.into_any_element()
 9637        };
 9638
 9639        let has_completion = self.active_edit_prediction.is_some();
 9640
 9641        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9642        Some(
 9643            h_flex()
 9644                .min_w(min_width)
 9645                .max_w(max_width)
 9646                .flex_1()
 9647                .elevation_2(cx)
 9648                .border_color(cx.theme().colors().border)
 9649                .child(
 9650                    div()
 9651                        .flex_1()
 9652                        .py_1()
 9653                        .px_2()
 9654                        .overflow_hidden()
 9655                        .child(completion),
 9656                )
 9657                .when_some(accept_keystroke, |el, accept_keystroke| {
 9658                    if !accept_keystroke.modifiers().modified() {
 9659                        return el;
 9660                    }
 9661
 9662                    el.child(
 9663                        h_flex()
 9664                            .h_full()
 9665                            .border_l_1()
 9666                            .rounded_r_lg()
 9667                            .border_color(cx.theme().colors().border)
 9668                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9669                            .gap_1()
 9670                            .py_1()
 9671                            .px_2()
 9672                            .child(
 9673                                h_flex()
 9674                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9675                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9676                                    .child(h_flex().children(ui::render_modifiers(
 9677                                        accept_keystroke.modifiers(),
 9678                                        PlatformStyle::platform(),
 9679                                        Some(if !has_completion {
 9680                                            Color::Muted
 9681                                        } else {
 9682                                            Color::Default
 9683                                        }),
 9684                                        None,
 9685                                        false,
 9686                                    ))),
 9687                            )
 9688                            .child(Label::new("Preview").into_any_element())
 9689                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9690                    )
 9691                })
 9692                .into_any(),
 9693        )
 9694    }
 9695
 9696    fn render_edit_prediction_cursor_popover_preview(
 9697        &self,
 9698        completion: &EditPredictionState,
 9699        cursor_point: Point,
 9700        style: &EditorStyle,
 9701        cx: &mut Context<Editor>,
 9702    ) -> Option<Div> {
 9703        use text::ToPoint as _;
 9704
 9705        fn render_relative_row_jump(
 9706            prefix: impl Into<String>,
 9707            current_row: u32,
 9708            target_row: u32,
 9709        ) -> Div {
 9710            let (row_diff, arrow) = if target_row < current_row {
 9711                (current_row - target_row, IconName::ArrowUp)
 9712            } else {
 9713                (target_row - current_row, IconName::ArrowDown)
 9714            };
 9715
 9716            h_flex()
 9717                .child(
 9718                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9719                        .color(Color::Muted)
 9720                        .size(LabelSize::Small),
 9721                )
 9722                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9723        }
 9724
 9725        let supports_jump = self
 9726            .edit_prediction_provider
 9727            .as_ref()
 9728            .map(|provider| provider.provider.supports_jump_to_edit())
 9729            .unwrap_or(true);
 9730
 9731        match &completion.completion {
 9732            EditPrediction::MoveWithin {
 9733                target, snapshot, ..
 9734            } => {
 9735                if !supports_jump {
 9736                    return None;
 9737                }
 9738
 9739                Some(
 9740                    h_flex()
 9741                        .px_2()
 9742                        .gap_2()
 9743                        .flex_1()
 9744                        .child(
 9745                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9746                                Icon::new(IconName::ZedPredictDown)
 9747                            } else {
 9748                                Icon::new(IconName::ZedPredictUp)
 9749                            },
 9750                        )
 9751                        .child(Label::new("Jump to Edit")),
 9752                )
 9753            }
 9754            EditPrediction::MoveOutside { snapshot, .. } => {
 9755                let file_name = snapshot
 9756                    .file()
 9757                    .map(|file| file.file_name(cx))
 9758                    .unwrap_or("untitled");
 9759                Some(
 9760                    h_flex()
 9761                        .px_2()
 9762                        .gap_2()
 9763                        .flex_1()
 9764                        .child(Icon::new(IconName::ZedPredict))
 9765                        .child(Label::new(format!("Jump to {file_name}"))),
 9766                )
 9767            }
 9768            EditPrediction::Edit {
 9769                edits,
 9770                edit_preview,
 9771                snapshot,
 9772                display_mode: _,
 9773            } => {
 9774                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9775
 9776                let (highlighted_edits, has_more_lines) =
 9777                    if let Some(edit_preview) = edit_preview.as_ref() {
 9778                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9779                            .first_line_preview()
 9780                    } else {
 9781                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9782                    };
 9783
 9784                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9785                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9786
 9787                let preview = h_flex()
 9788                    .gap_1()
 9789                    .min_w_16()
 9790                    .child(styled_text)
 9791                    .when(has_more_lines, |parent| parent.child(""));
 9792
 9793                let left = if supports_jump && first_edit_row != cursor_point.row {
 9794                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9795                        .into_any_element()
 9796                } else {
 9797                    let icon_name =
 9798                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9799                    Icon::new(icon_name).into_any_element()
 9800                };
 9801
 9802                Some(
 9803                    h_flex()
 9804                        .h_full()
 9805                        .flex_1()
 9806                        .gap_2()
 9807                        .pr_1()
 9808                        .overflow_x_hidden()
 9809                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9810                        .child(left)
 9811                        .child(preview),
 9812                )
 9813            }
 9814        }
 9815    }
 9816
 9817    pub fn render_context_menu(
 9818        &self,
 9819        style: &EditorStyle,
 9820        max_height_in_lines: u32,
 9821        window: &mut Window,
 9822        cx: &mut Context<Editor>,
 9823    ) -> Option<AnyElement> {
 9824        let menu = self.context_menu.borrow();
 9825        let menu = menu.as_ref()?;
 9826        if !menu.visible() {
 9827            return None;
 9828        };
 9829        Some(menu.render(style, max_height_in_lines, window, cx))
 9830    }
 9831
 9832    fn render_context_menu_aside(
 9833        &mut self,
 9834        max_size: Size<Pixels>,
 9835        window: &mut Window,
 9836        cx: &mut Context<Editor>,
 9837    ) -> Option<AnyElement> {
 9838        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9839            if menu.visible() {
 9840                menu.render_aside(max_size, window, cx)
 9841            } else {
 9842                None
 9843            }
 9844        })
 9845    }
 9846
 9847    fn hide_context_menu(
 9848        &mut self,
 9849        window: &mut Window,
 9850        cx: &mut Context<Self>,
 9851    ) -> Option<CodeContextMenu> {
 9852        cx.notify();
 9853        self.completion_tasks.clear();
 9854        let context_menu = self.context_menu.borrow_mut().take();
 9855        self.stale_edit_prediction_in_menu.take();
 9856        self.update_visible_edit_prediction(window, cx);
 9857        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9858            && let Some(completion_provider) = &self.completion_provider
 9859        {
 9860            completion_provider.selection_changed(None, window, cx);
 9861        }
 9862        context_menu
 9863    }
 9864
 9865    fn show_snippet_choices(
 9866        &mut self,
 9867        choices: &Vec<String>,
 9868        selection: Range<Anchor>,
 9869        cx: &mut Context<Self>,
 9870    ) {
 9871        let Some((_, buffer, _)) = self
 9872            .buffer()
 9873            .read(cx)
 9874            .excerpt_containing(selection.start, cx)
 9875        else {
 9876            return;
 9877        };
 9878        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9879        else {
 9880            return;
 9881        };
 9882        if buffer != end_buffer {
 9883            log::error!("expected anchor range to have matching buffer IDs");
 9884            return;
 9885        }
 9886
 9887        let id = post_inc(&mut self.next_completion_id);
 9888        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9889        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9890            CompletionsMenu::new_snippet_choices(
 9891                id,
 9892                true,
 9893                choices,
 9894                selection,
 9895                buffer,
 9896                snippet_sort_order,
 9897            ),
 9898        ));
 9899    }
 9900
 9901    pub fn insert_snippet(
 9902        &mut self,
 9903        insertion_ranges: &[Range<MultiBufferOffset>],
 9904        snippet: Snippet,
 9905        window: &mut Window,
 9906        cx: &mut Context<Self>,
 9907    ) -> Result<()> {
 9908        struct Tabstop<T> {
 9909            is_end_tabstop: bool,
 9910            ranges: Vec<Range<T>>,
 9911            choices: Option<Vec<String>>,
 9912        }
 9913
 9914        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9915            let snippet_text: Arc<str> = snippet.text.clone().into();
 9916            let edits = insertion_ranges
 9917                .iter()
 9918                .cloned()
 9919                .map(|range| (range, snippet_text.clone()));
 9920            let autoindent_mode = AutoindentMode::Block {
 9921                original_indent_columns: Vec::new(),
 9922            };
 9923            buffer.edit(edits, Some(autoindent_mode), cx);
 9924
 9925            let snapshot = &*buffer.read(cx);
 9926            let snippet = &snippet;
 9927            snippet
 9928                .tabstops
 9929                .iter()
 9930                .map(|tabstop| {
 9931                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9932                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9933                    });
 9934                    let mut tabstop_ranges = tabstop
 9935                        .ranges
 9936                        .iter()
 9937                        .flat_map(|tabstop_range| {
 9938                            let mut delta = 0_isize;
 9939                            insertion_ranges.iter().map(move |insertion_range| {
 9940                                let insertion_start = insertion_range.start + delta;
 9941                                delta += snippet.text.len() as isize
 9942                                    - (insertion_range.end - insertion_range.start) as isize;
 9943
 9944                                let start =
 9945                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9946                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9947                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9948                            })
 9949                        })
 9950                        .collect::<Vec<_>>();
 9951                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9952
 9953                    Tabstop {
 9954                        is_end_tabstop,
 9955                        ranges: tabstop_ranges,
 9956                        choices: tabstop.choices.clone(),
 9957                    }
 9958                })
 9959                .collect::<Vec<_>>()
 9960        });
 9961        if let Some(tabstop) = tabstops.first() {
 9962            self.change_selections(Default::default(), window, cx, |s| {
 9963                // Reverse order so that the first range is the newest created selection.
 9964                // Completions will use it and autoscroll will prioritize it.
 9965                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9966            });
 9967
 9968            if let Some(choices) = &tabstop.choices
 9969                && let Some(selection) = tabstop.ranges.first()
 9970            {
 9971                self.show_snippet_choices(choices, selection.clone(), cx)
 9972            }
 9973
 9974            // If we're already at the last tabstop and it's at the end of the snippet,
 9975            // we're done, we don't need to keep the state around.
 9976            if !tabstop.is_end_tabstop {
 9977                let choices = tabstops
 9978                    .iter()
 9979                    .map(|tabstop| tabstop.choices.clone())
 9980                    .collect();
 9981
 9982                let ranges = tabstops
 9983                    .into_iter()
 9984                    .map(|tabstop| tabstop.ranges)
 9985                    .collect::<Vec<_>>();
 9986
 9987                self.snippet_stack.push(SnippetState {
 9988                    active_index: 0,
 9989                    ranges,
 9990                    choices,
 9991                });
 9992            }
 9993
 9994            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9995            if self.autoclose_regions.is_empty() {
 9996                let snapshot = self.buffer.read(cx).snapshot(cx);
 9997                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9998                    let selection_head = selection.head();
 9999                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10000                        continue;
10001                    };
10002
10003                    let mut bracket_pair = None;
10004                    let max_lookup_length = scope
10005                        .brackets()
10006                        .map(|(pair, _)| {
10007                            pair.start
10008                                .as_str()
10009                                .chars()
10010                                .count()
10011                                .max(pair.end.as_str().chars().count())
10012                        })
10013                        .max();
10014                    if let Some(max_lookup_length) = max_lookup_length {
10015                        let next_text = snapshot
10016                            .chars_at(selection_head)
10017                            .take(max_lookup_length)
10018                            .collect::<String>();
10019                        let prev_text = snapshot
10020                            .reversed_chars_at(selection_head)
10021                            .take(max_lookup_length)
10022                            .collect::<String>();
10023
10024                        for (pair, enabled) in scope.brackets() {
10025                            if enabled
10026                                && pair.close
10027                                && prev_text.starts_with(pair.start.as_str())
10028                                && next_text.starts_with(pair.end.as_str())
10029                            {
10030                                bracket_pair = Some(pair.clone());
10031                                break;
10032                            }
10033                        }
10034                    }
10035
10036                    if let Some(pair) = bracket_pair {
10037                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10038                        let autoclose_enabled =
10039                            self.use_autoclose && snapshot_settings.use_autoclose;
10040                        if autoclose_enabled {
10041                            let start = snapshot.anchor_after(selection_head);
10042                            let end = snapshot.anchor_after(selection_head);
10043                            self.autoclose_regions.push(AutocloseRegion {
10044                                selection_id: selection.id,
10045                                range: start..end,
10046                                pair,
10047                            });
10048                        }
10049                    }
10050                }
10051            }
10052        }
10053        Ok(())
10054    }
10055
10056    pub fn move_to_next_snippet_tabstop(
10057        &mut self,
10058        window: &mut Window,
10059        cx: &mut Context<Self>,
10060    ) -> bool {
10061        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10062    }
10063
10064    pub fn move_to_prev_snippet_tabstop(
10065        &mut self,
10066        window: &mut Window,
10067        cx: &mut Context<Self>,
10068    ) -> bool {
10069        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10070    }
10071
10072    pub fn move_to_snippet_tabstop(
10073        &mut self,
10074        bias: Bias,
10075        window: &mut Window,
10076        cx: &mut Context<Self>,
10077    ) -> bool {
10078        if let Some(mut snippet) = self.snippet_stack.pop() {
10079            match bias {
10080                Bias::Left => {
10081                    if snippet.active_index > 0 {
10082                        snippet.active_index -= 1;
10083                    } else {
10084                        self.snippet_stack.push(snippet);
10085                        return false;
10086                    }
10087                }
10088                Bias::Right => {
10089                    if snippet.active_index + 1 < snippet.ranges.len() {
10090                        snippet.active_index += 1;
10091                    } else {
10092                        self.snippet_stack.push(snippet);
10093                        return false;
10094                    }
10095                }
10096            }
10097            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10098                self.change_selections(Default::default(), window, cx, |s| {
10099                    // Reverse order so that the first range is the newest created selection.
10100                    // Completions will use it and autoscroll will prioritize it.
10101                    s.select_ranges(current_ranges.iter().rev().cloned())
10102                });
10103
10104                if let Some(choices) = &snippet.choices[snippet.active_index]
10105                    && let Some(selection) = current_ranges.first()
10106                {
10107                    self.show_snippet_choices(choices, selection.clone(), cx);
10108                }
10109
10110                // If snippet state is not at the last tabstop, push it back on the stack
10111                if snippet.active_index + 1 < snippet.ranges.len() {
10112                    self.snippet_stack.push(snippet);
10113                }
10114                return true;
10115            }
10116        }
10117
10118        false
10119    }
10120
10121    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10122        self.transact(window, cx, |this, window, cx| {
10123            this.select_all(&SelectAll, window, cx);
10124            this.insert("", window, cx);
10125        });
10126    }
10127
10128    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10129        if self.read_only(cx) {
10130            return;
10131        }
10132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10133        self.transact(window, cx, |this, window, cx| {
10134            this.select_autoclose_pair(window, cx);
10135
10136            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10137
10138            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10139            if !this.linked_edit_ranges.is_empty() {
10140                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10141                let snapshot = this.buffer.read(cx).snapshot(cx);
10142
10143                for selection in selections.iter() {
10144                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10145                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10146                    if selection_start.buffer_id != selection_end.buffer_id {
10147                        continue;
10148                    }
10149                    if let Some(ranges) =
10150                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10151                    {
10152                        for (buffer, entries) in ranges {
10153                            linked_ranges.entry(buffer).or_default().extend(entries);
10154                        }
10155                    }
10156                }
10157            }
10158
10159            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10160            for selection in &mut selections {
10161                if selection.is_empty() {
10162                    let old_head = selection.head();
10163                    let mut new_head =
10164                        movement::left(&display_map, old_head.to_display_point(&display_map))
10165                            .to_point(&display_map);
10166                    if let Some((buffer, line_buffer_range)) = display_map
10167                        .buffer_snapshot()
10168                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10169                    {
10170                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10171                        let indent_len = match indent_size.kind {
10172                            IndentKind::Space => {
10173                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10174                            }
10175                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10176                        };
10177                        if old_head.column <= indent_size.len && old_head.column > 0 {
10178                            let indent_len = indent_len.get();
10179                            new_head = cmp::min(
10180                                new_head,
10181                                MultiBufferPoint::new(
10182                                    old_head.row,
10183                                    ((old_head.column - 1) / indent_len) * indent_len,
10184                                ),
10185                            );
10186                        }
10187                    }
10188
10189                    selection.set_head(new_head, SelectionGoal::None);
10190                }
10191            }
10192
10193            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10194            this.insert("", window, cx);
10195            let empty_str: Arc<str> = Arc::from("");
10196            for (buffer, edits) in linked_ranges {
10197                let snapshot = buffer.read(cx).snapshot();
10198                use text::ToPoint as TP;
10199
10200                let edits = edits
10201                    .into_iter()
10202                    .map(|range| {
10203                        let end_point = TP::to_point(&range.end, &snapshot);
10204                        let mut start_point = TP::to_point(&range.start, &snapshot);
10205
10206                        if end_point == start_point {
10207                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10208                                .saturating_sub(1);
10209                            start_point =
10210                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10211                        };
10212
10213                        (start_point..end_point, empty_str.clone())
10214                    })
10215                    .sorted_by_key(|(range, _)| range.start)
10216                    .collect::<Vec<_>>();
10217                buffer.update(cx, |this, cx| {
10218                    this.edit(edits, None, cx);
10219                })
10220            }
10221            this.refresh_edit_prediction(true, false, window, cx);
10222            refresh_linked_ranges(this, window, cx);
10223        });
10224    }
10225
10226    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10227        if self.read_only(cx) {
10228            return;
10229        }
10230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10231        self.transact(window, cx, |this, window, cx| {
10232            this.change_selections(Default::default(), window, cx, |s| {
10233                s.move_with(|map, selection| {
10234                    if selection.is_empty() {
10235                        let cursor = movement::right(map, selection.head());
10236                        selection.end = cursor;
10237                        selection.reversed = true;
10238                        selection.goal = SelectionGoal::None;
10239                    }
10240                })
10241            });
10242            this.insert("", window, cx);
10243            this.refresh_edit_prediction(true, false, window, cx);
10244        });
10245    }
10246
10247    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10248        if self.mode.is_single_line() {
10249            cx.propagate();
10250            return;
10251        }
10252
10253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10254        if self.move_to_prev_snippet_tabstop(window, cx) {
10255            return;
10256        }
10257        self.outdent(&Outdent, window, cx);
10258    }
10259
10260    pub fn next_snippet_tabstop(
10261        &mut self,
10262        _: &NextSnippetTabstop,
10263        window: &mut Window,
10264        cx: &mut Context<Self>,
10265    ) {
10266        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10267            cx.propagate();
10268            return;
10269        }
10270
10271        if self.move_to_next_snippet_tabstop(window, cx) {
10272            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10273            return;
10274        }
10275        cx.propagate();
10276    }
10277
10278    pub fn previous_snippet_tabstop(
10279        &mut self,
10280        _: &PreviousSnippetTabstop,
10281        window: &mut Window,
10282        cx: &mut Context<Self>,
10283    ) {
10284        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10285            cx.propagate();
10286            return;
10287        }
10288
10289        if self.move_to_prev_snippet_tabstop(window, cx) {
10290            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10291            return;
10292        }
10293        cx.propagate();
10294    }
10295
10296    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10297        if self.mode.is_single_line() {
10298            cx.propagate();
10299            return;
10300        }
10301
10302        if self.move_to_next_snippet_tabstop(window, cx) {
10303            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10304            return;
10305        }
10306        if self.read_only(cx) {
10307            return;
10308        }
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10311        let buffer = self.buffer.read(cx);
10312        let snapshot = buffer.snapshot(cx);
10313        let rows_iter = selections.iter().map(|s| s.head().row);
10314        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10315
10316        let has_some_cursor_in_whitespace = selections
10317            .iter()
10318            .filter(|selection| selection.is_empty())
10319            .any(|selection| {
10320                let cursor = selection.head();
10321                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10322                cursor.column < current_indent.len
10323            });
10324
10325        let mut edits = Vec::new();
10326        let mut prev_edited_row = 0;
10327        let mut row_delta = 0;
10328        for selection in &mut selections {
10329            if selection.start.row != prev_edited_row {
10330                row_delta = 0;
10331            }
10332            prev_edited_row = selection.end.row;
10333
10334            // If the selection is non-empty, then increase the indentation of the selected lines.
10335            if !selection.is_empty() {
10336                row_delta =
10337                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10338                continue;
10339            }
10340
10341            let cursor = selection.head();
10342            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10343            if let Some(suggested_indent) =
10344                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10345            {
10346                // Don't do anything if already at suggested indent
10347                // and there is any other cursor which is not
10348                if has_some_cursor_in_whitespace
10349                    && cursor.column == current_indent.len
10350                    && current_indent.len == suggested_indent.len
10351                {
10352                    continue;
10353                }
10354
10355                // Adjust line and move cursor to suggested indent
10356                // if cursor is not at suggested indent
10357                if cursor.column < suggested_indent.len
10358                    && cursor.column <= current_indent.len
10359                    && current_indent.len <= suggested_indent.len
10360                {
10361                    selection.start = Point::new(cursor.row, suggested_indent.len);
10362                    selection.end = selection.start;
10363                    if row_delta == 0 {
10364                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10365                            cursor.row,
10366                            current_indent,
10367                            suggested_indent,
10368                        ));
10369                        row_delta = suggested_indent.len - current_indent.len;
10370                    }
10371                    continue;
10372                }
10373
10374                // If current indent is more than suggested indent
10375                // only move cursor to current indent and skip indent
10376                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10377                    selection.start = Point::new(cursor.row, current_indent.len);
10378                    selection.end = selection.start;
10379                    continue;
10380                }
10381            }
10382
10383            // Otherwise, insert a hard or soft tab.
10384            let settings = buffer.language_settings_at(cursor, cx);
10385            let tab_size = if settings.hard_tabs {
10386                IndentSize::tab()
10387            } else {
10388                let tab_size = settings.tab_size.get();
10389                let indent_remainder = snapshot
10390                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10391                    .flat_map(str::chars)
10392                    .fold(row_delta % tab_size, |counter: u32, c| {
10393                        if c == '\t' {
10394                            0
10395                        } else {
10396                            (counter + 1) % tab_size
10397                        }
10398                    });
10399
10400                let chars_to_next_tab_stop = tab_size - indent_remainder;
10401                IndentSize::spaces(chars_to_next_tab_stop)
10402            };
10403            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10404            selection.end = selection.start;
10405            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10406            row_delta += tab_size.len;
10407        }
10408
10409        self.transact(window, cx, |this, window, cx| {
10410            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10411            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10412            this.refresh_edit_prediction(true, false, window, cx);
10413        });
10414    }
10415
10416    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10417        if self.read_only(cx) {
10418            return;
10419        }
10420        if self.mode.is_single_line() {
10421            cx.propagate();
10422            return;
10423        }
10424
10425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10426        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10427        let mut prev_edited_row = 0;
10428        let mut row_delta = 0;
10429        let mut edits = Vec::new();
10430        let buffer = self.buffer.read(cx);
10431        let snapshot = buffer.snapshot(cx);
10432        for selection in &mut selections {
10433            if selection.start.row != prev_edited_row {
10434                row_delta = 0;
10435            }
10436            prev_edited_row = selection.end.row;
10437
10438            row_delta =
10439                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10440        }
10441
10442        self.transact(window, cx, |this, window, cx| {
10443            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10444            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10445        });
10446    }
10447
10448    fn indent_selection(
10449        buffer: &MultiBuffer,
10450        snapshot: &MultiBufferSnapshot,
10451        selection: &mut Selection<Point>,
10452        edits: &mut Vec<(Range<Point>, String)>,
10453        delta_for_start_row: u32,
10454        cx: &App,
10455    ) -> u32 {
10456        let settings = buffer.language_settings_at(selection.start, cx);
10457        let tab_size = settings.tab_size.get();
10458        let indent_kind = if settings.hard_tabs {
10459            IndentKind::Tab
10460        } else {
10461            IndentKind::Space
10462        };
10463        let mut start_row = selection.start.row;
10464        let mut end_row = selection.end.row + 1;
10465
10466        // If a selection ends at the beginning of a line, don't indent
10467        // that last line.
10468        if selection.end.column == 0 && selection.end.row > selection.start.row {
10469            end_row -= 1;
10470        }
10471
10472        // Avoid re-indenting a row that has already been indented by a
10473        // previous selection, but still update this selection's column
10474        // to reflect that indentation.
10475        if delta_for_start_row > 0 {
10476            start_row += 1;
10477            selection.start.column += delta_for_start_row;
10478            if selection.end.row == selection.start.row {
10479                selection.end.column += delta_for_start_row;
10480            }
10481        }
10482
10483        let mut delta_for_end_row = 0;
10484        let has_multiple_rows = start_row + 1 != end_row;
10485        for row in start_row..end_row {
10486            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10487            let indent_delta = match (current_indent.kind, indent_kind) {
10488                (IndentKind::Space, IndentKind::Space) => {
10489                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10490                    IndentSize::spaces(columns_to_next_tab_stop)
10491                }
10492                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10493                (_, IndentKind::Tab) => IndentSize::tab(),
10494            };
10495
10496            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10497                0
10498            } else {
10499                selection.start.column
10500            };
10501            let row_start = Point::new(row, start);
10502            edits.push((
10503                row_start..row_start,
10504                indent_delta.chars().collect::<String>(),
10505            ));
10506
10507            // Update this selection's endpoints to reflect the indentation.
10508            if row == selection.start.row {
10509                selection.start.column += indent_delta.len;
10510            }
10511            if row == selection.end.row {
10512                selection.end.column += indent_delta.len;
10513                delta_for_end_row = indent_delta.len;
10514            }
10515        }
10516
10517        if selection.start.row == selection.end.row {
10518            delta_for_start_row + delta_for_end_row
10519        } else {
10520            delta_for_end_row
10521        }
10522    }
10523
10524    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10525        if self.read_only(cx) {
10526            return;
10527        }
10528        if self.mode.is_single_line() {
10529            cx.propagate();
10530            return;
10531        }
10532
10533        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10535        let selections = self.selections.all::<Point>(&display_map);
10536        let mut deletion_ranges = Vec::new();
10537        let mut last_outdent = None;
10538        {
10539            let buffer = self.buffer.read(cx);
10540            let snapshot = buffer.snapshot(cx);
10541            for selection in &selections {
10542                let settings = buffer.language_settings_at(selection.start, cx);
10543                let tab_size = settings.tab_size.get();
10544                let mut rows = selection.spanned_rows(false, &display_map);
10545
10546                // Avoid re-outdenting a row that has already been outdented by a
10547                // previous selection.
10548                if let Some(last_row) = last_outdent
10549                    && last_row == rows.start
10550                {
10551                    rows.start = rows.start.next_row();
10552                }
10553                let has_multiple_rows = rows.len() > 1;
10554                for row in rows.iter_rows() {
10555                    let indent_size = snapshot.indent_size_for_line(row);
10556                    if indent_size.len > 0 {
10557                        let deletion_len = match indent_size.kind {
10558                            IndentKind::Space => {
10559                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10560                                if columns_to_prev_tab_stop == 0 {
10561                                    tab_size
10562                                } else {
10563                                    columns_to_prev_tab_stop
10564                                }
10565                            }
10566                            IndentKind::Tab => 1,
10567                        };
10568                        let start = if has_multiple_rows
10569                            || deletion_len > selection.start.column
10570                            || indent_size.len < selection.start.column
10571                        {
10572                            0
10573                        } else {
10574                            selection.start.column - deletion_len
10575                        };
10576                        deletion_ranges.push(
10577                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10578                        );
10579                        last_outdent = Some(row);
10580                    }
10581                }
10582            }
10583        }
10584
10585        self.transact(window, cx, |this, window, cx| {
10586            this.buffer.update(cx, |buffer, cx| {
10587                let empty_str: Arc<str> = Arc::default();
10588                buffer.edit(
10589                    deletion_ranges
10590                        .into_iter()
10591                        .map(|range| (range, empty_str.clone())),
10592                    None,
10593                    cx,
10594                );
10595            });
10596            let selections = this
10597                .selections
10598                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10599            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10600        });
10601    }
10602
10603    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10604        if self.read_only(cx) {
10605            return;
10606        }
10607        if self.mode.is_single_line() {
10608            cx.propagate();
10609            return;
10610        }
10611
10612        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10613        let selections = self
10614            .selections
10615            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10616            .into_iter()
10617            .map(|s| s.range());
10618
10619        self.transact(window, cx, |this, window, cx| {
10620            this.buffer.update(cx, |buffer, cx| {
10621                buffer.autoindent_ranges(selections, cx);
10622            });
10623            let selections = this
10624                .selections
10625                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10626            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10627        });
10628    }
10629
10630    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10633        let selections = self.selections.all::<Point>(&display_map);
10634
10635        let mut new_cursors = Vec::new();
10636        let mut edit_ranges = Vec::new();
10637        let mut selections = selections.iter().peekable();
10638        while let Some(selection) = selections.next() {
10639            let mut rows = selection.spanned_rows(false, &display_map);
10640
10641            // Accumulate contiguous regions of rows that we want to delete.
10642            while let Some(next_selection) = selections.peek() {
10643                let next_rows = next_selection.spanned_rows(false, &display_map);
10644                if next_rows.start <= rows.end {
10645                    rows.end = next_rows.end;
10646                    selections.next().unwrap();
10647                } else {
10648                    break;
10649                }
10650            }
10651
10652            let buffer = display_map.buffer_snapshot();
10653            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10654            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10655                // If there's a line after the range, delete the \n from the end of the row range
10656                (
10657                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10658                    rows.end,
10659                )
10660            } else {
10661                // If there isn't a line after the range, delete the \n from the line before the
10662                // start of the row range
10663                edit_start = edit_start.saturating_sub_usize(1);
10664                (buffer.len(), rows.start.previous_row())
10665            };
10666
10667            let text_layout_details = self.text_layout_details(window);
10668            let x = display_map.x_for_display_point(
10669                selection.head().to_display_point(&display_map),
10670                &text_layout_details,
10671            );
10672            let row = Point::new(target_row.0, 0)
10673                .to_display_point(&display_map)
10674                .row();
10675            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10676
10677            new_cursors.push((
10678                selection.id,
10679                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10680                SelectionGoal::None,
10681            ));
10682            edit_ranges.push(edit_start..edit_end);
10683        }
10684
10685        self.transact(window, cx, |this, window, cx| {
10686            let buffer = this.buffer.update(cx, |buffer, cx| {
10687                let empty_str: Arc<str> = Arc::default();
10688                buffer.edit(
10689                    edit_ranges
10690                        .into_iter()
10691                        .map(|range| (range, empty_str.clone())),
10692                    None,
10693                    cx,
10694                );
10695                buffer.snapshot(cx)
10696            });
10697            let new_selections = new_cursors
10698                .into_iter()
10699                .map(|(id, cursor, goal)| {
10700                    let cursor = cursor.to_point(&buffer);
10701                    Selection {
10702                        id,
10703                        start: cursor,
10704                        end: cursor,
10705                        reversed: false,
10706                        goal,
10707                    }
10708                })
10709                .collect();
10710
10711            this.change_selections(Default::default(), window, cx, |s| {
10712                s.select(new_selections);
10713            });
10714        });
10715    }
10716
10717    pub fn join_lines_impl(
10718        &mut self,
10719        insert_whitespace: bool,
10720        window: &mut Window,
10721        cx: &mut Context<Self>,
10722    ) {
10723        if self.read_only(cx) {
10724            return;
10725        }
10726        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10727        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10728            let start = MultiBufferRow(selection.start.row);
10729            // Treat single line selections as if they include the next line. Otherwise this action
10730            // would do nothing for single line selections individual cursors.
10731            let end = if selection.start.row == selection.end.row {
10732                MultiBufferRow(selection.start.row + 1)
10733            } else {
10734                MultiBufferRow(selection.end.row)
10735            };
10736
10737            if let Some(last_row_range) = row_ranges.last_mut()
10738                && start <= last_row_range.end
10739            {
10740                last_row_range.end = end;
10741                continue;
10742            }
10743            row_ranges.push(start..end);
10744        }
10745
10746        let snapshot = self.buffer.read(cx).snapshot(cx);
10747        let mut cursor_positions = Vec::new();
10748        for row_range in &row_ranges {
10749            let anchor = snapshot.anchor_before(Point::new(
10750                row_range.end.previous_row().0,
10751                snapshot.line_len(row_range.end.previous_row()),
10752            ));
10753            cursor_positions.push(anchor..anchor);
10754        }
10755
10756        self.transact(window, cx, |this, window, cx| {
10757            for row_range in row_ranges.into_iter().rev() {
10758                for row in row_range.iter_rows().rev() {
10759                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10760                    let next_line_row = row.next_row();
10761                    let indent = snapshot.indent_size_for_line(next_line_row);
10762                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10763
10764                    let replace =
10765                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10766                            " "
10767                        } else {
10768                            ""
10769                        };
10770
10771                    this.buffer.update(cx, |buffer, cx| {
10772                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10773                    });
10774                }
10775            }
10776
10777            this.change_selections(Default::default(), window, cx, |s| {
10778                s.select_anchor_ranges(cursor_positions)
10779            });
10780        });
10781    }
10782
10783    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10784        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10785        self.join_lines_impl(true, window, cx);
10786    }
10787
10788    pub fn sort_lines_case_sensitive(
10789        &mut self,
10790        _: &SortLinesCaseSensitive,
10791        window: &mut Window,
10792        cx: &mut Context<Self>,
10793    ) {
10794        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10795    }
10796
10797    pub fn sort_lines_by_length(
10798        &mut self,
10799        _: &SortLinesByLength,
10800        window: &mut Window,
10801        cx: &mut Context<Self>,
10802    ) {
10803        self.manipulate_immutable_lines(window, cx, |lines| {
10804            lines.sort_by_key(|&line| line.chars().count())
10805        })
10806    }
10807
10808    pub fn sort_lines_case_insensitive(
10809        &mut self,
10810        _: &SortLinesCaseInsensitive,
10811        window: &mut Window,
10812        cx: &mut Context<Self>,
10813    ) {
10814        self.manipulate_immutable_lines(window, cx, |lines| {
10815            lines.sort_by_key(|line| line.to_lowercase())
10816        })
10817    }
10818
10819    pub fn unique_lines_case_insensitive(
10820        &mut self,
10821        _: &UniqueLinesCaseInsensitive,
10822        window: &mut Window,
10823        cx: &mut Context<Self>,
10824    ) {
10825        self.manipulate_immutable_lines(window, cx, |lines| {
10826            let mut seen = HashSet::default();
10827            lines.retain(|line| seen.insert(line.to_lowercase()));
10828        })
10829    }
10830
10831    pub fn unique_lines_case_sensitive(
10832        &mut self,
10833        _: &UniqueLinesCaseSensitive,
10834        window: &mut Window,
10835        cx: &mut Context<Self>,
10836    ) {
10837        self.manipulate_immutable_lines(window, cx, |lines| {
10838            let mut seen = HashSet::default();
10839            lines.retain(|line| seen.insert(*line));
10840        })
10841    }
10842
10843    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10844        let snapshot = self.buffer.read(cx).snapshot(cx);
10845        for selection in self.selections.disjoint_anchors_arc().iter() {
10846            if snapshot
10847                .language_at(selection.start)
10848                .and_then(|lang| lang.config().wrap_characters.as_ref())
10849                .is_some()
10850            {
10851                return true;
10852            }
10853        }
10854        false
10855    }
10856
10857    fn wrap_selections_in_tag(
10858        &mut self,
10859        _: &WrapSelectionsInTag,
10860        window: &mut Window,
10861        cx: &mut Context<Self>,
10862    ) {
10863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10864
10865        let snapshot = self.buffer.read(cx).snapshot(cx);
10866
10867        let mut edits = Vec::new();
10868        let mut boundaries = Vec::new();
10869
10870        for selection in self
10871            .selections
10872            .all_adjusted(&self.display_snapshot(cx))
10873            .iter()
10874        {
10875            let Some(wrap_config) = snapshot
10876                .language_at(selection.start)
10877                .and_then(|lang| lang.config().wrap_characters.clone())
10878            else {
10879                continue;
10880            };
10881
10882            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10883            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10884
10885            let start_before = snapshot.anchor_before(selection.start);
10886            let end_after = snapshot.anchor_after(selection.end);
10887
10888            edits.push((start_before..start_before, open_tag));
10889            edits.push((end_after..end_after, close_tag));
10890
10891            boundaries.push((
10892                start_before,
10893                end_after,
10894                wrap_config.start_prefix.len(),
10895                wrap_config.end_suffix.len(),
10896            ));
10897        }
10898
10899        if edits.is_empty() {
10900            return;
10901        }
10902
10903        self.transact(window, cx, |this, window, cx| {
10904            let buffer = this.buffer.update(cx, |buffer, cx| {
10905                buffer.edit(edits, None, cx);
10906                buffer.snapshot(cx)
10907            });
10908
10909            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10910            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10911                boundaries.into_iter()
10912            {
10913                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10914                let close_offset = end_after
10915                    .to_offset(&buffer)
10916                    .saturating_sub_usize(end_suffix_len);
10917                new_selections.push(open_offset..open_offset);
10918                new_selections.push(close_offset..close_offset);
10919            }
10920
10921            this.change_selections(Default::default(), window, cx, |s| {
10922                s.select_ranges(new_selections);
10923            });
10924
10925            this.request_autoscroll(Autoscroll::fit(), cx);
10926        });
10927    }
10928
10929    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10930        let Some(project) = self.project.clone() else {
10931            return;
10932        };
10933        self.reload(project, window, cx)
10934            .detach_and_notify_err(window, cx);
10935    }
10936
10937    pub fn restore_file(
10938        &mut self,
10939        _: &::git::RestoreFile,
10940        window: &mut Window,
10941        cx: &mut Context<Self>,
10942    ) {
10943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10944        let mut buffer_ids = HashSet::default();
10945        let snapshot = self.buffer().read(cx).snapshot(cx);
10946        for selection in self
10947            .selections
10948            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10949        {
10950            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10951        }
10952
10953        let buffer = self.buffer().read(cx);
10954        let ranges = buffer_ids
10955            .into_iter()
10956            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10957            .collect::<Vec<_>>();
10958
10959        self.restore_hunks_in_ranges(ranges, window, cx);
10960    }
10961
10962    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10964        let selections = self
10965            .selections
10966            .all(&self.display_snapshot(cx))
10967            .into_iter()
10968            .map(|s| s.range())
10969            .collect();
10970        self.restore_hunks_in_ranges(selections, window, cx);
10971    }
10972
10973    pub fn restore_hunks_in_ranges(
10974        &mut self,
10975        ranges: Vec<Range<Point>>,
10976        window: &mut Window,
10977        cx: &mut Context<Editor>,
10978    ) {
10979        let mut revert_changes = HashMap::default();
10980        let chunk_by = self
10981            .snapshot(window, cx)
10982            .hunks_for_ranges(ranges)
10983            .into_iter()
10984            .chunk_by(|hunk| hunk.buffer_id);
10985        for (buffer_id, hunks) in &chunk_by {
10986            let hunks = hunks.collect::<Vec<_>>();
10987            for hunk in &hunks {
10988                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10989            }
10990            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10991        }
10992        drop(chunk_by);
10993        if !revert_changes.is_empty() {
10994            self.transact(window, cx, |editor, window, cx| {
10995                editor.restore(revert_changes, window, cx);
10996            });
10997        }
10998    }
10999
11000    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11001        if let Some(status) = self
11002            .addons
11003            .iter()
11004            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11005        {
11006            return Some(status);
11007        }
11008        self.project
11009            .as_ref()?
11010            .read(cx)
11011            .status_for_buffer_id(buffer_id, cx)
11012    }
11013
11014    pub fn open_active_item_in_terminal(
11015        &mut self,
11016        _: &OpenInTerminal,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11021            let project_path = buffer.read(cx).project_path(cx)?;
11022            let project = self.project()?.read(cx);
11023            let entry = project.entry_for_path(&project_path, cx)?;
11024            let parent = match &entry.canonical_path {
11025                Some(canonical_path) => canonical_path.to_path_buf(),
11026                None => project.absolute_path(&project_path, cx)?,
11027            }
11028            .parent()?
11029            .to_path_buf();
11030            Some(parent)
11031        }) {
11032            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11033        }
11034    }
11035
11036    fn set_breakpoint_context_menu(
11037        &mut self,
11038        display_row: DisplayRow,
11039        position: Option<Anchor>,
11040        clicked_point: gpui::Point<Pixels>,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) {
11044        let source = self
11045            .buffer
11046            .read(cx)
11047            .snapshot(cx)
11048            .anchor_before(Point::new(display_row.0, 0u32));
11049
11050        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11051
11052        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11053            self,
11054            source,
11055            clicked_point,
11056            context_menu,
11057            window,
11058            cx,
11059        );
11060    }
11061
11062    fn add_edit_breakpoint_block(
11063        &mut self,
11064        anchor: Anchor,
11065        breakpoint: &Breakpoint,
11066        edit_action: BreakpointPromptEditAction,
11067        window: &mut Window,
11068        cx: &mut Context<Self>,
11069    ) {
11070        let weak_editor = cx.weak_entity();
11071        let bp_prompt = cx.new(|cx| {
11072            BreakpointPromptEditor::new(
11073                weak_editor,
11074                anchor,
11075                breakpoint.clone(),
11076                edit_action,
11077                window,
11078                cx,
11079            )
11080        });
11081
11082        let height = bp_prompt.update(cx, |this, cx| {
11083            this.prompt
11084                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11085        });
11086        let cloned_prompt = bp_prompt.clone();
11087        let blocks = vec![BlockProperties {
11088            style: BlockStyle::Sticky,
11089            placement: BlockPlacement::Above(anchor),
11090            height: Some(height),
11091            render: Arc::new(move |cx| {
11092                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11093                cloned_prompt.clone().into_any_element()
11094            }),
11095            priority: 0,
11096        }];
11097
11098        let focus_handle = bp_prompt.focus_handle(cx);
11099        window.focus(&focus_handle);
11100
11101        let block_ids = self.insert_blocks(blocks, None, cx);
11102        bp_prompt.update(cx, |prompt, _| {
11103            prompt.add_block_ids(block_ids);
11104        });
11105    }
11106
11107    pub(crate) fn breakpoint_at_row(
11108        &self,
11109        row: u32,
11110        window: &mut Window,
11111        cx: &mut Context<Self>,
11112    ) -> Option<(Anchor, Breakpoint)> {
11113        let snapshot = self.snapshot(window, cx);
11114        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11115
11116        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11117    }
11118
11119    pub(crate) fn breakpoint_at_anchor(
11120        &self,
11121        breakpoint_position: Anchor,
11122        snapshot: &EditorSnapshot,
11123        cx: &mut Context<Self>,
11124    ) -> Option<(Anchor, Breakpoint)> {
11125        let buffer = self
11126            .buffer
11127            .read(cx)
11128            .buffer_for_anchor(breakpoint_position, cx)?;
11129
11130        let enclosing_excerpt = breakpoint_position.excerpt_id;
11131        let buffer_snapshot = buffer.read(cx).snapshot();
11132
11133        let row = buffer_snapshot
11134            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11135            .row;
11136
11137        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11138        let anchor_end = snapshot
11139            .buffer_snapshot()
11140            .anchor_after(Point::new(row, line_len));
11141
11142        self.breakpoint_store
11143            .as_ref()?
11144            .read_with(cx, |breakpoint_store, cx| {
11145                breakpoint_store
11146                    .breakpoints(
11147                        &buffer,
11148                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11149                        &buffer_snapshot,
11150                        cx,
11151                    )
11152                    .next()
11153                    .and_then(|(bp, _)| {
11154                        let breakpoint_row = buffer_snapshot
11155                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11156                            .row;
11157
11158                        if breakpoint_row == row {
11159                            snapshot
11160                                .buffer_snapshot()
11161                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11162                                .map(|position| (position, bp.bp.clone()))
11163                        } else {
11164                            None
11165                        }
11166                    })
11167            })
11168    }
11169
11170    pub fn edit_log_breakpoint(
11171        &mut self,
11172        _: &EditLogBreakpoint,
11173        window: &mut Window,
11174        cx: &mut Context<Self>,
11175    ) {
11176        if self.breakpoint_store.is_none() {
11177            return;
11178        }
11179
11180        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11181            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11182                message: None,
11183                state: BreakpointState::Enabled,
11184                condition: None,
11185                hit_condition: None,
11186            });
11187
11188            self.add_edit_breakpoint_block(
11189                anchor,
11190                &breakpoint,
11191                BreakpointPromptEditAction::Log,
11192                window,
11193                cx,
11194            );
11195        }
11196    }
11197
11198    fn breakpoints_at_cursors(
11199        &self,
11200        window: &mut Window,
11201        cx: &mut Context<Self>,
11202    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11203        let snapshot = self.snapshot(window, cx);
11204        let cursors = self
11205            .selections
11206            .disjoint_anchors_arc()
11207            .iter()
11208            .map(|selection| {
11209                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11210
11211                let breakpoint_position = self
11212                    .breakpoint_at_row(cursor_position.row, window, cx)
11213                    .map(|bp| bp.0)
11214                    .unwrap_or_else(|| {
11215                        snapshot
11216                            .display_snapshot
11217                            .buffer_snapshot()
11218                            .anchor_after(Point::new(cursor_position.row, 0))
11219                    });
11220
11221                let breakpoint = self
11222                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11223                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11224
11225                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11226            })
11227            // 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.
11228            .collect::<HashMap<Anchor, _>>();
11229
11230        cursors.into_iter().collect()
11231    }
11232
11233    pub fn enable_breakpoint(
11234        &mut self,
11235        _: &crate::actions::EnableBreakpoint,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        if self.breakpoint_store.is_none() {
11240            return;
11241        }
11242
11243        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11244            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11245                continue;
11246            };
11247            self.edit_breakpoint_at_anchor(
11248                anchor,
11249                breakpoint,
11250                BreakpointEditAction::InvertState,
11251                cx,
11252            );
11253        }
11254    }
11255
11256    pub fn disable_breakpoint(
11257        &mut self,
11258        _: &crate::actions::DisableBreakpoint,
11259        window: &mut Window,
11260        cx: &mut Context<Self>,
11261    ) {
11262        if self.breakpoint_store.is_none() {
11263            return;
11264        }
11265
11266        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11267            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11268                continue;
11269            };
11270            self.edit_breakpoint_at_anchor(
11271                anchor,
11272                breakpoint,
11273                BreakpointEditAction::InvertState,
11274                cx,
11275            );
11276        }
11277    }
11278
11279    pub fn toggle_breakpoint(
11280        &mut self,
11281        _: &crate::actions::ToggleBreakpoint,
11282        window: &mut Window,
11283        cx: &mut Context<Self>,
11284    ) {
11285        if self.breakpoint_store.is_none() {
11286            return;
11287        }
11288
11289        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11290            if let Some(breakpoint) = breakpoint {
11291                self.edit_breakpoint_at_anchor(
11292                    anchor,
11293                    breakpoint,
11294                    BreakpointEditAction::Toggle,
11295                    cx,
11296                );
11297            } else {
11298                self.edit_breakpoint_at_anchor(
11299                    anchor,
11300                    Breakpoint::new_standard(),
11301                    BreakpointEditAction::Toggle,
11302                    cx,
11303                );
11304            }
11305        }
11306    }
11307
11308    pub fn edit_breakpoint_at_anchor(
11309        &mut self,
11310        breakpoint_position: Anchor,
11311        breakpoint: Breakpoint,
11312        edit_action: BreakpointEditAction,
11313        cx: &mut Context<Self>,
11314    ) {
11315        let Some(breakpoint_store) = &self.breakpoint_store else {
11316            return;
11317        };
11318
11319        let Some(buffer) = self
11320            .buffer
11321            .read(cx)
11322            .buffer_for_anchor(breakpoint_position, cx)
11323        else {
11324            return;
11325        };
11326
11327        breakpoint_store.update(cx, |breakpoint_store, cx| {
11328            breakpoint_store.toggle_breakpoint(
11329                buffer,
11330                BreakpointWithPosition {
11331                    position: breakpoint_position.text_anchor,
11332                    bp: breakpoint,
11333                },
11334                edit_action,
11335                cx,
11336            );
11337        });
11338
11339        cx.notify();
11340    }
11341
11342    #[cfg(any(test, feature = "test-support"))]
11343    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11344        self.breakpoint_store.clone()
11345    }
11346
11347    pub fn prepare_restore_change(
11348        &self,
11349        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11350        hunk: &MultiBufferDiffHunk,
11351        cx: &mut App,
11352    ) -> Option<()> {
11353        if hunk.is_created_file() {
11354            return None;
11355        }
11356        let buffer = self.buffer.read(cx);
11357        let diff = buffer.diff_for(hunk.buffer_id)?;
11358        let buffer = buffer.buffer(hunk.buffer_id)?;
11359        let buffer = buffer.read(cx);
11360        let original_text = diff
11361            .read(cx)
11362            .base_text()
11363            .as_rope()
11364            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11365        let buffer_snapshot = buffer.snapshot();
11366        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11367        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11368            probe
11369                .0
11370                .start
11371                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11372                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11373        }) {
11374            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11375            Some(())
11376        } else {
11377            None
11378        }
11379    }
11380
11381    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11382        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11383    }
11384
11385    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11386        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11387    }
11388
11389    fn manipulate_lines<M>(
11390        &mut self,
11391        window: &mut Window,
11392        cx: &mut Context<Self>,
11393        mut manipulate: M,
11394    ) where
11395        M: FnMut(&str) -> LineManipulationResult,
11396    {
11397        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11398
11399        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11400        let buffer = self.buffer.read(cx).snapshot(cx);
11401
11402        let mut edits = Vec::new();
11403
11404        let selections = self.selections.all::<Point>(&display_map);
11405        let mut selections = selections.iter().peekable();
11406        let mut contiguous_row_selections = Vec::new();
11407        let mut new_selections = Vec::new();
11408        let mut added_lines = 0;
11409        let mut removed_lines = 0;
11410
11411        while let Some(selection) = selections.next() {
11412            let (start_row, end_row) = consume_contiguous_rows(
11413                &mut contiguous_row_selections,
11414                selection,
11415                &display_map,
11416                &mut selections,
11417            );
11418
11419            let start_point = Point::new(start_row.0, 0);
11420            let end_point = Point::new(
11421                end_row.previous_row().0,
11422                buffer.line_len(end_row.previous_row()),
11423            );
11424            let text = buffer
11425                .text_for_range(start_point..end_point)
11426                .collect::<String>();
11427
11428            let LineManipulationResult {
11429                new_text,
11430                line_count_before,
11431                line_count_after,
11432            } = manipulate(&text);
11433
11434            edits.push((start_point..end_point, new_text));
11435
11436            // Selections must change based on added and removed line count
11437            let start_row =
11438                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11439            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11440            new_selections.push(Selection {
11441                id: selection.id,
11442                start: start_row,
11443                end: end_row,
11444                goal: SelectionGoal::None,
11445                reversed: selection.reversed,
11446            });
11447
11448            if line_count_after > line_count_before {
11449                added_lines += line_count_after - line_count_before;
11450            } else if line_count_before > line_count_after {
11451                removed_lines += line_count_before - line_count_after;
11452            }
11453        }
11454
11455        self.transact(window, cx, |this, window, cx| {
11456            let buffer = this.buffer.update(cx, |buffer, cx| {
11457                buffer.edit(edits, None, cx);
11458                buffer.snapshot(cx)
11459            });
11460
11461            // Recalculate offsets on newly edited buffer
11462            let new_selections = new_selections
11463                .iter()
11464                .map(|s| {
11465                    let start_point = Point::new(s.start.0, 0);
11466                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11467                    Selection {
11468                        id: s.id,
11469                        start: buffer.point_to_offset(start_point),
11470                        end: buffer.point_to_offset(end_point),
11471                        goal: s.goal,
11472                        reversed: s.reversed,
11473                    }
11474                })
11475                .collect();
11476
11477            this.change_selections(Default::default(), window, cx, |s| {
11478                s.select(new_selections);
11479            });
11480
11481            this.request_autoscroll(Autoscroll::fit(), cx);
11482        });
11483    }
11484
11485    fn manipulate_immutable_lines<Fn>(
11486        &mut self,
11487        window: &mut Window,
11488        cx: &mut Context<Self>,
11489        mut callback: Fn,
11490    ) where
11491        Fn: FnMut(&mut Vec<&str>),
11492    {
11493        self.manipulate_lines(window, cx, |text| {
11494            let mut lines: Vec<&str> = text.split('\n').collect();
11495            let line_count_before = lines.len();
11496
11497            callback(&mut lines);
11498
11499            LineManipulationResult {
11500                new_text: lines.join("\n"),
11501                line_count_before,
11502                line_count_after: lines.len(),
11503            }
11504        });
11505    }
11506
11507    fn manipulate_mutable_lines<Fn>(
11508        &mut self,
11509        window: &mut Window,
11510        cx: &mut Context<Self>,
11511        mut callback: Fn,
11512    ) where
11513        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11514    {
11515        self.manipulate_lines(window, cx, |text| {
11516            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11517            let line_count_before = lines.len();
11518
11519            callback(&mut lines);
11520
11521            LineManipulationResult {
11522                new_text: lines.join("\n"),
11523                line_count_before,
11524                line_count_after: lines.len(),
11525            }
11526        });
11527    }
11528
11529    pub fn convert_indentation_to_spaces(
11530        &mut self,
11531        _: &ConvertIndentationToSpaces,
11532        window: &mut Window,
11533        cx: &mut Context<Self>,
11534    ) {
11535        let settings = self.buffer.read(cx).language_settings(cx);
11536        let tab_size = settings.tab_size.get() as usize;
11537
11538        self.manipulate_mutable_lines(window, cx, |lines| {
11539            // Allocates a reasonably sized scratch buffer once for the whole loop
11540            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11541            // Avoids recomputing spaces that could be inserted many times
11542            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11543                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11544                .collect();
11545
11546            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11547                let mut chars = line.as_ref().chars();
11548                let mut col = 0;
11549                let mut changed = false;
11550
11551                for ch in chars.by_ref() {
11552                    match ch {
11553                        ' ' => {
11554                            reindented_line.push(' ');
11555                            col += 1;
11556                        }
11557                        '\t' => {
11558                            // \t are converted to spaces depending on the current column
11559                            let spaces_len = tab_size - (col % tab_size);
11560                            reindented_line.extend(&space_cache[spaces_len - 1]);
11561                            col += spaces_len;
11562                            changed = true;
11563                        }
11564                        _ => {
11565                            // If we dont append before break, the character is consumed
11566                            reindented_line.push(ch);
11567                            break;
11568                        }
11569                    }
11570                }
11571
11572                if !changed {
11573                    reindented_line.clear();
11574                    continue;
11575                }
11576                // Append the rest of the line and replace old reference with new one
11577                reindented_line.extend(chars);
11578                *line = Cow::Owned(reindented_line.clone());
11579                reindented_line.clear();
11580            }
11581        });
11582    }
11583
11584    pub fn convert_indentation_to_tabs(
11585        &mut self,
11586        _: &ConvertIndentationToTabs,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589    ) {
11590        let settings = self.buffer.read(cx).language_settings(cx);
11591        let tab_size = settings.tab_size.get() as usize;
11592
11593        self.manipulate_mutable_lines(window, cx, |lines| {
11594            // Allocates a reasonably sized buffer once for the whole loop
11595            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11596            // Avoids recomputing spaces that could be inserted many times
11597            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11598                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11599                .collect();
11600
11601            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11602                let mut chars = line.chars();
11603                let mut spaces_count = 0;
11604                let mut first_non_indent_char = None;
11605                let mut changed = false;
11606
11607                for ch in chars.by_ref() {
11608                    match ch {
11609                        ' ' => {
11610                            // Keep track of spaces. Append \t when we reach tab_size
11611                            spaces_count += 1;
11612                            changed = true;
11613                            if spaces_count == tab_size {
11614                                reindented_line.push('\t');
11615                                spaces_count = 0;
11616                            }
11617                        }
11618                        '\t' => {
11619                            reindented_line.push('\t');
11620                            spaces_count = 0;
11621                        }
11622                        _ => {
11623                            // Dont append it yet, we might have remaining spaces
11624                            first_non_indent_char = Some(ch);
11625                            break;
11626                        }
11627                    }
11628                }
11629
11630                if !changed {
11631                    reindented_line.clear();
11632                    continue;
11633                }
11634                // Remaining spaces that didn't make a full tab stop
11635                if spaces_count > 0 {
11636                    reindented_line.extend(&space_cache[spaces_count - 1]);
11637                }
11638                // If we consume an extra character that was not indentation, add it back
11639                if let Some(extra_char) = first_non_indent_char {
11640                    reindented_line.push(extra_char);
11641                }
11642                // Append the rest of the line and replace old reference with new one
11643                reindented_line.extend(chars);
11644                *line = Cow::Owned(reindented_line.clone());
11645                reindented_line.clear();
11646            }
11647        });
11648    }
11649
11650    pub fn convert_to_upper_case(
11651        &mut self,
11652        _: &ConvertToUpperCase,
11653        window: &mut Window,
11654        cx: &mut Context<Self>,
11655    ) {
11656        self.manipulate_text(window, cx, |text| text.to_uppercase())
11657    }
11658
11659    pub fn convert_to_lower_case(
11660        &mut self,
11661        _: &ConvertToLowerCase,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        self.manipulate_text(window, cx, |text| text.to_lowercase())
11666    }
11667
11668    pub fn convert_to_title_case(
11669        &mut self,
11670        _: &ConvertToTitleCase,
11671        window: &mut Window,
11672        cx: &mut Context<Self>,
11673    ) {
11674        self.manipulate_text(window, cx, |text| {
11675            text.split('\n')
11676                .map(|line| line.to_case(Case::Title))
11677                .join("\n")
11678        })
11679    }
11680
11681    pub fn convert_to_snake_case(
11682        &mut self,
11683        _: &ConvertToSnakeCase,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11688    }
11689
11690    pub fn convert_to_kebab_case(
11691        &mut self,
11692        _: &ConvertToKebabCase,
11693        window: &mut Window,
11694        cx: &mut Context<Self>,
11695    ) {
11696        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11697    }
11698
11699    pub fn convert_to_upper_camel_case(
11700        &mut self,
11701        _: &ConvertToUpperCamelCase,
11702        window: &mut Window,
11703        cx: &mut Context<Self>,
11704    ) {
11705        self.manipulate_text(window, cx, |text| {
11706            text.split('\n')
11707                .map(|line| line.to_case(Case::UpperCamel))
11708                .join("\n")
11709        })
11710    }
11711
11712    pub fn convert_to_lower_camel_case(
11713        &mut self,
11714        _: &ConvertToLowerCamelCase,
11715        window: &mut Window,
11716        cx: &mut Context<Self>,
11717    ) {
11718        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11719    }
11720
11721    pub fn convert_to_opposite_case(
11722        &mut self,
11723        _: &ConvertToOppositeCase,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.manipulate_text(window, cx, |text| {
11728            text.chars()
11729                .fold(String::with_capacity(text.len()), |mut t, c| {
11730                    if c.is_uppercase() {
11731                        t.extend(c.to_lowercase());
11732                    } else {
11733                        t.extend(c.to_uppercase());
11734                    }
11735                    t
11736                })
11737        })
11738    }
11739
11740    pub fn convert_to_sentence_case(
11741        &mut self,
11742        _: &ConvertToSentenceCase,
11743        window: &mut Window,
11744        cx: &mut Context<Self>,
11745    ) {
11746        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11747    }
11748
11749    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11750        self.manipulate_text(window, cx, |text| {
11751            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11752            if has_upper_case_characters {
11753                text.to_lowercase()
11754            } else {
11755                text.to_uppercase()
11756            }
11757        })
11758    }
11759
11760    pub fn convert_to_rot13(
11761        &mut self,
11762        _: &ConvertToRot13,
11763        window: &mut Window,
11764        cx: &mut Context<Self>,
11765    ) {
11766        self.manipulate_text(window, cx, |text| {
11767            text.chars()
11768                .map(|c| match c {
11769                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11770                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11771                    _ => c,
11772                })
11773                .collect()
11774        })
11775    }
11776
11777    pub fn convert_to_rot47(
11778        &mut self,
11779        _: &ConvertToRot47,
11780        window: &mut Window,
11781        cx: &mut Context<Self>,
11782    ) {
11783        self.manipulate_text(window, cx, |text| {
11784            text.chars()
11785                .map(|c| {
11786                    let code_point = c as u32;
11787                    if code_point >= 33 && code_point <= 126 {
11788                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11789                    }
11790                    c
11791                })
11792                .collect()
11793        })
11794    }
11795
11796    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11797    where
11798        Fn: FnMut(&str) -> String,
11799    {
11800        let buffer = self.buffer.read(cx).snapshot(cx);
11801
11802        let mut new_selections = Vec::new();
11803        let mut edits = Vec::new();
11804        let mut selection_adjustment = 0isize;
11805
11806        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11807            let selection_is_empty = selection.is_empty();
11808
11809            let (start, end) = if selection_is_empty {
11810                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11811                (word_range.start, word_range.end)
11812            } else {
11813                (
11814                    buffer.point_to_offset(selection.start),
11815                    buffer.point_to_offset(selection.end),
11816                )
11817            };
11818
11819            let text = buffer.text_for_range(start..end).collect::<String>();
11820            let old_length = text.len() as isize;
11821            let text = callback(&text);
11822
11823            new_selections.push(Selection {
11824                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11825                end: MultiBufferOffset(
11826                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11827                ),
11828                goal: SelectionGoal::None,
11829                id: selection.id,
11830                reversed: selection.reversed,
11831            });
11832
11833            selection_adjustment += old_length - text.len() as isize;
11834
11835            edits.push((start..end, text));
11836        }
11837
11838        self.transact(window, cx, |this, window, cx| {
11839            this.buffer.update(cx, |buffer, cx| {
11840                buffer.edit(edits, None, cx);
11841            });
11842
11843            this.change_selections(Default::default(), window, cx, |s| {
11844                s.select(new_selections);
11845            });
11846
11847            this.request_autoscroll(Autoscroll::fit(), cx);
11848        });
11849    }
11850
11851    pub fn move_selection_on_drop(
11852        &mut self,
11853        selection: &Selection<Anchor>,
11854        target: DisplayPoint,
11855        is_cut: bool,
11856        window: &mut Window,
11857        cx: &mut Context<Self>,
11858    ) {
11859        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11860        let buffer = display_map.buffer_snapshot();
11861        let mut edits = Vec::new();
11862        let insert_point = display_map
11863            .clip_point(target, Bias::Left)
11864            .to_point(&display_map);
11865        let text = buffer
11866            .text_for_range(selection.start..selection.end)
11867            .collect::<String>();
11868        if is_cut {
11869            edits.push(((selection.start..selection.end), String::new()));
11870        }
11871        let insert_anchor = buffer.anchor_before(insert_point);
11872        edits.push(((insert_anchor..insert_anchor), text));
11873        let last_edit_start = insert_anchor.bias_left(buffer);
11874        let last_edit_end = insert_anchor.bias_right(buffer);
11875        self.transact(window, cx, |this, window, cx| {
11876            this.buffer.update(cx, |buffer, cx| {
11877                buffer.edit(edits, None, cx);
11878            });
11879            this.change_selections(Default::default(), window, cx, |s| {
11880                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11881            });
11882        });
11883    }
11884
11885    pub fn clear_selection_drag_state(&mut self) {
11886        self.selection_drag_state = SelectionDragState::None;
11887    }
11888
11889    pub fn duplicate(
11890        &mut self,
11891        upwards: bool,
11892        whole_lines: bool,
11893        window: &mut Window,
11894        cx: &mut Context<Self>,
11895    ) {
11896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11897
11898        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11899        let buffer = display_map.buffer_snapshot();
11900        let selections = self.selections.all::<Point>(&display_map);
11901
11902        let mut edits = Vec::new();
11903        let mut selections_iter = selections.iter().peekable();
11904        while let Some(selection) = selections_iter.next() {
11905            let mut rows = selection.spanned_rows(false, &display_map);
11906            // duplicate line-wise
11907            if whole_lines || selection.start == selection.end {
11908                // Avoid duplicating the same lines twice.
11909                while let Some(next_selection) = selections_iter.peek() {
11910                    let next_rows = next_selection.spanned_rows(false, &display_map);
11911                    if next_rows.start < rows.end {
11912                        rows.end = next_rows.end;
11913                        selections_iter.next().unwrap();
11914                    } else {
11915                        break;
11916                    }
11917                }
11918
11919                // Copy the text from the selected row region and splice it either at the start
11920                // or end of the region.
11921                let start = Point::new(rows.start.0, 0);
11922                let end = Point::new(
11923                    rows.end.previous_row().0,
11924                    buffer.line_len(rows.end.previous_row()),
11925                );
11926
11927                let mut text = buffer.text_for_range(start..end).collect::<String>();
11928
11929                let insert_location = if upwards {
11930                    // When duplicating upward, we need to insert before the current line.
11931                    // If we're on the last line and it doesn't end with a newline,
11932                    // we need to add a newline before the duplicated content.
11933                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11934                        && buffer.max_point().column > 0
11935                        && !text.ends_with('\n');
11936
11937                    if needs_leading_newline {
11938                        text.insert(0, '\n');
11939                        end
11940                    } else {
11941                        text.push('\n');
11942                        Point::new(rows.start.0, 0)
11943                    }
11944                } else {
11945                    text.push('\n');
11946                    start
11947                };
11948                edits.push((insert_location..insert_location, text));
11949            } else {
11950                // duplicate character-wise
11951                let start = selection.start;
11952                let end = selection.end;
11953                let text = buffer.text_for_range(start..end).collect::<String>();
11954                edits.push((selection.end..selection.end, text));
11955            }
11956        }
11957
11958        self.transact(window, cx, |this, window, cx| {
11959            this.buffer.update(cx, |buffer, cx| {
11960                buffer.edit(edits, None, cx);
11961            });
11962
11963            // When duplicating upward with whole lines, move the cursor to the duplicated line
11964            if upwards && whole_lines {
11965                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11966
11967                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11968                    let mut new_ranges = Vec::new();
11969                    let selections = s.all::<Point>(&display_map);
11970                    let mut selections_iter = selections.iter().peekable();
11971
11972                    while let Some(first_selection) = selections_iter.next() {
11973                        // Group contiguous selections together to find the total row span
11974                        let mut group_selections = vec![first_selection];
11975                        let mut rows = first_selection.spanned_rows(false, &display_map);
11976
11977                        while let Some(next_selection) = selections_iter.peek() {
11978                            let next_rows = next_selection.spanned_rows(false, &display_map);
11979                            if next_rows.start < rows.end {
11980                                rows.end = next_rows.end;
11981                                group_selections.push(selections_iter.next().unwrap());
11982                            } else {
11983                                break;
11984                            }
11985                        }
11986
11987                        let row_count = rows.end.0 - rows.start.0;
11988
11989                        // Move all selections in this group up by the total number of duplicated rows
11990                        for selection in group_selections {
11991                            let new_start = Point::new(
11992                                selection.start.row.saturating_sub(row_count),
11993                                selection.start.column,
11994                            );
11995
11996                            let new_end = Point::new(
11997                                selection.end.row.saturating_sub(row_count),
11998                                selection.end.column,
11999                            );
12000
12001                            new_ranges.push(new_start..new_end);
12002                        }
12003                    }
12004
12005                    s.select_ranges(new_ranges);
12006                });
12007            }
12008
12009            this.request_autoscroll(Autoscroll::fit(), cx);
12010        });
12011    }
12012
12013    pub fn duplicate_line_up(
12014        &mut self,
12015        _: &DuplicateLineUp,
12016        window: &mut Window,
12017        cx: &mut Context<Self>,
12018    ) {
12019        self.duplicate(true, true, window, cx);
12020    }
12021
12022    pub fn duplicate_line_down(
12023        &mut self,
12024        _: &DuplicateLineDown,
12025        window: &mut Window,
12026        cx: &mut Context<Self>,
12027    ) {
12028        self.duplicate(false, true, window, cx);
12029    }
12030
12031    pub fn duplicate_selection(
12032        &mut self,
12033        _: &DuplicateSelection,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        self.duplicate(false, false, window, cx);
12038    }
12039
12040    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12042        if self.mode.is_single_line() {
12043            cx.propagate();
12044            return;
12045        }
12046
12047        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12048        let buffer = self.buffer.read(cx).snapshot(cx);
12049
12050        let mut edits = Vec::new();
12051        let mut unfold_ranges = Vec::new();
12052        let mut refold_creases = Vec::new();
12053
12054        let selections = self.selections.all::<Point>(&display_map);
12055        let mut selections = selections.iter().peekable();
12056        let mut contiguous_row_selections = Vec::new();
12057        let mut new_selections = Vec::new();
12058
12059        while let Some(selection) = selections.next() {
12060            // Find all the selections that span a contiguous row range
12061            let (start_row, end_row) = consume_contiguous_rows(
12062                &mut contiguous_row_selections,
12063                selection,
12064                &display_map,
12065                &mut selections,
12066            );
12067
12068            // Move the text spanned by the row range to be before the line preceding the row range
12069            if start_row.0 > 0 {
12070                let range_to_move = Point::new(
12071                    start_row.previous_row().0,
12072                    buffer.line_len(start_row.previous_row()),
12073                )
12074                    ..Point::new(
12075                        end_row.previous_row().0,
12076                        buffer.line_len(end_row.previous_row()),
12077                    );
12078                let insertion_point = display_map
12079                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12080                    .0;
12081
12082                // Don't move lines across excerpts
12083                if buffer
12084                    .excerpt_containing(insertion_point..range_to_move.end)
12085                    .is_some()
12086                {
12087                    let text = buffer
12088                        .text_for_range(range_to_move.clone())
12089                        .flat_map(|s| s.chars())
12090                        .skip(1)
12091                        .chain(['\n'])
12092                        .collect::<String>();
12093
12094                    edits.push((
12095                        buffer.anchor_after(range_to_move.start)
12096                            ..buffer.anchor_before(range_to_move.end),
12097                        String::new(),
12098                    ));
12099                    let insertion_anchor = buffer.anchor_after(insertion_point);
12100                    edits.push((insertion_anchor..insertion_anchor, text));
12101
12102                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12103
12104                    // Move selections up
12105                    new_selections.extend(contiguous_row_selections.drain(..).map(
12106                        |mut selection| {
12107                            selection.start.row -= row_delta;
12108                            selection.end.row -= row_delta;
12109                            selection
12110                        },
12111                    ));
12112
12113                    // Move folds up
12114                    unfold_ranges.push(range_to_move.clone());
12115                    for fold in display_map.folds_in_range(
12116                        buffer.anchor_before(range_to_move.start)
12117                            ..buffer.anchor_after(range_to_move.end),
12118                    ) {
12119                        let mut start = fold.range.start.to_point(&buffer);
12120                        let mut end = fold.range.end.to_point(&buffer);
12121                        start.row -= row_delta;
12122                        end.row -= row_delta;
12123                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12124                    }
12125                }
12126            }
12127
12128            // If we didn't move line(s), preserve the existing selections
12129            new_selections.append(&mut contiguous_row_selections);
12130        }
12131
12132        self.transact(window, cx, |this, window, cx| {
12133            this.unfold_ranges(&unfold_ranges, true, true, cx);
12134            this.buffer.update(cx, |buffer, cx| {
12135                for (range, text) in edits {
12136                    buffer.edit([(range, text)], None, cx);
12137                }
12138            });
12139            this.fold_creases(refold_creases, true, window, cx);
12140            this.change_selections(Default::default(), window, cx, |s| {
12141                s.select(new_selections);
12142            })
12143        });
12144    }
12145
12146    pub fn move_line_down(
12147        &mut self,
12148        _: &MoveLineDown,
12149        window: &mut Window,
12150        cx: &mut Context<Self>,
12151    ) {
12152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12153        if self.mode.is_single_line() {
12154            cx.propagate();
12155            return;
12156        }
12157
12158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12159        let buffer = self.buffer.read(cx).snapshot(cx);
12160
12161        let mut edits = Vec::new();
12162        let mut unfold_ranges = Vec::new();
12163        let mut refold_creases = Vec::new();
12164
12165        let selections = self.selections.all::<Point>(&display_map);
12166        let mut selections = selections.iter().peekable();
12167        let mut contiguous_row_selections = Vec::new();
12168        let mut new_selections = Vec::new();
12169
12170        while let Some(selection) = selections.next() {
12171            // Find all the selections that span a contiguous row range
12172            let (start_row, end_row) = consume_contiguous_rows(
12173                &mut contiguous_row_selections,
12174                selection,
12175                &display_map,
12176                &mut selections,
12177            );
12178
12179            // Move the text spanned by the row range to be after the last line of the row range
12180            if end_row.0 <= buffer.max_point().row {
12181                let range_to_move =
12182                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12183                let insertion_point = display_map
12184                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12185                    .0;
12186
12187                // Don't move lines across excerpt boundaries
12188                if buffer
12189                    .excerpt_containing(range_to_move.start..insertion_point)
12190                    .is_some()
12191                {
12192                    let mut text = String::from("\n");
12193                    text.extend(buffer.text_for_range(range_to_move.clone()));
12194                    text.pop(); // Drop trailing newline
12195                    edits.push((
12196                        buffer.anchor_after(range_to_move.start)
12197                            ..buffer.anchor_before(range_to_move.end),
12198                        String::new(),
12199                    ));
12200                    let insertion_anchor = buffer.anchor_after(insertion_point);
12201                    edits.push((insertion_anchor..insertion_anchor, text));
12202
12203                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12204
12205                    // Move selections down
12206                    new_selections.extend(contiguous_row_selections.drain(..).map(
12207                        |mut selection| {
12208                            selection.start.row += row_delta;
12209                            selection.end.row += row_delta;
12210                            selection
12211                        },
12212                    ));
12213
12214                    // Move folds down
12215                    unfold_ranges.push(range_to_move.clone());
12216                    for fold in display_map.folds_in_range(
12217                        buffer.anchor_before(range_to_move.start)
12218                            ..buffer.anchor_after(range_to_move.end),
12219                    ) {
12220                        let mut start = fold.range.start.to_point(&buffer);
12221                        let mut end = fold.range.end.to_point(&buffer);
12222                        start.row += row_delta;
12223                        end.row += row_delta;
12224                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12225                    }
12226                }
12227            }
12228
12229            // If we didn't move line(s), preserve the existing selections
12230            new_selections.append(&mut contiguous_row_selections);
12231        }
12232
12233        self.transact(window, cx, |this, window, cx| {
12234            this.unfold_ranges(&unfold_ranges, true, true, cx);
12235            this.buffer.update(cx, |buffer, cx| {
12236                for (range, text) in edits {
12237                    buffer.edit([(range, text)], None, cx);
12238                }
12239            });
12240            this.fold_creases(refold_creases, true, window, cx);
12241            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12242        });
12243    }
12244
12245    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12246        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12247        let text_layout_details = &self.text_layout_details(window);
12248        self.transact(window, cx, |this, window, cx| {
12249            let edits = this.change_selections(Default::default(), window, cx, |s| {
12250                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12251                s.move_with(|display_map, selection| {
12252                    if !selection.is_empty() {
12253                        return;
12254                    }
12255
12256                    let mut head = selection.head();
12257                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12258                    if head.column() == display_map.line_len(head.row()) {
12259                        transpose_offset = display_map
12260                            .buffer_snapshot()
12261                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12262                    }
12263
12264                    if transpose_offset == MultiBufferOffset(0) {
12265                        return;
12266                    }
12267
12268                    *head.column_mut() += 1;
12269                    head = display_map.clip_point(head, Bias::Right);
12270                    let goal = SelectionGoal::HorizontalPosition(
12271                        display_map
12272                            .x_for_display_point(head, text_layout_details)
12273                            .into(),
12274                    );
12275                    selection.collapse_to(head, goal);
12276
12277                    let transpose_start = display_map
12278                        .buffer_snapshot()
12279                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12280                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12281                        let transpose_end = display_map
12282                            .buffer_snapshot()
12283                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12284                        if let Some(ch) = display_map
12285                            .buffer_snapshot()
12286                            .chars_at(transpose_start)
12287                            .next()
12288                        {
12289                            edits.push((transpose_start..transpose_offset, String::new()));
12290                            edits.push((transpose_end..transpose_end, ch.to_string()));
12291                        }
12292                    }
12293                });
12294                edits
12295            });
12296            this.buffer
12297                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12298            let selections = this
12299                .selections
12300                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12301            this.change_selections(Default::default(), window, cx, |s| {
12302                s.select(selections);
12303            });
12304        });
12305    }
12306
12307    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12309        if self.mode.is_single_line() {
12310            cx.propagate();
12311            return;
12312        }
12313
12314        self.rewrap_impl(RewrapOptions::default(), cx)
12315    }
12316
12317    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12318        let buffer = self.buffer.read(cx).snapshot(cx);
12319        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12320
12321        #[derive(Clone, Debug, PartialEq)]
12322        enum CommentFormat {
12323            /// single line comment, with prefix for line
12324            Line(String),
12325            /// single line within a block comment, with prefix for line
12326            BlockLine(String),
12327            /// a single line of a block comment that includes the initial delimiter
12328            BlockCommentWithStart(BlockCommentConfig),
12329            /// a single line of a block comment that includes the ending delimiter
12330            BlockCommentWithEnd(BlockCommentConfig),
12331        }
12332
12333        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12334        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12335            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12336                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12337                .peekable();
12338
12339            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12340                row
12341            } else {
12342                return Vec::new();
12343            };
12344
12345            let language_settings = buffer.language_settings_at(selection.head(), cx);
12346            let language_scope = buffer.language_scope_at(selection.head());
12347
12348            let indent_and_prefix_for_row =
12349                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12350                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12351                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12352                        &language_scope
12353                    {
12354                        let indent_end = Point::new(row, indent.len);
12355                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12356                        let line_text_after_indent = buffer
12357                            .text_for_range(indent_end..line_end)
12358                            .collect::<String>();
12359
12360                        let is_within_comment_override = buffer
12361                            .language_scope_at(indent_end)
12362                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12363                        let comment_delimiters = if is_within_comment_override {
12364                            // we are within a comment syntax node, but we don't
12365                            // yet know what kind of comment: block, doc or line
12366                            match (
12367                                language_scope.documentation_comment(),
12368                                language_scope.block_comment(),
12369                            ) {
12370                                (Some(config), _) | (_, Some(config))
12371                                    if buffer.contains_str_at(indent_end, &config.start) =>
12372                                {
12373                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12374                                }
12375                                (Some(config), _) | (_, Some(config))
12376                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12377                                {
12378                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12379                                }
12380                                (Some(config), _) | (_, Some(config))
12381                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12382                                {
12383                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12384                                }
12385                                (_, _) => language_scope
12386                                    .line_comment_prefixes()
12387                                    .iter()
12388                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12389                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12390                            }
12391                        } else {
12392                            // we not in an overridden comment node, but we may
12393                            // be within a non-overridden line comment node
12394                            language_scope
12395                                .line_comment_prefixes()
12396                                .iter()
12397                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12398                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12399                        };
12400
12401                        let rewrap_prefix = language_scope
12402                            .rewrap_prefixes()
12403                            .iter()
12404                            .find_map(|prefix_regex| {
12405                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12406                                    if mat.start() == 0 {
12407                                        Some(mat.as_str().to_string())
12408                                    } else {
12409                                        None
12410                                    }
12411                                })
12412                            })
12413                            .flatten();
12414                        (comment_delimiters, rewrap_prefix)
12415                    } else {
12416                        (None, None)
12417                    };
12418                    (indent, comment_prefix, rewrap_prefix)
12419                };
12420
12421            let mut ranges = Vec::new();
12422            let from_empty_selection = selection.is_empty();
12423
12424            let mut current_range_start = first_row;
12425            let mut prev_row = first_row;
12426            let (
12427                mut current_range_indent,
12428                mut current_range_comment_delimiters,
12429                mut current_range_rewrap_prefix,
12430            ) = indent_and_prefix_for_row(first_row);
12431
12432            for row in non_blank_rows_iter.skip(1) {
12433                let has_paragraph_break = row > prev_row + 1;
12434
12435                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12436                    indent_and_prefix_for_row(row);
12437
12438                let has_indent_change = row_indent != current_range_indent;
12439                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12440
12441                let has_boundary_change = has_comment_change
12442                    || row_rewrap_prefix.is_some()
12443                    || (has_indent_change && current_range_comment_delimiters.is_some());
12444
12445                if has_paragraph_break || has_boundary_change {
12446                    ranges.push((
12447                        language_settings.clone(),
12448                        Point::new(current_range_start, 0)
12449                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12450                        current_range_indent,
12451                        current_range_comment_delimiters.clone(),
12452                        current_range_rewrap_prefix.clone(),
12453                        from_empty_selection,
12454                    ));
12455                    current_range_start = row;
12456                    current_range_indent = row_indent;
12457                    current_range_comment_delimiters = row_comment_delimiters;
12458                    current_range_rewrap_prefix = row_rewrap_prefix;
12459                }
12460                prev_row = row;
12461            }
12462
12463            ranges.push((
12464                language_settings.clone(),
12465                Point::new(current_range_start, 0)
12466                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12467                current_range_indent,
12468                current_range_comment_delimiters,
12469                current_range_rewrap_prefix,
12470                from_empty_selection,
12471            ));
12472
12473            ranges
12474        });
12475
12476        let mut edits = Vec::new();
12477        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12478
12479        for (
12480            language_settings,
12481            wrap_range,
12482            mut indent_size,
12483            comment_prefix,
12484            rewrap_prefix,
12485            from_empty_selection,
12486        ) in wrap_ranges
12487        {
12488            let mut start_row = wrap_range.start.row;
12489            let mut end_row = wrap_range.end.row;
12490
12491            // Skip selections that overlap with a range that has already been rewrapped.
12492            let selection_range = start_row..end_row;
12493            if rewrapped_row_ranges
12494                .iter()
12495                .any(|range| range.overlaps(&selection_range))
12496            {
12497                continue;
12498            }
12499
12500            let tab_size = language_settings.tab_size;
12501
12502            let (line_prefix, inside_comment) = match &comment_prefix {
12503                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12504                    (Some(prefix.as_str()), true)
12505                }
12506                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12507                    (Some(prefix.as_ref()), true)
12508                }
12509                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12510                    start: _,
12511                    end: _,
12512                    prefix,
12513                    tab_size,
12514                })) => {
12515                    indent_size.len += tab_size;
12516                    (Some(prefix.as_ref()), true)
12517                }
12518                None => (None, false),
12519            };
12520            let indent_prefix = indent_size.chars().collect::<String>();
12521            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12522
12523            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12524                RewrapBehavior::InComments => inside_comment,
12525                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12526                RewrapBehavior::Anywhere => true,
12527            };
12528
12529            let should_rewrap = options.override_language_settings
12530                || allow_rewrap_based_on_language
12531                || self.hard_wrap.is_some();
12532            if !should_rewrap {
12533                continue;
12534            }
12535
12536            if from_empty_selection {
12537                'expand_upwards: while start_row > 0 {
12538                    let prev_row = start_row - 1;
12539                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12540                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12541                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12542                    {
12543                        start_row = prev_row;
12544                    } else {
12545                        break 'expand_upwards;
12546                    }
12547                }
12548
12549                'expand_downwards: while end_row < buffer.max_point().row {
12550                    let next_row = end_row + 1;
12551                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12552                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12553                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12554                    {
12555                        end_row = next_row;
12556                    } else {
12557                        break 'expand_downwards;
12558                    }
12559                }
12560            }
12561
12562            let start = Point::new(start_row, 0);
12563            let start_offset = ToOffset::to_offset(&start, &buffer);
12564            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12565            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12566            let mut first_line_delimiter = None;
12567            let mut last_line_delimiter = None;
12568            let Some(lines_without_prefixes) = selection_text
12569                .lines()
12570                .enumerate()
12571                .map(|(ix, line)| {
12572                    let line_trimmed = line.trim_start();
12573                    if rewrap_prefix.is_some() && ix > 0 {
12574                        Ok(line_trimmed)
12575                    } else if let Some(
12576                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12577                            start,
12578                            prefix,
12579                            end,
12580                            tab_size,
12581                        })
12582                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12583                            start,
12584                            prefix,
12585                            end,
12586                            tab_size,
12587                        }),
12588                    ) = &comment_prefix
12589                    {
12590                        let line_trimmed = line_trimmed
12591                            .strip_prefix(start.as_ref())
12592                            .map(|s| {
12593                                let mut indent_size = indent_size;
12594                                indent_size.len -= tab_size;
12595                                let indent_prefix: String = indent_size.chars().collect();
12596                                first_line_delimiter = Some((indent_prefix, start));
12597                                s.trim_start()
12598                            })
12599                            .unwrap_or(line_trimmed);
12600                        let line_trimmed = line_trimmed
12601                            .strip_suffix(end.as_ref())
12602                            .map(|s| {
12603                                last_line_delimiter = Some(end);
12604                                s.trim_end()
12605                            })
12606                            .unwrap_or(line_trimmed);
12607                        let line_trimmed = line_trimmed
12608                            .strip_prefix(prefix.as_ref())
12609                            .unwrap_or(line_trimmed);
12610                        Ok(line_trimmed)
12611                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12612                        line_trimmed.strip_prefix(prefix).with_context(|| {
12613                            format!("line did not start with prefix {prefix:?}: {line:?}")
12614                        })
12615                    } else {
12616                        line_trimmed
12617                            .strip_prefix(&line_prefix.trim_start())
12618                            .with_context(|| {
12619                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12620                            })
12621                    }
12622                })
12623                .collect::<Result<Vec<_>, _>>()
12624                .log_err()
12625            else {
12626                continue;
12627            };
12628
12629            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12630                buffer
12631                    .language_settings_at(Point::new(start_row, 0), cx)
12632                    .preferred_line_length as usize
12633            });
12634
12635            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12636                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12637            } else {
12638                line_prefix.clone()
12639            };
12640
12641            let wrapped_text = {
12642                let mut wrapped_text = wrap_with_prefix(
12643                    line_prefix,
12644                    subsequent_lines_prefix,
12645                    lines_without_prefixes.join("\n"),
12646                    wrap_column,
12647                    tab_size,
12648                    options.preserve_existing_whitespace,
12649                );
12650
12651                if let Some((indent, delimiter)) = first_line_delimiter {
12652                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12653                }
12654                if let Some(last_line) = last_line_delimiter {
12655                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12656                }
12657
12658                wrapped_text
12659            };
12660
12661            // TODO: should always use char-based diff while still supporting cursor behavior that
12662            // matches vim.
12663            let mut diff_options = DiffOptions::default();
12664            if options.override_language_settings {
12665                diff_options.max_word_diff_len = 0;
12666                diff_options.max_word_diff_line_count = 0;
12667            } else {
12668                diff_options.max_word_diff_len = usize::MAX;
12669                diff_options.max_word_diff_line_count = usize::MAX;
12670            }
12671
12672            for (old_range, new_text) in
12673                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12674            {
12675                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12676                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12677                edits.push((edit_start..edit_end, new_text));
12678            }
12679
12680            rewrapped_row_ranges.push(start_row..=end_row);
12681        }
12682
12683        self.buffer
12684            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12685    }
12686
12687    pub fn cut_common(
12688        &mut self,
12689        cut_no_selection_line: bool,
12690        window: &mut Window,
12691        cx: &mut Context<Self>,
12692    ) -> ClipboardItem {
12693        let mut text = String::new();
12694        let buffer = self.buffer.read(cx).snapshot(cx);
12695        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12696        let mut clipboard_selections = Vec::with_capacity(selections.len());
12697        {
12698            let max_point = buffer.max_point();
12699            let mut is_first = true;
12700            let mut prev_selection_was_entire_line = false;
12701            for selection in &mut selections {
12702                let is_entire_line =
12703                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12704                if is_entire_line {
12705                    selection.start = Point::new(selection.start.row, 0);
12706                    if !selection.is_empty() && selection.end.column == 0 {
12707                        selection.end = cmp::min(max_point, selection.end);
12708                    } else {
12709                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12710                    }
12711                    selection.goal = SelectionGoal::None;
12712                }
12713                if is_first {
12714                    is_first = false;
12715                } else if !prev_selection_was_entire_line {
12716                    text += "\n";
12717                }
12718                prev_selection_was_entire_line = is_entire_line;
12719                let mut len = 0;
12720                for chunk in buffer.text_for_range(selection.start..selection.end) {
12721                    text.push_str(chunk);
12722                    len += chunk.len();
12723                }
12724                clipboard_selections.push(ClipboardSelection {
12725                    len,
12726                    is_entire_line,
12727                    first_line_indent: buffer
12728                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12729                        .len,
12730                });
12731            }
12732        }
12733
12734        self.transact(window, cx, |this, window, cx| {
12735            this.change_selections(Default::default(), window, cx, |s| {
12736                s.select(selections);
12737            });
12738            this.insert("", window, cx);
12739        });
12740        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12741    }
12742
12743    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12745        let item = self.cut_common(true, window, cx);
12746        cx.write_to_clipboard(item);
12747    }
12748
12749    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12751        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12752            s.move_with(|snapshot, sel| {
12753                if sel.is_empty() {
12754                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12755                }
12756                if sel.is_empty() {
12757                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12758                }
12759            });
12760        });
12761        let item = self.cut_common(false, window, cx);
12762        cx.set_global(KillRing(item))
12763    }
12764
12765    pub fn kill_ring_yank(
12766        &mut self,
12767        _: &KillRingYank,
12768        window: &mut Window,
12769        cx: &mut Context<Self>,
12770    ) {
12771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12772        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12773            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12774                (kill_ring.text().to_string(), kill_ring.metadata_json())
12775            } else {
12776                return;
12777            }
12778        } else {
12779            return;
12780        };
12781        self.do_paste(&text, metadata, false, window, cx);
12782    }
12783
12784    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12785        self.do_copy(true, cx);
12786    }
12787
12788    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12789        self.do_copy(false, cx);
12790    }
12791
12792    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12793        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12794        let buffer = self.buffer.read(cx).read(cx);
12795        let mut text = String::new();
12796
12797        let mut clipboard_selections = Vec::with_capacity(selections.len());
12798        {
12799            let max_point = buffer.max_point();
12800            let mut is_first = true;
12801            let mut prev_selection_was_entire_line = false;
12802            for selection in &selections {
12803                let mut start = selection.start;
12804                let mut end = selection.end;
12805                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12806                let mut add_trailing_newline = false;
12807                if is_entire_line {
12808                    start = Point::new(start.row, 0);
12809                    let next_line_start = Point::new(end.row + 1, 0);
12810                    if next_line_start <= max_point {
12811                        end = next_line_start;
12812                    } else {
12813                        // We're on the last line without a trailing newline.
12814                        // Copy to the end of the line and add a newline afterwards.
12815                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12816                        add_trailing_newline = true;
12817                    }
12818                }
12819
12820                let mut trimmed_selections = Vec::new();
12821                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12822                    let row = MultiBufferRow(start.row);
12823                    let first_indent = buffer.indent_size_for_line(row);
12824                    if first_indent.len == 0 || start.column > first_indent.len {
12825                        trimmed_selections.push(start..end);
12826                    } else {
12827                        trimmed_selections.push(
12828                            Point::new(row.0, first_indent.len)
12829                                ..Point::new(row.0, buffer.line_len(row)),
12830                        );
12831                        for row in start.row + 1..=end.row {
12832                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12833                            if row == end.row {
12834                                line_len = end.column;
12835                            }
12836                            if line_len == 0 {
12837                                trimmed_selections
12838                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12839                                continue;
12840                            }
12841                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12842                            if row_indent_size.len >= first_indent.len {
12843                                trimmed_selections.push(
12844                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12845                                );
12846                            } else {
12847                                trimmed_selections.clear();
12848                                trimmed_selections.push(start..end);
12849                                break;
12850                            }
12851                        }
12852                    }
12853                } else {
12854                    trimmed_selections.push(start..end);
12855                }
12856
12857                for trimmed_range in trimmed_selections {
12858                    if is_first {
12859                        is_first = false;
12860                    } else if !prev_selection_was_entire_line {
12861                        text += "\n";
12862                    }
12863                    prev_selection_was_entire_line = is_entire_line;
12864                    let mut len = 0;
12865                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12866                        text.push_str(chunk);
12867                        len += chunk.len();
12868                    }
12869                    if add_trailing_newline {
12870                        text.push('\n');
12871                        len += 1;
12872                    }
12873                    clipboard_selections.push(ClipboardSelection {
12874                        len,
12875                        is_entire_line,
12876                        first_line_indent: buffer
12877                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12878                            .len,
12879                    });
12880                }
12881            }
12882        }
12883
12884        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12885            text,
12886            clipboard_selections,
12887        ));
12888    }
12889
12890    pub fn do_paste(
12891        &mut self,
12892        text: &String,
12893        clipboard_selections: Option<Vec<ClipboardSelection>>,
12894        handle_entire_lines: bool,
12895        window: &mut Window,
12896        cx: &mut Context<Self>,
12897    ) {
12898        if self.read_only(cx) {
12899            return;
12900        }
12901
12902        let clipboard_text = Cow::Borrowed(text.as_str());
12903
12904        self.transact(window, cx, |this, window, cx| {
12905            let had_active_edit_prediction = this.has_active_edit_prediction();
12906            let display_map = this.display_snapshot(cx);
12907            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12908            let cursor_offset = this
12909                .selections
12910                .last::<MultiBufferOffset>(&display_map)
12911                .head();
12912
12913            if let Some(mut clipboard_selections) = clipboard_selections {
12914                let all_selections_were_entire_line =
12915                    clipboard_selections.iter().all(|s| s.is_entire_line);
12916                let first_selection_indent_column =
12917                    clipboard_selections.first().map(|s| s.first_line_indent);
12918                if clipboard_selections.len() != old_selections.len() {
12919                    clipboard_selections.drain(..);
12920                }
12921                let mut auto_indent_on_paste = true;
12922
12923                this.buffer.update(cx, |buffer, cx| {
12924                    let snapshot = buffer.read(cx);
12925                    auto_indent_on_paste = snapshot
12926                        .language_settings_at(cursor_offset, cx)
12927                        .auto_indent_on_paste;
12928
12929                    let mut start_offset = 0;
12930                    let mut edits = Vec::new();
12931                    let mut original_indent_columns = Vec::new();
12932                    for (ix, selection) in old_selections.iter().enumerate() {
12933                        let to_insert;
12934                        let entire_line;
12935                        let original_indent_column;
12936                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12937                            let end_offset = start_offset + clipboard_selection.len;
12938                            to_insert = &clipboard_text[start_offset..end_offset];
12939                            entire_line = clipboard_selection.is_entire_line;
12940                            start_offset = if entire_line {
12941                                end_offset
12942                            } else {
12943                                end_offset + 1
12944                            };
12945                            original_indent_column = Some(clipboard_selection.first_line_indent);
12946                        } else {
12947                            to_insert = &*clipboard_text;
12948                            entire_line = all_selections_were_entire_line;
12949                            original_indent_column = first_selection_indent_column
12950                        }
12951
12952                        let (range, to_insert) =
12953                            if selection.is_empty() && handle_entire_lines && entire_line {
12954                                // If the corresponding selection was empty when this slice of the
12955                                // clipboard text was written, then the entire line containing the
12956                                // selection was copied. If this selection is also currently empty,
12957                                // then paste the line before the current line of the buffer.
12958                                let column = selection.start.to_point(&snapshot).column as usize;
12959                                let line_start = selection.start - column;
12960                                (line_start..line_start, Cow::Borrowed(to_insert))
12961                            } else {
12962                                let language = snapshot.language_at(selection.head());
12963                                let range = selection.range();
12964                                if let Some(language) = language
12965                                    && language.name() == "Markdown".into()
12966                                {
12967                                    edit_for_markdown_paste(
12968                                        &snapshot,
12969                                        range,
12970                                        to_insert,
12971                                        url::Url::parse(to_insert).ok(),
12972                                    )
12973                                } else {
12974                                    (range, Cow::Borrowed(to_insert))
12975                                }
12976                            };
12977
12978                        edits.push((range, to_insert));
12979                        original_indent_columns.push(original_indent_column);
12980                    }
12981                    drop(snapshot);
12982
12983                    buffer.edit(
12984                        edits,
12985                        if auto_indent_on_paste {
12986                            Some(AutoindentMode::Block {
12987                                original_indent_columns,
12988                            })
12989                        } else {
12990                            None
12991                        },
12992                        cx,
12993                    );
12994                });
12995
12996                let selections = this
12997                    .selections
12998                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12999                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13000            } else {
13001                let url = url::Url::parse(&clipboard_text).ok();
13002
13003                let auto_indent_mode = if !clipboard_text.is_empty() {
13004                    Some(AutoindentMode::Block {
13005                        original_indent_columns: Vec::new(),
13006                    })
13007                } else {
13008                    None
13009                };
13010
13011                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13012                    let snapshot = buffer.snapshot(cx);
13013
13014                    let anchors = old_selections
13015                        .iter()
13016                        .map(|s| {
13017                            let anchor = snapshot.anchor_after(s.head());
13018                            s.map(|_| anchor)
13019                        })
13020                        .collect::<Vec<_>>();
13021
13022                    let mut edits = Vec::new();
13023
13024                    for selection in old_selections.iter() {
13025                        let language = snapshot.language_at(selection.head());
13026                        let range = selection.range();
13027
13028                        let (edit_range, edit_text) = if let Some(language) = language
13029                            && language.name() == "Markdown".into()
13030                        {
13031                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13032                        } else {
13033                            (range, clipboard_text.clone())
13034                        };
13035
13036                        edits.push((edit_range, edit_text));
13037                    }
13038
13039                    drop(snapshot);
13040                    buffer.edit(edits, auto_indent_mode, cx);
13041
13042                    anchors
13043                });
13044
13045                this.change_selections(Default::default(), window, cx, |s| {
13046                    s.select_anchors(selection_anchors);
13047                });
13048            }
13049
13050            //   🤔                 |    ..     | show_in_menu |
13051            // | ..                  |   true        true
13052            // | had_edit_prediction |   false       true
13053
13054            let trigger_in_words =
13055                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13056
13057            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13058        });
13059    }
13060
13061    pub fn diff_clipboard_with_selection(
13062        &mut self,
13063        _: &DiffClipboardWithSelection,
13064        window: &mut Window,
13065        cx: &mut Context<Self>,
13066    ) {
13067        let selections = self
13068            .selections
13069            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13070
13071        if selections.is_empty() {
13072            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13073            return;
13074        };
13075
13076        let clipboard_text = match cx.read_from_clipboard() {
13077            Some(item) => match item.entries().first() {
13078                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13079                _ => None,
13080            },
13081            None => None,
13082        };
13083
13084        let Some(clipboard_text) = clipboard_text else {
13085            log::warn!("Clipboard doesn't contain text.");
13086            return;
13087        };
13088
13089        window.dispatch_action(
13090            Box::new(DiffClipboardWithSelectionData {
13091                clipboard_text,
13092                editor: cx.entity(),
13093            }),
13094            cx,
13095        );
13096    }
13097
13098    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13100        if let Some(item) = cx.read_from_clipboard() {
13101            let entries = item.entries();
13102
13103            match entries.first() {
13104                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13105                // of all the pasted entries.
13106                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13107                    .do_paste(
13108                        clipboard_string.text(),
13109                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13110                        true,
13111                        window,
13112                        cx,
13113                    ),
13114                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13115            }
13116        }
13117    }
13118
13119    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13120        if self.read_only(cx) {
13121            return;
13122        }
13123
13124        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13125
13126        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13127            if let Some((selections, _)) =
13128                self.selection_history.transaction(transaction_id).cloned()
13129            {
13130                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13131                    s.select_anchors(selections.to_vec());
13132                });
13133            } else {
13134                log::error!(
13135                    "No entry in selection_history found for undo. \
13136                     This may correspond to a bug where undo does not update the selection. \
13137                     If this is occurring, please add details to \
13138                     https://github.com/zed-industries/zed/issues/22692"
13139                );
13140            }
13141            self.request_autoscroll(Autoscroll::fit(), cx);
13142            self.unmark_text(window, cx);
13143            self.refresh_edit_prediction(true, false, window, cx);
13144            cx.emit(EditorEvent::Edited { transaction_id });
13145            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13146        }
13147    }
13148
13149    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13150        if self.read_only(cx) {
13151            return;
13152        }
13153
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13155
13156        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13157            if let Some((_, Some(selections))) =
13158                self.selection_history.transaction(transaction_id).cloned()
13159            {
13160                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13161                    s.select_anchors(selections.to_vec());
13162                });
13163            } else {
13164                log::error!(
13165                    "No entry in selection_history found for redo. \
13166                     This may correspond to a bug where undo does not update the selection. \
13167                     If this is occurring, please add details to \
13168                     https://github.com/zed-industries/zed/issues/22692"
13169                );
13170            }
13171            self.request_autoscroll(Autoscroll::fit(), cx);
13172            self.unmark_text(window, cx);
13173            self.refresh_edit_prediction(true, false, window, cx);
13174            cx.emit(EditorEvent::Edited { transaction_id });
13175        }
13176    }
13177
13178    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13179        self.buffer
13180            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13181    }
13182
13183    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13184        self.buffer
13185            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13186    }
13187
13188    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13190        self.change_selections(Default::default(), window, cx, |s| {
13191            s.move_with(|map, selection| {
13192                let cursor = if selection.is_empty() {
13193                    movement::left(map, selection.start)
13194                } else {
13195                    selection.start
13196                };
13197                selection.collapse_to(cursor, SelectionGoal::None);
13198            });
13199        })
13200    }
13201
13202    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204        self.change_selections(Default::default(), window, cx, |s| {
13205            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13206        })
13207    }
13208
13209    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13211        self.change_selections(Default::default(), window, cx, |s| {
13212            s.move_with(|map, selection| {
13213                let cursor = if selection.is_empty() {
13214                    movement::right(map, selection.end)
13215                } else {
13216                    selection.end
13217                };
13218                selection.collapse_to(cursor, SelectionGoal::None)
13219            });
13220        })
13221    }
13222
13223    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13225        self.change_selections(Default::default(), window, cx, |s| {
13226            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13227        });
13228    }
13229
13230    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13231        if self.take_rename(true, window, cx).is_some() {
13232            return;
13233        }
13234
13235        if self.mode.is_single_line() {
13236            cx.propagate();
13237            return;
13238        }
13239
13240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13241
13242        let text_layout_details = &self.text_layout_details(window);
13243        let selection_count = self.selections.count();
13244        let first_selection = self.selections.first_anchor();
13245
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_with(|map, selection| {
13248                if !selection.is_empty() {
13249                    selection.goal = SelectionGoal::None;
13250                }
13251                let (cursor, goal) = movement::up(
13252                    map,
13253                    selection.start,
13254                    selection.goal,
13255                    false,
13256                    text_layout_details,
13257                );
13258                selection.collapse_to(cursor, goal);
13259            });
13260        });
13261
13262        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13263        {
13264            cx.propagate();
13265        }
13266    }
13267
13268    pub fn move_up_by_lines(
13269        &mut self,
13270        action: &MoveUpByLines,
13271        window: &mut Window,
13272        cx: &mut Context<Self>,
13273    ) {
13274        if self.take_rename(true, window, cx).is_some() {
13275            return;
13276        }
13277
13278        if self.mode.is_single_line() {
13279            cx.propagate();
13280            return;
13281        }
13282
13283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13284
13285        let text_layout_details = &self.text_layout_details(window);
13286
13287        self.change_selections(Default::default(), window, cx, |s| {
13288            s.move_with(|map, selection| {
13289                if !selection.is_empty() {
13290                    selection.goal = SelectionGoal::None;
13291                }
13292                let (cursor, goal) = movement::up_by_rows(
13293                    map,
13294                    selection.start,
13295                    action.lines,
13296                    selection.goal,
13297                    false,
13298                    text_layout_details,
13299                );
13300                selection.collapse_to(cursor, goal);
13301            });
13302        })
13303    }
13304
13305    pub fn move_down_by_lines(
13306        &mut self,
13307        action: &MoveDownByLines,
13308        window: &mut Window,
13309        cx: &mut Context<Self>,
13310    ) {
13311        if self.take_rename(true, window, cx).is_some() {
13312            return;
13313        }
13314
13315        if self.mode.is_single_line() {
13316            cx.propagate();
13317            return;
13318        }
13319
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13321
13322        let text_layout_details = &self.text_layout_details(window);
13323
13324        self.change_selections(Default::default(), window, cx, |s| {
13325            s.move_with(|map, selection| {
13326                if !selection.is_empty() {
13327                    selection.goal = SelectionGoal::None;
13328                }
13329                let (cursor, goal) = movement::down_by_rows(
13330                    map,
13331                    selection.start,
13332                    action.lines,
13333                    selection.goal,
13334                    false,
13335                    text_layout_details,
13336                );
13337                selection.collapse_to(cursor, goal);
13338            });
13339        })
13340    }
13341
13342    pub fn select_down_by_lines(
13343        &mut self,
13344        action: &SelectDownByLines,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13349        let text_layout_details = &self.text_layout_details(window);
13350        self.change_selections(Default::default(), window, cx, |s| {
13351            s.move_heads_with(|map, head, goal| {
13352                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13353            })
13354        })
13355    }
13356
13357    pub fn select_up_by_lines(
13358        &mut self,
13359        action: &SelectUpByLines,
13360        window: &mut Window,
13361        cx: &mut Context<Self>,
13362    ) {
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        let text_layout_details = &self.text_layout_details(window);
13365        self.change_selections(Default::default(), window, cx, |s| {
13366            s.move_heads_with(|map, head, goal| {
13367                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13368            })
13369        })
13370    }
13371
13372    pub fn select_page_up(
13373        &mut self,
13374        _: &SelectPageUp,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        let Some(row_count) = self.visible_row_count() else {
13379            return;
13380        };
13381
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383
13384        let text_layout_details = &self.text_layout_details(window);
13385
13386        self.change_selections(Default::default(), window, cx, |s| {
13387            s.move_heads_with(|map, head, goal| {
13388                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13389            })
13390        })
13391    }
13392
13393    pub fn move_page_up(
13394        &mut self,
13395        action: &MovePageUp,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        if self.take_rename(true, window, cx).is_some() {
13400            return;
13401        }
13402
13403        if self
13404            .context_menu
13405            .borrow_mut()
13406            .as_mut()
13407            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13408            .unwrap_or(false)
13409        {
13410            return;
13411        }
13412
13413        if matches!(self.mode, EditorMode::SingleLine) {
13414            cx.propagate();
13415            return;
13416        }
13417
13418        let Some(row_count) = self.visible_row_count() else {
13419            return;
13420        };
13421
13422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13423
13424        let effects = if action.center_cursor {
13425            SelectionEffects::scroll(Autoscroll::center())
13426        } else {
13427            SelectionEffects::default()
13428        };
13429
13430        let text_layout_details = &self.text_layout_details(window);
13431
13432        self.change_selections(effects, window, cx, |s| {
13433            s.move_with(|map, selection| {
13434                if !selection.is_empty() {
13435                    selection.goal = SelectionGoal::None;
13436                }
13437                let (cursor, goal) = movement::up_by_rows(
13438                    map,
13439                    selection.end,
13440                    row_count,
13441                    selection.goal,
13442                    false,
13443                    text_layout_details,
13444                );
13445                selection.collapse_to(cursor, goal);
13446            });
13447        });
13448    }
13449
13450    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        let text_layout_details = &self.text_layout_details(window);
13453        self.change_selections(Default::default(), window, cx, |s| {
13454            s.move_heads_with(|map, head, goal| {
13455                movement::up(map, head, goal, false, text_layout_details)
13456            })
13457        })
13458    }
13459
13460    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13461        self.take_rename(true, window, cx);
13462
13463        if self.mode.is_single_line() {
13464            cx.propagate();
13465            return;
13466        }
13467
13468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13469
13470        let text_layout_details = &self.text_layout_details(window);
13471        let selection_count = self.selections.count();
13472        let first_selection = self.selections.first_anchor();
13473
13474        self.change_selections(Default::default(), window, cx, |s| {
13475            s.move_with(|map, selection| {
13476                if !selection.is_empty() {
13477                    selection.goal = SelectionGoal::None;
13478                }
13479                let (cursor, goal) = movement::down(
13480                    map,
13481                    selection.end,
13482                    selection.goal,
13483                    false,
13484                    text_layout_details,
13485                );
13486                selection.collapse_to(cursor, goal);
13487            });
13488        });
13489
13490        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13491        {
13492            cx.propagate();
13493        }
13494    }
13495
13496    pub fn select_page_down(
13497        &mut self,
13498        _: &SelectPageDown,
13499        window: &mut Window,
13500        cx: &mut Context<Self>,
13501    ) {
13502        let Some(row_count) = self.visible_row_count() else {
13503            return;
13504        };
13505
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13507
13508        let text_layout_details = &self.text_layout_details(window);
13509
13510        self.change_selections(Default::default(), window, cx, |s| {
13511            s.move_heads_with(|map, head, goal| {
13512                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13513            })
13514        })
13515    }
13516
13517    pub fn move_page_down(
13518        &mut self,
13519        action: &MovePageDown,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        if self.take_rename(true, window, cx).is_some() {
13524            return;
13525        }
13526
13527        if self
13528            .context_menu
13529            .borrow_mut()
13530            .as_mut()
13531            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13532            .unwrap_or(false)
13533        {
13534            return;
13535        }
13536
13537        if matches!(self.mode, EditorMode::SingleLine) {
13538            cx.propagate();
13539            return;
13540        }
13541
13542        let Some(row_count) = self.visible_row_count() else {
13543            return;
13544        };
13545
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547
13548        let effects = if action.center_cursor {
13549            SelectionEffects::scroll(Autoscroll::center())
13550        } else {
13551            SelectionEffects::default()
13552        };
13553
13554        let text_layout_details = &self.text_layout_details(window);
13555        self.change_selections(effects, window, cx, |s| {
13556            s.move_with(|map, selection| {
13557                if !selection.is_empty() {
13558                    selection.goal = SelectionGoal::None;
13559                }
13560                let (cursor, goal) = movement::down_by_rows(
13561                    map,
13562                    selection.end,
13563                    row_count,
13564                    selection.goal,
13565                    false,
13566                    text_layout_details,
13567                );
13568                selection.collapse_to(cursor, goal);
13569            });
13570        });
13571    }
13572
13573    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13575        let text_layout_details = &self.text_layout_details(window);
13576        self.change_selections(Default::default(), window, cx, |s| {
13577            s.move_heads_with(|map, head, goal| {
13578                movement::down(map, head, goal, false, text_layout_details)
13579            })
13580        });
13581    }
13582
13583    pub fn context_menu_first(
13584        &mut self,
13585        _: &ContextMenuFirst,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13590            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13591        }
13592    }
13593
13594    pub fn context_menu_prev(
13595        &mut self,
13596        _: &ContextMenuPrevious,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13601            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13602        }
13603    }
13604
13605    pub fn context_menu_next(
13606        &mut self,
13607        _: &ContextMenuNext,
13608        window: &mut Window,
13609        cx: &mut Context<Self>,
13610    ) {
13611        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13612            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13613        }
13614    }
13615
13616    pub fn context_menu_last(
13617        &mut self,
13618        _: &ContextMenuLast,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13623            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13624        }
13625    }
13626
13627    pub fn signature_help_prev(
13628        &mut self,
13629        _: &SignatureHelpPrevious,
13630        _: &mut Window,
13631        cx: &mut Context<Self>,
13632    ) {
13633        if let Some(popover) = self.signature_help_state.popover_mut() {
13634            if popover.current_signature == 0 {
13635                popover.current_signature = popover.signatures.len() - 1;
13636            } else {
13637                popover.current_signature -= 1;
13638            }
13639            cx.notify();
13640        }
13641    }
13642
13643    pub fn signature_help_next(
13644        &mut self,
13645        _: &SignatureHelpNext,
13646        _: &mut Window,
13647        cx: &mut Context<Self>,
13648    ) {
13649        if let Some(popover) = self.signature_help_state.popover_mut() {
13650            if popover.current_signature + 1 == popover.signatures.len() {
13651                popover.current_signature = 0;
13652            } else {
13653                popover.current_signature += 1;
13654            }
13655            cx.notify();
13656        }
13657    }
13658
13659    pub fn move_to_previous_word_start(
13660        &mut self,
13661        _: &MoveToPreviousWordStart,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13666        self.change_selections(Default::default(), window, cx, |s| {
13667            s.move_cursors_with(|map, head, _| {
13668                (
13669                    movement::previous_word_start(map, head),
13670                    SelectionGoal::None,
13671                )
13672            });
13673        })
13674    }
13675
13676    pub fn move_to_previous_subword_start(
13677        &mut self,
13678        _: &MoveToPreviousSubwordStart,
13679        window: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13683        self.change_selections(Default::default(), window, cx, |s| {
13684            s.move_cursors_with(|map, head, _| {
13685                (
13686                    movement::previous_subword_start(map, head),
13687                    SelectionGoal::None,
13688                )
13689            });
13690        })
13691    }
13692
13693    pub fn select_to_previous_word_start(
13694        &mut self,
13695        _: &SelectToPreviousWordStart,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13700        self.change_selections(Default::default(), window, cx, |s| {
13701            s.move_heads_with(|map, head, _| {
13702                (
13703                    movement::previous_word_start(map, head),
13704                    SelectionGoal::None,
13705                )
13706            });
13707        })
13708    }
13709
13710    pub fn select_to_previous_subword_start(
13711        &mut self,
13712        _: &SelectToPreviousSubwordStart,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13717        self.change_selections(Default::default(), window, cx, |s| {
13718            s.move_heads_with(|map, head, _| {
13719                (
13720                    movement::previous_subword_start(map, head),
13721                    SelectionGoal::None,
13722                )
13723            });
13724        })
13725    }
13726
13727    pub fn delete_to_previous_word_start(
13728        &mut self,
13729        action: &DeleteToPreviousWordStart,
13730        window: &mut Window,
13731        cx: &mut Context<Self>,
13732    ) {
13733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13734        self.transact(window, cx, |this, window, cx| {
13735            this.select_autoclose_pair(window, cx);
13736            this.change_selections(Default::default(), window, cx, |s| {
13737                s.move_with(|map, selection| {
13738                    if selection.is_empty() {
13739                        let mut cursor = if action.ignore_newlines {
13740                            movement::previous_word_start(map, selection.head())
13741                        } else {
13742                            movement::previous_word_start_or_newline(map, selection.head())
13743                        };
13744                        cursor = movement::adjust_greedy_deletion(
13745                            map,
13746                            selection.head(),
13747                            cursor,
13748                            action.ignore_brackets,
13749                        );
13750                        selection.set_head(cursor, SelectionGoal::None);
13751                    }
13752                });
13753            });
13754            this.insert("", window, cx);
13755        });
13756    }
13757
13758    pub fn delete_to_previous_subword_start(
13759        &mut self,
13760        _: &DeleteToPreviousSubwordStart,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13765        self.transact(window, cx, |this, window, cx| {
13766            this.select_autoclose_pair(window, cx);
13767            this.change_selections(Default::default(), window, cx, |s| {
13768                s.move_with(|map, selection| {
13769                    if selection.is_empty() {
13770                        let mut cursor = movement::previous_subword_start(map, selection.head());
13771                        cursor =
13772                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13773                        selection.set_head(cursor, SelectionGoal::None);
13774                    }
13775                });
13776            });
13777            this.insert("", window, cx);
13778        });
13779    }
13780
13781    pub fn move_to_next_word_end(
13782        &mut self,
13783        _: &MoveToNextWordEnd,
13784        window: &mut Window,
13785        cx: &mut Context<Self>,
13786    ) {
13787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13788        self.change_selections(Default::default(), window, cx, |s| {
13789            s.move_cursors_with(|map, head, _| {
13790                (movement::next_word_end(map, head), SelectionGoal::None)
13791            });
13792        })
13793    }
13794
13795    pub fn move_to_next_subword_end(
13796        &mut self,
13797        _: &MoveToNextSubwordEnd,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13802        self.change_selections(Default::default(), window, cx, |s| {
13803            s.move_cursors_with(|map, head, _| {
13804                (movement::next_subword_end(map, head), SelectionGoal::None)
13805            });
13806        })
13807    }
13808
13809    pub fn select_to_next_word_end(
13810        &mut self,
13811        _: &SelectToNextWordEnd,
13812        window: &mut Window,
13813        cx: &mut Context<Self>,
13814    ) {
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (movement::next_word_end(map, head), SelectionGoal::None)
13819            });
13820        })
13821    }
13822
13823    pub fn select_to_next_subword_end(
13824        &mut self,
13825        _: &SelectToNextSubwordEnd,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) {
13829        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13830        self.change_selections(Default::default(), window, cx, |s| {
13831            s.move_heads_with(|map, head, _| {
13832                (movement::next_subword_end(map, head), SelectionGoal::None)
13833            });
13834        })
13835    }
13836
13837    pub fn delete_to_next_word_end(
13838        &mut self,
13839        action: &DeleteToNextWordEnd,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13844        self.transact(window, cx, |this, window, cx| {
13845            this.change_selections(Default::default(), window, cx, |s| {
13846                s.move_with(|map, selection| {
13847                    if selection.is_empty() {
13848                        let mut cursor = if action.ignore_newlines {
13849                            movement::next_word_end(map, selection.head())
13850                        } else {
13851                            movement::next_word_end_or_newline(map, selection.head())
13852                        };
13853                        cursor = movement::adjust_greedy_deletion(
13854                            map,
13855                            selection.head(),
13856                            cursor,
13857                            action.ignore_brackets,
13858                        );
13859                        selection.set_head(cursor, SelectionGoal::None);
13860                    }
13861                });
13862            });
13863            this.insert("", window, cx);
13864        });
13865    }
13866
13867    pub fn delete_to_next_subword_end(
13868        &mut self,
13869        _: &DeleteToNextSubwordEnd,
13870        window: &mut Window,
13871        cx: &mut Context<Self>,
13872    ) {
13873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13874        self.transact(window, cx, |this, window, cx| {
13875            this.change_selections(Default::default(), window, cx, |s| {
13876                s.move_with(|map, selection| {
13877                    if selection.is_empty() {
13878                        let mut cursor = movement::next_subword_end(map, selection.head());
13879                        cursor =
13880                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13881                        selection.set_head(cursor, SelectionGoal::None);
13882                    }
13883                });
13884            });
13885            this.insert("", window, cx);
13886        });
13887    }
13888
13889    pub fn move_to_beginning_of_line(
13890        &mut self,
13891        action: &MoveToBeginningOfLine,
13892        window: &mut Window,
13893        cx: &mut Context<Self>,
13894    ) {
13895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13896        self.change_selections(Default::default(), window, cx, |s| {
13897            s.move_cursors_with(|map, head, _| {
13898                (
13899                    movement::indented_line_beginning(
13900                        map,
13901                        head,
13902                        action.stop_at_soft_wraps,
13903                        action.stop_at_indent,
13904                    ),
13905                    SelectionGoal::None,
13906                )
13907            });
13908        })
13909    }
13910
13911    pub fn select_to_beginning_of_line(
13912        &mut self,
13913        action: &SelectToBeginningOfLine,
13914        window: &mut Window,
13915        cx: &mut Context<Self>,
13916    ) {
13917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13918        self.change_selections(Default::default(), window, cx, |s| {
13919            s.move_heads_with(|map, head, _| {
13920                (
13921                    movement::indented_line_beginning(
13922                        map,
13923                        head,
13924                        action.stop_at_soft_wraps,
13925                        action.stop_at_indent,
13926                    ),
13927                    SelectionGoal::None,
13928                )
13929            });
13930        });
13931    }
13932
13933    pub fn delete_to_beginning_of_line(
13934        &mut self,
13935        action: &DeleteToBeginningOfLine,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13940        self.transact(window, cx, |this, window, cx| {
13941            this.change_selections(Default::default(), window, cx, |s| {
13942                s.move_with(|_, selection| {
13943                    selection.reversed = true;
13944                });
13945            });
13946
13947            this.select_to_beginning_of_line(
13948                &SelectToBeginningOfLine {
13949                    stop_at_soft_wraps: false,
13950                    stop_at_indent: action.stop_at_indent,
13951                },
13952                window,
13953                cx,
13954            );
13955            this.backspace(&Backspace, window, cx);
13956        });
13957    }
13958
13959    pub fn move_to_end_of_line(
13960        &mut self,
13961        action: &MoveToEndOfLine,
13962        window: &mut Window,
13963        cx: &mut Context<Self>,
13964    ) {
13965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13966        self.change_selections(Default::default(), window, cx, |s| {
13967            s.move_cursors_with(|map, head, _| {
13968                (
13969                    movement::line_end(map, head, action.stop_at_soft_wraps),
13970                    SelectionGoal::None,
13971                )
13972            });
13973        })
13974    }
13975
13976    pub fn select_to_end_of_line(
13977        &mut self,
13978        action: &SelectToEndOfLine,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13983        self.change_selections(Default::default(), window, cx, |s| {
13984            s.move_heads_with(|map, head, _| {
13985                (
13986                    movement::line_end(map, head, action.stop_at_soft_wraps),
13987                    SelectionGoal::None,
13988                )
13989            });
13990        })
13991    }
13992
13993    pub fn delete_to_end_of_line(
13994        &mut self,
13995        _: &DeleteToEndOfLine,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) {
13999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14000        self.transact(window, cx, |this, window, cx| {
14001            this.select_to_end_of_line(
14002                &SelectToEndOfLine {
14003                    stop_at_soft_wraps: false,
14004                },
14005                window,
14006                cx,
14007            );
14008            this.delete(&Delete, window, cx);
14009        });
14010    }
14011
14012    pub fn cut_to_end_of_line(
14013        &mut self,
14014        action: &CutToEndOfLine,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14019        self.transact(window, cx, |this, window, cx| {
14020            this.select_to_end_of_line(
14021                &SelectToEndOfLine {
14022                    stop_at_soft_wraps: false,
14023                },
14024                window,
14025                cx,
14026            );
14027            if !action.stop_at_newlines {
14028                this.change_selections(Default::default(), window, cx, |s| {
14029                    s.move_with(|_, sel| {
14030                        if sel.is_empty() {
14031                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14032                        }
14033                    });
14034                });
14035            }
14036            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14037            let item = this.cut_common(false, window, cx);
14038            cx.write_to_clipboard(item);
14039        });
14040    }
14041
14042    pub fn move_to_start_of_paragraph(
14043        &mut self,
14044        _: &MoveToStartOfParagraph,
14045        window: &mut Window,
14046        cx: &mut Context<Self>,
14047    ) {
14048        if matches!(self.mode, EditorMode::SingleLine) {
14049            cx.propagate();
14050            return;
14051        }
14052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14053        self.change_selections(Default::default(), window, cx, |s| {
14054            s.move_with(|map, selection| {
14055                selection.collapse_to(
14056                    movement::start_of_paragraph(map, selection.head(), 1),
14057                    SelectionGoal::None,
14058                )
14059            });
14060        })
14061    }
14062
14063    pub fn move_to_end_of_paragraph(
14064        &mut self,
14065        _: &MoveToEndOfParagraph,
14066        window: &mut Window,
14067        cx: &mut Context<Self>,
14068    ) {
14069        if matches!(self.mode, EditorMode::SingleLine) {
14070            cx.propagate();
14071            return;
14072        }
14073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14074        self.change_selections(Default::default(), window, cx, |s| {
14075            s.move_with(|map, selection| {
14076                selection.collapse_to(
14077                    movement::end_of_paragraph(map, selection.head(), 1),
14078                    SelectionGoal::None,
14079                )
14080            });
14081        })
14082    }
14083
14084    pub fn select_to_start_of_paragraph(
14085        &mut self,
14086        _: &SelectToStartOfParagraph,
14087        window: &mut Window,
14088        cx: &mut Context<Self>,
14089    ) {
14090        if matches!(self.mode, EditorMode::SingleLine) {
14091            cx.propagate();
14092            return;
14093        }
14094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14095        self.change_selections(Default::default(), window, cx, |s| {
14096            s.move_heads_with(|map, head, _| {
14097                (
14098                    movement::start_of_paragraph(map, head, 1),
14099                    SelectionGoal::None,
14100                )
14101            });
14102        })
14103    }
14104
14105    pub fn select_to_end_of_paragraph(
14106        &mut self,
14107        _: &SelectToEndOfParagraph,
14108        window: &mut Window,
14109        cx: &mut Context<Self>,
14110    ) {
14111        if matches!(self.mode, EditorMode::SingleLine) {
14112            cx.propagate();
14113            return;
14114        }
14115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14116        self.change_selections(Default::default(), window, cx, |s| {
14117            s.move_heads_with(|map, head, _| {
14118                (
14119                    movement::end_of_paragraph(map, head, 1),
14120                    SelectionGoal::None,
14121                )
14122            });
14123        })
14124    }
14125
14126    pub fn move_to_start_of_excerpt(
14127        &mut self,
14128        _: &MoveToStartOfExcerpt,
14129        window: &mut Window,
14130        cx: &mut Context<Self>,
14131    ) {
14132        if matches!(self.mode, EditorMode::SingleLine) {
14133            cx.propagate();
14134            return;
14135        }
14136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14137        self.change_selections(Default::default(), window, cx, |s| {
14138            s.move_with(|map, selection| {
14139                selection.collapse_to(
14140                    movement::start_of_excerpt(
14141                        map,
14142                        selection.head(),
14143                        workspace::searchable::Direction::Prev,
14144                    ),
14145                    SelectionGoal::None,
14146                )
14147            });
14148        })
14149    }
14150
14151    pub fn move_to_start_of_next_excerpt(
14152        &mut self,
14153        _: &MoveToStartOfNextExcerpt,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) {
14157        if matches!(self.mode, EditorMode::SingleLine) {
14158            cx.propagate();
14159            return;
14160        }
14161
14162        self.change_selections(Default::default(), window, cx, |s| {
14163            s.move_with(|map, selection| {
14164                selection.collapse_to(
14165                    movement::start_of_excerpt(
14166                        map,
14167                        selection.head(),
14168                        workspace::searchable::Direction::Next,
14169                    ),
14170                    SelectionGoal::None,
14171                )
14172            });
14173        })
14174    }
14175
14176    pub fn move_to_end_of_excerpt(
14177        &mut self,
14178        _: &MoveToEndOfExcerpt,
14179        window: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) {
14182        if matches!(self.mode, EditorMode::SingleLine) {
14183            cx.propagate();
14184            return;
14185        }
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14187        self.change_selections(Default::default(), window, cx, |s| {
14188            s.move_with(|map, selection| {
14189                selection.collapse_to(
14190                    movement::end_of_excerpt(
14191                        map,
14192                        selection.head(),
14193                        workspace::searchable::Direction::Next,
14194                    ),
14195                    SelectionGoal::None,
14196                )
14197            });
14198        })
14199    }
14200
14201    pub fn move_to_end_of_previous_excerpt(
14202        &mut self,
14203        _: &MoveToEndOfPreviousExcerpt,
14204        window: &mut Window,
14205        cx: &mut Context<Self>,
14206    ) {
14207        if matches!(self.mode, EditorMode::SingleLine) {
14208            cx.propagate();
14209            return;
14210        }
14211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14212        self.change_selections(Default::default(), window, cx, |s| {
14213            s.move_with(|map, selection| {
14214                selection.collapse_to(
14215                    movement::end_of_excerpt(
14216                        map,
14217                        selection.head(),
14218                        workspace::searchable::Direction::Prev,
14219                    ),
14220                    SelectionGoal::None,
14221                )
14222            });
14223        })
14224    }
14225
14226    pub fn select_to_start_of_excerpt(
14227        &mut self,
14228        _: &SelectToStartOfExcerpt,
14229        window: &mut Window,
14230        cx: &mut Context<Self>,
14231    ) {
14232        if matches!(self.mode, EditorMode::SingleLine) {
14233            cx.propagate();
14234            return;
14235        }
14236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14237        self.change_selections(Default::default(), window, cx, |s| {
14238            s.move_heads_with(|map, head, _| {
14239                (
14240                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14241                    SelectionGoal::None,
14242                )
14243            });
14244        })
14245    }
14246
14247    pub fn select_to_start_of_next_excerpt(
14248        &mut self,
14249        _: &SelectToStartOfNextExcerpt,
14250        window: &mut Window,
14251        cx: &mut Context<Self>,
14252    ) {
14253        if matches!(self.mode, EditorMode::SingleLine) {
14254            cx.propagate();
14255            return;
14256        }
14257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14258        self.change_selections(Default::default(), window, cx, |s| {
14259            s.move_heads_with(|map, head, _| {
14260                (
14261                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14262                    SelectionGoal::None,
14263                )
14264            });
14265        })
14266    }
14267
14268    pub fn select_to_end_of_excerpt(
14269        &mut self,
14270        _: &SelectToEndOfExcerpt,
14271        window: &mut Window,
14272        cx: &mut Context<Self>,
14273    ) {
14274        if matches!(self.mode, EditorMode::SingleLine) {
14275            cx.propagate();
14276            return;
14277        }
14278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14279        self.change_selections(Default::default(), window, cx, |s| {
14280            s.move_heads_with(|map, head, _| {
14281                (
14282                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14283                    SelectionGoal::None,
14284                )
14285            });
14286        })
14287    }
14288
14289    pub fn select_to_end_of_previous_excerpt(
14290        &mut self,
14291        _: &SelectToEndOfPreviousExcerpt,
14292        window: &mut Window,
14293        cx: &mut Context<Self>,
14294    ) {
14295        if matches!(self.mode, EditorMode::SingleLine) {
14296            cx.propagate();
14297            return;
14298        }
14299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14300        self.change_selections(Default::default(), window, cx, |s| {
14301            s.move_heads_with(|map, head, _| {
14302                (
14303                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14304                    SelectionGoal::None,
14305                )
14306            });
14307        })
14308    }
14309
14310    pub fn move_to_beginning(
14311        &mut self,
14312        _: &MoveToBeginning,
14313        window: &mut Window,
14314        cx: &mut Context<Self>,
14315    ) {
14316        if matches!(self.mode, EditorMode::SingleLine) {
14317            cx.propagate();
14318            return;
14319        }
14320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14321        self.change_selections(Default::default(), window, cx, |s| {
14322            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14323        });
14324    }
14325
14326    pub fn select_to_beginning(
14327        &mut self,
14328        _: &SelectToBeginning,
14329        window: &mut Window,
14330        cx: &mut Context<Self>,
14331    ) {
14332        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14333        selection.set_head(Point::zero(), SelectionGoal::None);
14334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14335        self.change_selections(Default::default(), window, cx, |s| {
14336            s.select(vec![selection]);
14337        });
14338    }
14339
14340    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14341        if matches!(self.mode, EditorMode::SingleLine) {
14342            cx.propagate();
14343            return;
14344        }
14345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14346        let cursor = self.buffer.read(cx).read(cx).len();
14347        self.change_selections(Default::default(), window, cx, |s| {
14348            s.select_ranges(vec![cursor..cursor])
14349        });
14350    }
14351
14352    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14353        self.nav_history = nav_history;
14354    }
14355
14356    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14357        self.nav_history.as_ref()
14358    }
14359
14360    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14361        self.push_to_nav_history(
14362            self.selections.newest_anchor().head(),
14363            None,
14364            false,
14365            true,
14366            cx,
14367        );
14368    }
14369
14370    fn push_to_nav_history(
14371        &mut self,
14372        cursor_anchor: Anchor,
14373        new_position: Option<Point>,
14374        is_deactivate: bool,
14375        always: bool,
14376        cx: &mut Context<Self>,
14377    ) {
14378        if let Some(nav_history) = self.nav_history.as_mut() {
14379            let buffer = self.buffer.read(cx).read(cx);
14380            let cursor_position = cursor_anchor.to_point(&buffer);
14381            let scroll_state = self.scroll_manager.anchor();
14382            let scroll_top_row = scroll_state.top_row(&buffer);
14383            drop(buffer);
14384
14385            if let Some(new_position) = new_position {
14386                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14387                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14388                    return;
14389                }
14390            }
14391
14392            nav_history.push(
14393                Some(NavigationData {
14394                    cursor_anchor,
14395                    cursor_position,
14396                    scroll_anchor: scroll_state,
14397                    scroll_top_row,
14398                }),
14399                cx,
14400            );
14401            cx.emit(EditorEvent::PushedToNavHistory {
14402                anchor: cursor_anchor,
14403                is_deactivate,
14404            })
14405        }
14406    }
14407
14408    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14410        let buffer = self.buffer.read(cx).snapshot(cx);
14411        let mut selection = self
14412            .selections
14413            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14414        selection.set_head(buffer.len(), SelectionGoal::None);
14415        self.change_selections(Default::default(), window, cx, |s| {
14416            s.select(vec![selection]);
14417        });
14418    }
14419
14420    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14422        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14423            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14424        });
14425    }
14426
14427    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14429        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14430        let mut selections = self.selections.all::<Point>(&display_map);
14431        let max_point = display_map.buffer_snapshot().max_point();
14432        for selection in &mut selections {
14433            let rows = selection.spanned_rows(true, &display_map);
14434            selection.start = Point::new(rows.start.0, 0);
14435            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14436            selection.reversed = false;
14437        }
14438        self.change_selections(Default::default(), window, cx, |s| {
14439            s.select(selections);
14440        });
14441    }
14442
14443    pub fn split_selection_into_lines(
14444        &mut self,
14445        action: &SplitSelectionIntoLines,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) {
14449        let selections = self
14450            .selections
14451            .all::<Point>(&self.display_snapshot(cx))
14452            .into_iter()
14453            .map(|selection| selection.start..selection.end)
14454            .collect::<Vec<_>>();
14455        self.unfold_ranges(&selections, true, true, cx);
14456
14457        let mut new_selection_ranges = Vec::new();
14458        {
14459            let buffer = self.buffer.read(cx).read(cx);
14460            for selection in selections {
14461                for row in selection.start.row..selection.end.row {
14462                    let line_start = Point::new(row, 0);
14463                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14464
14465                    if action.keep_selections {
14466                        // Keep the selection range for each line
14467                        let selection_start = if row == selection.start.row {
14468                            selection.start
14469                        } else {
14470                            line_start
14471                        };
14472                        new_selection_ranges.push(selection_start..line_end);
14473                    } else {
14474                        // Collapse to cursor at end of line
14475                        new_selection_ranges.push(line_end..line_end);
14476                    }
14477                }
14478
14479                let is_multiline_selection = selection.start.row != selection.end.row;
14480                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14481                // so this action feels more ergonomic when paired with other selection operations
14482                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14483                if !should_skip_last {
14484                    if action.keep_selections {
14485                        if is_multiline_selection {
14486                            let line_start = Point::new(selection.end.row, 0);
14487                            new_selection_ranges.push(line_start..selection.end);
14488                        } else {
14489                            new_selection_ranges.push(selection.start..selection.end);
14490                        }
14491                    } else {
14492                        new_selection_ranges.push(selection.end..selection.end);
14493                    }
14494                }
14495            }
14496        }
14497        self.change_selections(Default::default(), window, cx, |s| {
14498            s.select_ranges(new_selection_ranges);
14499        });
14500    }
14501
14502    pub fn add_selection_above(
14503        &mut self,
14504        action: &AddSelectionAbove,
14505        window: &mut Window,
14506        cx: &mut Context<Self>,
14507    ) {
14508        self.add_selection(true, action.skip_soft_wrap, window, cx);
14509    }
14510
14511    pub fn add_selection_below(
14512        &mut self,
14513        action: &AddSelectionBelow,
14514        window: &mut Window,
14515        cx: &mut Context<Self>,
14516    ) {
14517        self.add_selection(false, action.skip_soft_wrap, window, cx);
14518    }
14519
14520    fn add_selection(
14521        &mut self,
14522        above: bool,
14523        skip_soft_wrap: bool,
14524        window: &mut Window,
14525        cx: &mut Context<Self>,
14526    ) {
14527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14528
14529        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14530        let all_selections = self.selections.all::<Point>(&display_map);
14531        let text_layout_details = self.text_layout_details(window);
14532
14533        let (mut columnar_selections, new_selections_to_columnarize) = {
14534            if let Some(state) = self.add_selections_state.as_ref() {
14535                let columnar_selection_ids: HashSet<_> = state
14536                    .groups
14537                    .iter()
14538                    .flat_map(|group| group.stack.iter())
14539                    .copied()
14540                    .collect();
14541
14542                all_selections
14543                    .into_iter()
14544                    .partition(|s| columnar_selection_ids.contains(&s.id))
14545            } else {
14546                (Vec::new(), all_selections)
14547            }
14548        };
14549
14550        let mut state = self
14551            .add_selections_state
14552            .take()
14553            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14554
14555        for selection in new_selections_to_columnarize {
14556            let range = selection.display_range(&display_map).sorted();
14557            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14558            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14559            let positions = start_x.min(end_x)..start_x.max(end_x);
14560            let mut stack = Vec::new();
14561            for row in range.start.row().0..=range.end.row().0 {
14562                if let Some(selection) = self.selections.build_columnar_selection(
14563                    &display_map,
14564                    DisplayRow(row),
14565                    &positions,
14566                    selection.reversed,
14567                    &text_layout_details,
14568                ) {
14569                    stack.push(selection.id);
14570                    columnar_selections.push(selection);
14571                }
14572            }
14573            if !stack.is_empty() {
14574                if above {
14575                    stack.reverse();
14576                }
14577                state.groups.push(AddSelectionsGroup { above, stack });
14578            }
14579        }
14580
14581        let mut final_selections = Vec::new();
14582        let end_row = if above {
14583            DisplayRow(0)
14584        } else {
14585            display_map.max_point().row()
14586        };
14587
14588        let mut last_added_item_per_group = HashMap::default();
14589        for group in state.groups.iter_mut() {
14590            if let Some(last_id) = group.stack.last() {
14591                last_added_item_per_group.insert(*last_id, group);
14592            }
14593        }
14594
14595        for selection in columnar_selections {
14596            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14597                if above == group.above {
14598                    let range = selection.display_range(&display_map).sorted();
14599                    debug_assert_eq!(range.start.row(), range.end.row());
14600                    let mut row = range.start.row();
14601                    let positions =
14602                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14603                            Pixels::from(start)..Pixels::from(end)
14604                        } else {
14605                            let start_x =
14606                                display_map.x_for_display_point(range.start, &text_layout_details);
14607                            let end_x =
14608                                display_map.x_for_display_point(range.end, &text_layout_details);
14609                            start_x.min(end_x)..start_x.max(end_x)
14610                        };
14611
14612                    let mut maybe_new_selection = None;
14613                    let direction = if above { -1 } else { 1 };
14614
14615                    while row != end_row {
14616                        if skip_soft_wrap {
14617                            row = display_map
14618                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14619                                .row();
14620                        } else if above {
14621                            row.0 -= 1;
14622                        } else {
14623                            row.0 += 1;
14624                        }
14625
14626                        if let Some(new_selection) = self.selections.build_columnar_selection(
14627                            &display_map,
14628                            row,
14629                            &positions,
14630                            selection.reversed,
14631                            &text_layout_details,
14632                        ) {
14633                            maybe_new_selection = Some(new_selection);
14634                            break;
14635                        }
14636                    }
14637
14638                    if let Some(new_selection) = maybe_new_selection {
14639                        group.stack.push(new_selection.id);
14640                        if above {
14641                            final_selections.push(new_selection);
14642                            final_selections.push(selection);
14643                        } else {
14644                            final_selections.push(selection);
14645                            final_selections.push(new_selection);
14646                        }
14647                    } else {
14648                        final_selections.push(selection);
14649                    }
14650                } else {
14651                    group.stack.pop();
14652                }
14653            } else {
14654                final_selections.push(selection);
14655            }
14656        }
14657
14658        self.change_selections(Default::default(), window, cx, |s| {
14659            s.select(final_selections);
14660        });
14661
14662        let final_selection_ids: HashSet<_> = self
14663            .selections
14664            .all::<Point>(&display_map)
14665            .iter()
14666            .map(|s| s.id)
14667            .collect();
14668        state.groups.retain_mut(|group| {
14669            // selections might get merged above so we remove invalid items from stacks
14670            group.stack.retain(|id| final_selection_ids.contains(id));
14671
14672            // single selection in stack can be treated as initial state
14673            group.stack.len() > 1
14674        });
14675
14676        if !state.groups.is_empty() {
14677            self.add_selections_state = Some(state);
14678        }
14679    }
14680
14681    fn select_match_ranges(
14682        &mut self,
14683        range: Range<MultiBufferOffset>,
14684        reversed: bool,
14685        replace_newest: bool,
14686        auto_scroll: Option<Autoscroll>,
14687        window: &mut Window,
14688        cx: &mut Context<Editor>,
14689    ) {
14690        self.unfold_ranges(
14691            std::slice::from_ref(&range),
14692            false,
14693            auto_scroll.is_some(),
14694            cx,
14695        );
14696        let effects = if let Some(scroll) = auto_scroll {
14697            SelectionEffects::scroll(scroll)
14698        } else {
14699            SelectionEffects::no_scroll()
14700        };
14701        self.change_selections(effects, window, cx, |s| {
14702            if replace_newest {
14703                s.delete(s.newest_anchor().id);
14704            }
14705            if reversed {
14706                s.insert_range(range.end..range.start);
14707            } else {
14708                s.insert_range(range);
14709            }
14710        });
14711    }
14712
14713    pub fn select_next_match_internal(
14714        &mut self,
14715        display_map: &DisplaySnapshot,
14716        replace_newest: bool,
14717        autoscroll: Option<Autoscroll>,
14718        window: &mut Window,
14719        cx: &mut Context<Self>,
14720    ) -> Result<()> {
14721        let buffer = display_map.buffer_snapshot();
14722        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14723        if let Some(mut select_next_state) = self.select_next_state.take() {
14724            let query = &select_next_state.query;
14725            if !select_next_state.done {
14726                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14727                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14728                let mut next_selected_range = None;
14729
14730                let bytes_after_last_selection =
14731                    buffer.bytes_in_range(last_selection.end..buffer.len());
14732                let bytes_before_first_selection =
14733                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14734                let query_matches = query
14735                    .stream_find_iter(bytes_after_last_selection)
14736                    .map(|result| (last_selection.end, result))
14737                    .chain(
14738                        query
14739                            .stream_find_iter(bytes_before_first_selection)
14740                            .map(|result| (MultiBufferOffset(0), result)),
14741                    );
14742
14743                for (start_offset, query_match) in query_matches {
14744                    let query_match = query_match.unwrap(); // can only fail due to I/O
14745                    let offset_range =
14746                        start_offset + query_match.start()..start_offset + query_match.end();
14747
14748                    if !select_next_state.wordwise
14749                        || (!buffer.is_inside_word(offset_range.start, None)
14750                            && !buffer.is_inside_word(offset_range.end, None))
14751                    {
14752                        let idx = selections
14753                            .partition_point(|selection| selection.end <= offset_range.start);
14754                        let overlaps = selections
14755                            .get(idx)
14756                            .map_or(false, |selection| selection.start < offset_range.end);
14757
14758                        if !overlaps {
14759                            next_selected_range = Some(offset_range);
14760                            break;
14761                        }
14762                    }
14763                }
14764
14765                if let Some(next_selected_range) = next_selected_range {
14766                    self.select_match_ranges(
14767                        next_selected_range,
14768                        last_selection.reversed,
14769                        replace_newest,
14770                        autoscroll,
14771                        window,
14772                        cx,
14773                    );
14774                } else {
14775                    select_next_state.done = true;
14776                }
14777            }
14778
14779            self.select_next_state = Some(select_next_state);
14780        } else {
14781            let mut only_carets = true;
14782            let mut same_text_selected = true;
14783            let mut selected_text = None;
14784
14785            let mut selections_iter = selections.iter().peekable();
14786            while let Some(selection) = selections_iter.next() {
14787                if selection.start != selection.end {
14788                    only_carets = false;
14789                }
14790
14791                if same_text_selected {
14792                    if selected_text.is_none() {
14793                        selected_text =
14794                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14795                    }
14796
14797                    if let Some(next_selection) = selections_iter.peek() {
14798                        if next_selection.len() == selection.len() {
14799                            let next_selected_text = buffer
14800                                .text_for_range(next_selection.range())
14801                                .collect::<String>();
14802                            if Some(next_selected_text) != selected_text {
14803                                same_text_selected = false;
14804                                selected_text = None;
14805                            }
14806                        } else {
14807                            same_text_selected = false;
14808                            selected_text = None;
14809                        }
14810                    }
14811                }
14812            }
14813
14814            if only_carets {
14815                for selection in &mut selections {
14816                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14817                    selection.start = word_range.start;
14818                    selection.end = word_range.end;
14819                    selection.goal = SelectionGoal::None;
14820                    selection.reversed = false;
14821                    self.select_match_ranges(
14822                        selection.start..selection.end,
14823                        selection.reversed,
14824                        replace_newest,
14825                        autoscroll,
14826                        window,
14827                        cx,
14828                    );
14829                }
14830
14831                if selections.len() == 1 {
14832                    let selection = selections
14833                        .last()
14834                        .expect("ensured that there's only one selection");
14835                    let query = buffer
14836                        .text_for_range(selection.start..selection.end)
14837                        .collect::<String>();
14838                    let is_empty = query.is_empty();
14839                    let select_state = SelectNextState {
14840                        query: self.build_query(&[query], cx)?,
14841                        wordwise: true,
14842                        done: is_empty,
14843                    };
14844                    self.select_next_state = Some(select_state);
14845                } else {
14846                    self.select_next_state = None;
14847                }
14848            } else if let Some(selected_text) = selected_text {
14849                self.select_next_state = Some(SelectNextState {
14850                    query: self.build_query(&[selected_text], cx)?,
14851                    wordwise: false,
14852                    done: false,
14853                });
14854                self.select_next_match_internal(
14855                    display_map,
14856                    replace_newest,
14857                    autoscroll,
14858                    window,
14859                    cx,
14860                )?;
14861            }
14862        }
14863        Ok(())
14864    }
14865
14866    pub fn select_all_matches(
14867        &mut self,
14868        _action: &SelectAllMatches,
14869        window: &mut Window,
14870        cx: &mut Context<Self>,
14871    ) -> Result<()> {
14872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14873
14874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14875
14876        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14877        let Some(select_next_state) = self.select_next_state.as_mut() else {
14878            return Ok(());
14879        };
14880        if select_next_state.done {
14881            return Ok(());
14882        }
14883
14884        let mut new_selections = Vec::new();
14885
14886        let reversed = self
14887            .selections
14888            .oldest::<MultiBufferOffset>(&display_map)
14889            .reversed;
14890        let buffer = display_map.buffer_snapshot();
14891        let query_matches = select_next_state
14892            .query
14893            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14894
14895        for query_match in query_matches.into_iter() {
14896            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14897            let offset_range = if reversed {
14898                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14899            } else {
14900                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14901            };
14902
14903            if !select_next_state.wordwise
14904                || (!buffer.is_inside_word(offset_range.start, None)
14905                    && !buffer.is_inside_word(offset_range.end, None))
14906            {
14907                new_selections.push(offset_range.start..offset_range.end);
14908            }
14909        }
14910
14911        select_next_state.done = true;
14912
14913        if new_selections.is_empty() {
14914            log::error!("bug: new_selections is empty in select_all_matches");
14915            return Ok(());
14916        }
14917
14918        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14919        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14920            selections.select_ranges(new_selections)
14921        });
14922
14923        Ok(())
14924    }
14925
14926    pub fn select_next(
14927        &mut self,
14928        action: &SelectNext,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) -> Result<()> {
14932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14934        self.select_next_match_internal(
14935            &display_map,
14936            action.replace_newest,
14937            Some(Autoscroll::newest()),
14938            window,
14939            cx,
14940        )?;
14941        Ok(())
14942    }
14943
14944    pub fn select_previous(
14945        &mut self,
14946        action: &SelectPrevious,
14947        window: &mut Window,
14948        cx: &mut Context<Self>,
14949    ) -> Result<()> {
14950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14951        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14952        let buffer = display_map.buffer_snapshot();
14953        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14954        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14955            let query = &select_prev_state.query;
14956            if !select_prev_state.done {
14957                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14958                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14959                let mut next_selected_range = None;
14960                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14961                let bytes_before_last_selection =
14962                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14963                let bytes_after_first_selection =
14964                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14965                let query_matches = query
14966                    .stream_find_iter(bytes_before_last_selection)
14967                    .map(|result| (last_selection.start, result))
14968                    .chain(
14969                        query
14970                            .stream_find_iter(bytes_after_first_selection)
14971                            .map(|result| (buffer.len(), result)),
14972                    );
14973                for (end_offset, query_match) in query_matches {
14974                    let query_match = query_match.unwrap(); // can only fail due to I/O
14975                    let offset_range =
14976                        end_offset - query_match.end()..end_offset - query_match.start();
14977
14978                    if !select_prev_state.wordwise
14979                        || (!buffer.is_inside_word(offset_range.start, None)
14980                            && !buffer.is_inside_word(offset_range.end, None))
14981                    {
14982                        next_selected_range = Some(offset_range);
14983                        break;
14984                    }
14985                }
14986
14987                if let Some(next_selected_range) = next_selected_range {
14988                    self.select_match_ranges(
14989                        next_selected_range,
14990                        last_selection.reversed,
14991                        action.replace_newest,
14992                        Some(Autoscroll::newest()),
14993                        window,
14994                        cx,
14995                    );
14996                } else {
14997                    select_prev_state.done = true;
14998                }
14999            }
15000
15001            self.select_prev_state = Some(select_prev_state);
15002        } else {
15003            let mut only_carets = true;
15004            let mut same_text_selected = true;
15005            let mut selected_text = None;
15006
15007            let mut selections_iter = selections.iter().peekable();
15008            while let Some(selection) = selections_iter.next() {
15009                if selection.start != selection.end {
15010                    only_carets = false;
15011                }
15012
15013                if same_text_selected {
15014                    if selected_text.is_none() {
15015                        selected_text =
15016                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15017                    }
15018
15019                    if let Some(next_selection) = selections_iter.peek() {
15020                        if next_selection.len() == selection.len() {
15021                            let next_selected_text = buffer
15022                                .text_for_range(next_selection.range())
15023                                .collect::<String>();
15024                            if Some(next_selected_text) != selected_text {
15025                                same_text_selected = false;
15026                                selected_text = None;
15027                            }
15028                        } else {
15029                            same_text_selected = false;
15030                            selected_text = None;
15031                        }
15032                    }
15033                }
15034            }
15035
15036            if only_carets {
15037                for selection in &mut selections {
15038                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15039                    selection.start = word_range.start;
15040                    selection.end = word_range.end;
15041                    selection.goal = SelectionGoal::None;
15042                    selection.reversed = false;
15043                    self.select_match_ranges(
15044                        selection.start..selection.end,
15045                        selection.reversed,
15046                        action.replace_newest,
15047                        Some(Autoscroll::newest()),
15048                        window,
15049                        cx,
15050                    );
15051                }
15052                if selections.len() == 1 {
15053                    let selection = selections
15054                        .last()
15055                        .expect("ensured that there's only one selection");
15056                    let query = buffer
15057                        .text_for_range(selection.start..selection.end)
15058                        .collect::<String>();
15059                    let is_empty = query.is_empty();
15060                    let select_state = SelectNextState {
15061                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15062                        wordwise: true,
15063                        done: is_empty,
15064                    };
15065                    self.select_prev_state = Some(select_state);
15066                } else {
15067                    self.select_prev_state = None;
15068                }
15069            } else if let Some(selected_text) = selected_text {
15070                self.select_prev_state = Some(SelectNextState {
15071                    query: self
15072                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15073                    wordwise: false,
15074                    done: false,
15075                });
15076                self.select_previous(action, window, cx)?;
15077            }
15078        }
15079        Ok(())
15080    }
15081
15082    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15083    /// setting the case sensitivity based on the global
15084    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15085    /// editor's settings.
15086    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15087    where
15088        I: IntoIterator<Item = P>,
15089        P: AsRef<[u8]>,
15090    {
15091        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15092            || EditorSettings::get_global(cx).search.case_sensitive,
15093            |value| value,
15094        );
15095
15096        let mut builder = AhoCorasickBuilder::new();
15097        builder.ascii_case_insensitive(!case_sensitive);
15098        builder.build(patterns)
15099    }
15100
15101    pub fn find_next_match(
15102        &mut self,
15103        _: &FindNextMatch,
15104        window: &mut Window,
15105        cx: &mut Context<Self>,
15106    ) -> Result<()> {
15107        let selections = self.selections.disjoint_anchors_arc();
15108        match selections.first() {
15109            Some(first) if selections.len() >= 2 => {
15110                self.change_selections(Default::default(), window, cx, |s| {
15111                    s.select_ranges([first.range()]);
15112                });
15113            }
15114            _ => self.select_next(
15115                &SelectNext {
15116                    replace_newest: true,
15117                },
15118                window,
15119                cx,
15120            )?,
15121        }
15122        Ok(())
15123    }
15124
15125    pub fn find_previous_match(
15126        &mut self,
15127        _: &FindPreviousMatch,
15128        window: &mut Window,
15129        cx: &mut Context<Self>,
15130    ) -> Result<()> {
15131        let selections = self.selections.disjoint_anchors_arc();
15132        match selections.last() {
15133            Some(last) if selections.len() >= 2 => {
15134                self.change_selections(Default::default(), window, cx, |s| {
15135                    s.select_ranges([last.range()]);
15136                });
15137            }
15138            _ => self.select_previous(
15139                &SelectPrevious {
15140                    replace_newest: true,
15141                },
15142                window,
15143                cx,
15144            )?,
15145        }
15146        Ok(())
15147    }
15148
15149    pub fn toggle_comments(
15150        &mut self,
15151        action: &ToggleComments,
15152        window: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) {
15155        if self.read_only(cx) {
15156            return;
15157        }
15158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15159        let text_layout_details = &self.text_layout_details(window);
15160        self.transact(window, cx, |this, window, cx| {
15161            let mut selections = this
15162                .selections
15163                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15164            let mut edits = Vec::new();
15165            let mut selection_edit_ranges = Vec::new();
15166            let mut last_toggled_row = None;
15167            let snapshot = this.buffer.read(cx).read(cx);
15168            let empty_str: Arc<str> = Arc::default();
15169            let mut suffixes_inserted = Vec::new();
15170            let ignore_indent = action.ignore_indent;
15171
15172            fn comment_prefix_range(
15173                snapshot: &MultiBufferSnapshot,
15174                row: MultiBufferRow,
15175                comment_prefix: &str,
15176                comment_prefix_whitespace: &str,
15177                ignore_indent: bool,
15178            ) -> Range<Point> {
15179                let indent_size = if ignore_indent {
15180                    0
15181                } else {
15182                    snapshot.indent_size_for_line(row).len
15183                };
15184
15185                let start = Point::new(row.0, indent_size);
15186
15187                let mut line_bytes = snapshot
15188                    .bytes_in_range(start..snapshot.max_point())
15189                    .flatten()
15190                    .copied();
15191
15192                // If this line currently begins with the line comment prefix, then record
15193                // the range containing the prefix.
15194                if line_bytes
15195                    .by_ref()
15196                    .take(comment_prefix.len())
15197                    .eq(comment_prefix.bytes())
15198                {
15199                    // Include any whitespace that matches the comment prefix.
15200                    let matching_whitespace_len = line_bytes
15201                        .zip(comment_prefix_whitespace.bytes())
15202                        .take_while(|(a, b)| a == b)
15203                        .count() as u32;
15204                    let end = Point::new(
15205                        start.row,
15206                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15207                    );
15208                    start..end
15209                } else {
15210                    start..start
15211                }
15212            }
15213
15214            fn comment_suffix_range(
15215                snapshot: &MultiBufferSnapshot,
15216                row: MultiBufferRow,
15217                comment_suffix: &str,
15218                comment_suffix_has_leading_space: bool,
15219            ) -> Range<Point> {
15220                let end = Point::new(row.0, snapshot.line_len(row));
15221                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15222
15223                let mut line_end_bytes = snapshot
15224                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15225                    .flatten()
15226                    .copied();
15227
15228                let leading_space_len = if suffix_start_column > 0
15229                    && line_end_bytes.next() == Some(b' ')
15230                    && comment_suffix_has_leading_space
15231                {
15232                    1
15233                } else {
15234                    0
15235                };
15236
15237                // If this line currently begins with the line comment prefix, then record
15238                // the range containing the prefix.
15239                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15240                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15241                    start..end
15242                } else {
15243                    end..end
15244                }
15245            }
15246
15247            // TODO: Handle selections that cross excerpts
15248            for selection in &mut selections {
15249                let start_column = snapshot
15250                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15251                    .len;
15252                let language = if let Some(language) =
15253                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15254                {
15255                    language
15256                } else {
15257                    continue;
15258                };
15259
15260                selection_edit_ranges.clear();
15261
15262                // If multiple selections contain a given row, avoid processing that
15263                // row more than once.
15264                let mut start_row = MultiBufferRow(selection.start.row);
15265                if last_toggled_row == Some(start_row) {
15266                    start_row = start_row.next_row();
15267                }
15268                let end_row =
15269                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15270                        MultiBufferRow(selection.end.row - 1)
15271                    } else {
15272                        MultiBufferRow(selection.end.row)
15273                    };
15274                last_toggled_row = Some(end_row);
15275
15276                if start_row > end_row {
15277                    continue;
15278                }
15279
15280                // If the language has line comments, toggle those.
15281                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15282
15283                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15284                if ignore_indent {
15285                    full_comment_prefixes = full_comment_prefixes
15286                        .into_iter()
15287                        .map(|s| Arc::from(s.trim_end()))
15288                        .collect();
15289                }
15290
15291                if !full_comment_prefixes.is_empty() {
15292                    let first_prefix = full_comment_prefixes
15293                        .first()
15294                        .expect("prefixes is non-empty");
15295                    let prefix_trimmed_lengths = full_comment_prefixes
15296                        .iter()
15297                        .map(|p| p.trim_end_matches(' ').len())
15298                        .collect::<SmallVec<[usize; 4]>>();
15299
15300                    let mut all_selection_lines_are_comments = true;
15301
15302                    for row in start_row.0..=end_row.0 {
15303                        let row = MultiBufferRow(row);
15304                        if start_row < end_row && snapshot.is_line_blank(row) {
15305                            continue;
15306                        }
15307
15308                        let prefix_range = full_comment_prefixes
15309                            .iter()
15310                            .zip(prefix_trimmed_lengths.iter().copied())
15311                            .map(|(prefix, trimmed_prefix_len)| {
15312                                comment_prefix_range(
15313                                    snapshot.deref(),
15314                                    row,
15315                                    &prefix[..trimmed_prefix_len],
15316                                    &prefix[trimmed_prefix_len..],
15317                                    ignore_indent,
15318                                )
15319                            })
15320                            .max_by_key(|range| range.end.column - range.start.column)
15321                            .expect("prefixes is non-empty");
15322
15323                        if prefix_range.is_empty() {
15324                            all_selection_lines_are_comments = false;
15325                        }
15326
15327                        selection_edit_ranges.push(prefix_range);
15328                    }
15329
15330                    if all_selection_lines_are_comments {
15331                        edits.extend(
15332                            selection_edit_ranges
15333                                .iter()
15334                                .cloned()
15335                                .map(|range| (range, empty_str.clone())),
15336                        );
15337                    } else {
15338                        let min_column = selection_edit_ranges
15339                            .iter()
15340                            .map(|range| range.start.column)
15341                            .min()
15342                            .unwrap_or(0);
15343                        edits.extend(selection_edit_ranges.iter().map(|range| {
15344                            let position = Point::new(range.start.row, min_column);
15345                            (position..position, first_prefix.clone())
15346                        }));
15347                    }
15348                } else if let Some(BlockCommentConfig {
15349                    start: full_comment_prefix,
15350                    end: comment_suffix,
15351                    ..
15352                }) = language.block_comment()
15353                {
15354                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15355                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15356                    let prefix_range = comment_prefix_range(
15357                        snapshot.deref(),
15358                        start_row,
15359                        comment_prefix,
15360                        comment_prefix_whitespace,
15361                        ignore_indent,
15362                    );
15363                    let suffix_range = comment_suffix_range(
15364                        snapshot.deref(),
15365                        end_row,
15366                        comment_suffix.trim_start_matches(' '),
15367                        comment_suffix.starts_with(' '),
15368                    );
15369
15370                    if prefix_range.is_empty() || suffix_range.is_empty() {
15371                        edits.push((
15372                            prefix_range.start..prefix_range.start,
15373                            full_comment_prefix.clone(),
15374                        ));
15375                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15376                        suffixes_inserted.push((end_row, comment_suffix.len()));
15377                    } else {
15378                        edits.push((prefix_range, empty_str.clone()));
15379                        edits.push((suffix_range, empty_str.clone()));
15380                    }
15381                } else {
15382                    continue;
15383                }
15384            }
15385
15386            drop(snapshot);
15387            this.buffer.update(cx, |buffer, cx| {
15388                buffer.edit(edits, None, cx);
15389            });
15390
15391            // Adjust selections so that they end before any comment suffixes that
15392            // were inserted.
15393            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15394            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15395            let snapshot = this.buffer.read(cx).read(cx);
15396            for selection in &mut selections {
15397                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15398                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15399                        Ordering::Less => {
15400                            suffixes_inserted.next();
15401                            continue;
15402                        }
15403                        Ordering::Greater => break,
15404                        Ordering::Equal => {
15405                            if selection.end.column == snapshot.line_len(row) {
15406                                if selection.is_empty() {
15407                                    selection.start.column -= suffix_len as u32;
15408                                }
15409                                selection.end.column -= suffix_len as u32;
15410                            }
15411                            break;
15412                        }
15413                    }
15414                }
15415            }
15416
15417            drop(snapshot);
15418            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15419
15420            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15421            let selections_on_single_row = selections.windows(2).all(|selections| {
15422                selections[0].start.row == selections[1].start.row
15423                    && selections[0].end.row == selections[1].end.row
15424                    && selections[0].start.row == selections[0].end.row
15425            });
15426            let selections_selecting = selections
15427                .iter()
15428                .any(|selection| selection.start != selection.end);
15429            let advance_downwards = action.advance_downwards
15430                && selections_on_single_row
15431                && !selections_selecting
15432                && !matches!(this.mode, EditorMode::SingleLine);
15433
15434            if advance_downwards {
15435                let snapshot = this.buffer.read(cx).snapshot(cx);
15436
15437                this.change_selections(Default::default(), window, cx, |s| {
15438                    s.move_cursors_with(|display_snapshot, display_point, _| {
15439                        let mut point = display_point.to_point(display_snapshot);
15440                        point.row += 1;
15441                        point = snapshot.clip_point(point, Bias::Left);
15442                        let display_point = point.to_display_point(display_snapshot);
15443                        let goal = SelectionGoal::HorizontalPosition(
15444                            display_snapshot
15445                                .x_for_display_point(display_point, text_layout_details)
15446                                .into(),
15447                        );
15448                        (display_point, goal)
15449                    })
15450                });
15451            }
15452        });
15453    }
15454
15455    pub fn select_enclosing_symbol(
15456        &mut self,
15457        _: &SelectEnclosingSymbol,
15458        window: &mut Window,
15459        cx: &mut Context<Self>,
15460    ) {
15461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15462
15463        let buffer = self.buffer.read(cx).snapshot(cx);
15464        let old_selections = self
15465            .selections
15466            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15467            .into_boxed_slice();
15468
15469        fn update_selection(
15470            selection: &Selection<MultiBufferOffset>,
15471            buffer_snap: &MultiBufferSnapshot,
15472        ) -> Option<Selection<MultiBufferOffset>> {
15473            let cursor = selection.head();
15474            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15475            for symbol in symbols.iter().rev() {
15476                let start = symbol.range.start.to_offset(buffer_snap);
15477                let end = symbol.range.end.to_offset(buffer_snap);
15478                let new_range = start..end;
15479                if start < selection.start || end > selection.end {
15480                    return Some(Selection {
15481                        id: selection.id,
15482                        start: new_range.start,
15483                        end: new_range.end,
15484                        goal: SelectionGoal::None,
15485                        reversed: selection.reversed,
15486                    });
15487                }
15488            }
15489            None
15490        }
15491
15492        let mut selected_larger_symbol = false;
15493        let new_selections = old_selections
15494            .iter()
15495            .map(|selection| match update_selection(selection, &buffer) {
15496                Some(new_selection) => {
15497                    if new_selection.range() != selection.range() {
15498                        selected_larger_symbol = true;
15499                    }
15500                    new_selection
15501                }
15502                None => selection.clone(),
15503            })
15504            .collect::<Vec<_>>();
15505
15506        if selected_larger_symbol {
15507            self.change_selections(Default::default(), window, cx, |s| {
15508                s.select(new_selections);
15509            });
15510        }
15511    }
15512
15513    pub fn select_larger_syntax_node(
15514        &mut self,
15515        _: &SelectLargerSyntaxNode,
15516        window: &mut Window,
15517        cx: &mut Context<Self>,
15518    ) {
15519        let Some(visible_row_count) = self.visible_row_count() else {
15520            return;
15521        };
15522        let old_selections: Box<[_]> = self
15523            .selections
15524            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15525            .into();
15526        if old_selections.is_empty() {
15527            return;
15528        }
15529
15530        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15531
15532        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15533        let buffer = self.buffer.read(cx).snapshot(cx);
15534
15535        let mut selected_larger_node = false;
15536        let mut new_selections = old_selections
15537            .iter()
15538            .map(|selection| {
15539                let old_range = selection.start..selection.end;
15540
15541                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15542                    // manually select word at selection
15543                    if ["string_content", "inline"].contains(&node.kind()) {
15544                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15545                        // ignore if word is already selected
15546                        if !word_range.is_empty() && old_range != word_range {
15547                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15548                            // only select word if start and end point belongs to same word
15549                            if word_range == last_word_range {
15550                                selected_larger_node = true;
15551                                return Selection {
15552                                    id: selection.id,
15553                                    start: word_range.start,
15554                                    end: word_range.end,
15555                                    goal: SelectionGoal::None,
15556                                    reversed: selection.reversed,
15557                                };
15558                            }
15559                        }
15560                    }
15561                }
15562
15563                let mut new_range = old_range.clone();
15564                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15565                    new_range = range;
15566                    if !node.is_named() {
15567                        continue;
15568                    }
15569                    if !display_map.intersects_fold(new_range.start)
15570                        && !display_map.intersects_fold(new_range.end)
15571                    {
15572                        break;
15573                    }
15574                }
15575
15576                selected_larger_node |= new_range != old_range;
15577                Selection {
15578                    id: selection.id,
15579                    start: new_range.start,
15580                    end: new_range.end,
15581                    goal: SelectionGoal::None,
15582                    reversed: selection.reversed,
15583                }
15584            })
15585            .collect::<Vec<_>>();
15586
15587        if !selected_larger_node {
15588            return; // don't put this call in the history
15589        }
15590
15591        // scroll based on transformation done to the last selection created by the user
15592        let (last_old, last_new) = old_selections
15593            .last()
15594            .zip(new_selections.last().cloned())
15595            .expect("old_selections isn't empty");
15596
15597        // revert selection
15598        let is_selection_reversed = {
15599            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15600            new_selections.last_mut().expect("checked above").reversed =
15601                should_newest_selection_be_reversed;
15602            should_newest_selection_be_reversed
15603        };
15604
15605        if selected_larger_node {
15606            self.select_syntax_node_history.disable_clearing = true;
15607            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15608                s.select(new_selections.clone());
15609            });
15610            self.select_syntax_node_history.disable_clearing = false;
15611        }
15612
15613        let start_row = last_new.start.to_display_point(&display_map).row().0;
15614        let end_row = last_new.end.to_display_point(&display_map).row().0;
15615        let selection_height = end_row - start_row + 1;
15616        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15617
15618        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15619        let scroll_behavior = if fits_on_the_screen {
15620            self.request_autoscroll(Autoscroll::fit(), cx);
15621            SelectSyntaxNodeScrollBehavior::FitSelection
15622        } else if is_selection_reversed {
15623            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15624            SelectSyntaxNodeScrollBehavior::CursorTop
15625        } else {
15626            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15627            SelectSyntaxNodeScrollBehavior::CursorBottom
15628        };
15629
15630        self.select_syntax_node_history.push((
15631            old_selections,
15632            scroll_behavior,
15633            is_selection_reversed,
15634        ));
15635    }
15636
15637    pub fn select_smaller_syntax_node(
15638        &mut self,
15639        _: &SelectSmallerSyntaxNode,
15640        window: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15644
15645        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15646            self.select_syntax_node_history.pop()
15647        {
15648            if let Some(selection) = selections.last_mut() {
15649                selection.reversed = is_selection_reversed;
15650            }
15651
15652            self.select_syntax_node_history.disable_clearing = true;
15653            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15654                s.select(selections.to_vec());
15655            });
15656            self.select_syntax_node_history.disable_clearing = false;
15657
15658            match scroll_behavior {
15659                SelectSyntaxNodeScrollBehavior::CursorTop => {
15660                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15661                }
15662                SelectSyntaxNodeScrollBehavior::FitSelection => {
15663                    self.request_autoscroll(Autoscroll::fit(), cx);
15664                }
15665                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15666                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15667                }
15668            }
15669        }
15670    }
15671
15672    pub fn unwrap_syntax_node(
15673        &mut self,
15674        _: &UnwrapSyntaxNode,
15675        window: &mut Window,
15676        cx: &mut Context<Self>,
15677    ) {
15678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15679
15680        let buffer = self.buffer.read(cx).snapshot(cx);
15681        let selections = self
15682            .selections
15683            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15684            .into_iter()
15685            // subtracting the offset requires sorting
15686            .sorted_by_key(|i| i.start);
15687
15688        let full_edits = selections
15689            .into_iter()
15690            .filter_map(|selection| {
15691                let child = if selection.is_empty()
15692                    && let Some((_, ancestor_range)) =
15693                        buffer.syntax_ancestor(selection.start..selection.end)
15694                {
15695                    ancestor_range
15696                } else {
15697                    selection.range()
15698                };
15699
15700                let mut parent = child.clone();
15701                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15702                    parent = ancestor_range;
15703                    if parent.start < child.start || parent.end > child.end {
15704                        break;
15705                    }
15706                }
15707
15708                if parent == child {
15709                    return None;
15710                }
15711                let text = buffer.text_for_range(child).collect::<String>();
15712                Some((selection.id, parent, text))
15713            })
15714            .collect::<Vec<_>>();
15715        if full_edits.is_empty() {
15716            return;
15717        }
15718
15719        self.transact(window, cx, |this, window, cx| {
15720            this.buffer.update(cx, |buffer, cx| {
15721                buffer.edit(
15722                    full_edits
15723                        .iter()
15724                        .map(|(_, p, t)| (p.clone(), t.clone()))
15725                        .collect::<Vec<_>>(),
15726                    None,
15727                    cx,
15728                );
15729            });
15730            this.change_selections(Default::default(), window, cx, |s| {
15731                let mut offset = 0;
15732                let mut selections = vec![];
15733                for (id, parent, text) in full_edits {
15734                    let start = parent.start - offset;
15735                    offset += (parent.end - parent.start) - text.len();
15736                    selections.push(Selection {
15737                        id,
15738                        start,
15739                        end: start + text.len(),
15740                        reversed: false,
15741                        goal: Default::default(),
15742                    });
15743                }
15744                s.select(selections);
15745            });
15746        });
15747    }
15748
15749    pub fn select_next_syntax_node(
15750        &mut self,
15751        _: &SelectNextSyntaxNode,
15752        window: &mut Window,
15753        cx: &mut Context<Self>,
15754    ) {
15755        let old_selections: Box<[_]> = self
15756            .selections
15757            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15758            .into();
15759        if old_selections.is_empty() {
15760            return;
15761        }
15762
15763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15764
15765        let buffer = self.buffer.read(cx).snapshot(cx);
15766        let mut selected_sibling = false;
15767
15768        let new_selections = old_selections
15769            .iter()
15770            .map(|selection| {
15771                let old_range = selection.start..selection.end;
15772
15773                let old_range =
15774                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15775                let excerpt = buffer.excerpt_containing(old_range.clone());
15776
15777                if let Some(mut excerpt) = excerpt
15778                    && let Some(node) = excerpt
15779                        .buffer()
15780                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15781                {
15782                    let new_range = excerpt.map_range_from_buffer(
15783                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15784                    );
15785                    selected_sibling = true;
15786                    Selection {
15787                        id: selection.id,
15788                        start: new_range.start,
15789                        end: new_range.end,
15790                        goal: SelectionGoal::None,
15791                        reversed: selection.reversed,
15792                    }
15793                } else {
15794                    selection.clone()
15795                }
15796            })
15797            .collect::<Vec<_>>();
15798
15799        if selected_sibling {
15800            self.change_selections(
15801                SelectionEffects::scroll(Autoscroll::fit()),
15802                window,
15803                cx,
15804                |s| {
15805                    s.select(new_selections);
15806                },
15807            );
15808        }
15809    }
15810
15811    pub fn select_prev_syntax_node(
15812        &mut self,
15813        _: &SelectPreviousSyntaxNode,
15814        window: &mut Window,
15815        cx: &mut Context<Self>,
15816    ) {
15817        let old_selections: Box<[_]> = self
15818            .selections
15819            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15820            .into();
15821        if old_selections.is_empty() {
15822            return;
15823        }
15824
15825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15826
15827        let buffer = self.buffer.read(cx).snapshot(cx);
15828        let mut selected_sibling = false;
15829
15830        let new_selections = old_selections
15831            .iter()
15832            .map(|selection| {
15833                let old_range = selection.start..selection.end;
15834                let old_range =
15835                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15836                let excerpt = buffer.excerpt_containing(old_range.clone());
15837
15838                if let Some(mut excerpt) = excerpt
15839                    && let Some(node) = excerpt
15840                        .buffer()
15841                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15842                {
15843                    let new_range = excerpt.map_range_from_buffer(
15844                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15845                    );
15846                    selected_sibling = true;
15847                    Selection {
15848                        id: selection.id,
15849                        start: new_range.start,
15850                        end: new_range.end,
15851                        goal: SelectionGoal::None,
15852                        reversed: selection.reversed,
15853                    }
15854                } else {
15855                    selection.clone()
15856                }
15857            })
15858            .collect::<Vec<_>>();
15859
15860        if selected_sibling {
15861            self.change_selections(
15862                SelectionEffects::scroll(Autoscroll::fit()),
15863                window,
15864                cx,
15865                |s| {
15866                    s.select(new_selections);
15867                },
15868            );
15869        }
15870    }
15871
15872    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15873        if !EditorSettings::get_global(cx).gutter.runnables {
15874            self.clear_tasks();
15875            return Task::ready(());
15876        }
15877        let project = self.project().map(Entity::downgrade);
15878        let task_sources = self.lsp_task_sources(cx);
15879        let multi_buffer = self.buffer.downgrade();
15880        cx.spawn_in(window, async move |editor, cx| {
15881            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15882            let Some(project) = project.and_then(|p| p.upgrade()) else {
15883                return;
15884            };
15885            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15886                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15887            }) else {
15888                return;
15889            };
15890
15891            let hide_runnables = project
15892                .update(cx, |project, _| project.is_via_collab())
15893                .unwrap_or(true);
15894            if hide_runnables {
15895                return;
15896            }
15897            let new_rows =
15898                cx.background_spawn({
15899                    let snapshot = display_snapshot.clone();
15900                    async move {
15901                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15902                    }
15903                })
15904                    .await;
15905            let Ok(lsp_tasks) =
15906                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15907            else {
15908                return;
15909            };
15910            let lsp_tasks = lsp_tasks.await;
15911
15912            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15913                lsp_tasks
15914                    .into_iter()
15915                    .flat_map(|(kind, tasks)| {
15916                        tasks.into_iter().filter_map(move |(location, task)| {
15917                            Some((kind.clone(), location?, task))
15918                        })
15919                    })
15920                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15921                        let buffer = location.target.buffer;
15922                        let buffer_snapshot = buffer.read(cx).snapshot();
15923                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15924                            |(excerpt_id, snapshot, _)| {
15925                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15926                                    display_snapshot
15927                                        .buffer_snapshot()
15928                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15929                                } else {
15930                                    None
15931                                }
15932                            },
15933                        );
15934                        if let Some(offset) = offset {
15935                            let task_buffer_range =
15936                                location.target.range.to_point(&buffer_snapshot);
15937                            let context_buffer_range =
15938                                task_buffer_range.to_offset(&buffer_snapshot);
15939                            let context_range = BufferOffset(context_buffer_range.start)
15940                                ..BufferOffset(context_buffer_range.end);
15941
15942                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15943                                .or_insert_with(|| RunnableTasks {
15944                                    templates: Vec::new(),
15945                                    offset,
15946                                    column: task_buffer_range.start.column,
15947                                    extra_variables: HashMap::default(),
15948                                    context_range,
15949                                })
15950                                .templates
15951                                .push((kind, task.original_task().clone()));
15952                        }
15953
15954                        acc
15955                    })
15956            }) else {
15957                return;
15958            };
15959
15960            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15961                buffer.language_settings(cx).tasks.prefer_lsp
15962            }) else {
15963                return;
15964            };
15965
15966            let rows = Self::runnable_rows(
15967                project,
15968                display_snapshot,
15969                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15970                new_rows,
15971                cx.clone(),
15972            )
15973            .await;
15974            editor
15975                .update(cx, |editor, _| {
15976                    editor.clear_tasks();
15977                    for (key, mut value) in rows {
15978                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15979                            value.templates.extend(lsp_tasks.templates);
15980                        }
15981
15982                        editor.insert_tasks(key, value);
15983                    }
15984                    for (key, value) in lsp_tasks_by_rows {
15985                        editor.insert_tasks(key, value);
15986                    }
15987                })
15988                .ok();
15989        })
15990    }
15991    fn fetch_runnable_ranges(
15992        snapshot: &DisplaySnapshot,
15993        range: Range<Anchor>,
15994    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15995        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15996    }
15997
15998    fn runnable_rows(
15999        project: Entity<Project>,
16000        snapshot: DisplaySnapshot,
16001        prefer_lsp: bool,
16002        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16003        cx: AsyncWindowContext,
16004    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16005        cx.spawn(async move |cx| {
16006            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16007            for (run_range, mut runnable) in runnable_ranges {
16008                let Some(tasks) = cx
16009                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16010                    .ok()
16011                else {
16012                    continue;
16013                };
16014                let mut tasks = tasks.await;
16015
16016                if prefer_lsp {
16017                    tasks.retain(|(task_kind, _)| {
16018                        !matches!(task_kind, TaskSourceKind::Language { .. })
16019                    });
16020                }
16021                if tasks.is_empty() {
16022                    continue;
16023                }
16024
16025                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16026                let Some(row) = snapshot
16027                    .buffer_snapshot()
16028                    .buffer_line_for_row(MultiBufferRow(point.row))
16029                    .map(|(_, range)| range.start.row)
16030                else {
16031                    continue;
16032                };
16033
16034                let context_range =
16035                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16036                runnable_rows.push((
16037                    (runnable.buffer_id, row),
16038                    RunnableTasks {
16039                        templates: tasks,
16040                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16041                        context_range,
16042                        column: point.column,
16043                        extra_variables: runnable.extra_captures,
16044                    },
16045                ));
16046            }
16047            runnable_rows
16048        })
16049    }
16050
16051    fn templates_with_tags(
16052        project: &Entity<Project>,
16053        runnable: &mut Runnable,
16054        cx: &mut App,
16055    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16056        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16057            let (worktree_id, file) = project
16058                .buffer_for_id(runnable.buffer, cx)
16059                .and_then(|buffer| buffer.read(cx).file())
16060                .map(|file| (file.worktree_id(cx), file.clone()))
16061                .unzip();
16062
16063            (
16064                project.task_store().read(cx).task_inventory().cloned(),
16065                worktree_id,
16066                file,
16067            )
16068        });
16069
16070        let tags = mem::take(&mut runnable.tags);
16071        let language = runnable.language.clone();
16072        cx.spawn(async move |cx| {
16073            let mut templates_with_tags = Vec::new();
16074            if let Some(inventory) = inventory {
16075                for RunnableTag(tag) in tags {
16076                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16077                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16078                    }) else {
16079                        return templates_with_tags;
16080                    };
16081                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16082                        move |(_, template)| {
16083                            template.tags.iter().any(|source_tag| source_tag == &tag)
16084                        },
16085                    ));
16086                }
16087            }
16088            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16089
16090            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16091                // Strongest source wins; if we have worktree tag binding, prefer that to
16092                // global and language bindings;
16093                // if we have a global binding, prefer that to language binding.
16094                let first_mismatch = templates_with_tags
16095                    .iter()
16096                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16097                if let Some(index) = first_mismatch {
16098                    templates_with_tags.truncate(index);
16099                }
16100            }
16101
16102            templates_with_tags
16103        })
16104    }
16105
16106    pub fn move_to_enclosing_bracket(
16107        &mut self,
16108        _: &MoveToEnclosingBracket,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) {
16112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16113        self.change_selections(Default::default(), window, cx, |s| {
16114            s.move_offsets_with(|snapshot, selection| {
16115                let Some(enclosing_bracket_ranges) =
16116                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16117                else {
16118                    return;
16119                };
16120
16121                let mut best_length = usize::MAX;
16122                let mut best_inside = false;
16123                let mut best_in_bracket_range = false;
16124                let mut best_destination = None;
16125                for (open, close) in enclosing_bracket_ranges {
16126                    let close = close.to_inclusive();
16127                    let length = *close.end() - open.start;
16128                    let inside = selection.start >= open.end && selection.end <= *close.start();
16129                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16130                        || close.contains(&selection.head());
16131
16132                    // If best is next to a bracket and current isn't, skip
16133                    if !in_bracket_range && best_in_bracket_range {
16134                        continue;
16135                    }
16136
16137                    // Prefer smaller lengths unless best is inside and current isn't
16138                    if length > best_length && (best_inside || !inside) {
16139                        continue;
16140                    }
16141
16142                    best_length = length;
16143                    best_inside = inside;
16144                    best_in_bracket_range = in_bracket_range;
16145                    best_destination = Some(
16146                        if close.contains(&selection.start) && close.contains(&selection.end) {
16147                            if inside { open.end } else { open.start }
16148                        } else if inside {
16149                            *close.start()
16150                        } else {
16151                            *close.end()
16152                        },
16153                    );
16154                }
16155
16156                if let Some(destination) = best_destination {
16157                    selection.collapse_to(destination, SelectionGoal::None);
16158                }
16159            })
16160        });
16161    }
16162
16163    pub fn undo_selection(
16164        &mut self,
16165        _: &UndoSelection,
16166        window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) {
16169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16170        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16171            self.selection_history.mode = SelectionHistoryMode::Undoing;
16172            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16173                this.end_selection(window, cx);
16174                this.change_selections(
16175                    SelectionEffects::scroll(Autoscroll::newest()),
16176                    window,
16177                    cx,
16178                    |s| s.select_anchors(entry.selections.to_vec()),
16179                );
16180            });
16181            self.selection_history.mode = SelectionHistoryMode::Normal;
16182
16183            self.select_next_state = entry.select_next_state;
16184            self.select_prev_state = entry.select_prev_state;
16185            self.add_selections_state = entry.add_selections_state;
16186        }
16187    }
16188
16189    pub fn redo_selection(
16190        &mut self,
16191        _: &RedoSelection,
16192        window: &mut Window,
16193        cx: &mut Context<Self>,
16194    ) {
16195        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16196        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16197            self.selection_history.mode = SelectionHistoryMode::Redoing;
16198            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16199                this.end_selection(window, cx);
16200                this.change_selections(
16201                    SelectionEffects::scroll(Autoscroll::newest()),
16202                    window,
16203                    cx,
16204                    |s| s.select_anchors(entry.selections.to_vec()),
16205                );
16206            });
16207            self.selection_history.mode = SelectionHistoryMode::Normal;
16208
16209            self.select_next_state = entry.select_next_state;
16210            self.select_prev_state = entry.select_prev_state;
16211            self.add_selections_state = entry.add_selections_state;
16212        }
16213    }
16214
16215    pub fn expand_excerpts(
16216        &mut self,
16217        action: &ExpandExcerpts,
16218        _: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) {
16221        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16222    }
16223
16224    pub fn expand_excerpts_down(
16225        &mut self,
16226        action: &ExpandExcerptsDown,
16227        _: &mut Window,
16228        cx: &mut Context<Self>,
16229    ) {
16230        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16231    }
16232
16233    pub fn expand_excerpts_up(
16234        &mut self,
16235        action: &ExpandExcerptsUp,
16236        _: &mut Window,
16237        cx: &mut Context<Self>,
16238    ) {
16239        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16240    }
16241
16242    pub fn expand_excerpts_for_direction(
16243        &mut self,
16244        lines: u32,
16245        direction: ExpandExcerptDirection,
16246
16247        cx: &mut Context<Self>,
16248    ) {
16249        let selections = self.selections.disjoint_anchors_arc();
16250
16251        let lines = if lines == 0 {
16252            EditorSettings::get_global(cx).expand_excerpt_lines
16253        } else {
16254            lines
16255        };
16256
16257        self.buffer.update(cx, |buffer, cx| {
16258            let snapshot = buffer.snapshot(cx);
16259            let mut excerpt_ids = selections
16260                .iter()
16261                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16262                .collect::<Vec<_>>();
16263            excerpt_ids.sort();
16264            excerpt_ids.dedup();
16265            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16266        })
16267    }
16268
16269    pub fn expand_excerpt(
16270        &mut self,
16271        excerpt: ExcerptId,
16272        direction: ExpandExcerptDirection,
16273        window: &mut Window,
16274        cx: &mut Context<Self>,
16275    ) {
16276        let current_scroll_position = self.scroll_position(cx);
16277        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16278        let mut scroll = None;
16279
16280        if direction == ExpandExcerptDirection::Down {
16281            let multi_buffer = self.buffer.read(cx);
16282            let snapshot = multi_buffer.snapshot(cx);
16283            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16284                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16285                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16286            {
16287                let buffer_snapshot = buffer.read(cx).snapshot();
16288                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16289                let last_row = buffer_snapshot.max_point().row;
16290                let lines_below = last_row.saturating_sub(excerpt_end_row);
16291                if lines_below >= lines_to_expand {
16292                    scroll = Some(
16293                        current_scroll_position
16294                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16295                    );
16296                }
16297            }
16298        }
16299        if direction == ExpandExcerptDirection::Up
16300            && self
16301                .buffer
16302                .read(cx)
16303                .snapshot(cx)
16304                .excerpt_before(excerpt)
16305                .is_none()
16306        {
16307            scroll = Some(current_scroll_position);
16308        }
16309
16310        self.buffer.update(cx, |buffer, cx| {
16311            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16312        });
16313
16314        if let Some(new_scroll_position) = scroll {
16315            self.set_scroll_position(new_scroll_position, window, cx);
16316        }
16317    }
16318
16319    pub fn go_to_singleton_buffer_point(
16320        &mut self,
16321        point: Point,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) {
16325        self.go_to_singleton_buffer_range(point..point, window, cx);
16326    }
16327
16328    pub fn go_to_singleton_buffer_range(
16329        &mut self,
16330        range: Range<Point>,
16331        window: &mut Window,
16332        cx: &mut Context<Self>,
16333    ) {
16334        let multibuffer = self.buffer().read(cx);
16335        let Some(buffer) = multibuffer.as_singleton() else {
16336            return;
16337        };
16338        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16339            return;
16340        };
16341        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16342            return;
16343        };
16344        self.change_selections(
16345            SelectionEffects::default().nav_history(true),
16346            window,
16347            cx,
16348            |s| s.select_anchor_ranges([start..end]),
16349        );
16350    }
16351
16352    pub fn go_to_diagnostic(
16353        &mut self,
16354        action: &GoToDiagnostic,
16355        window: &mut Window,
16356        cx: &mut Context<Self>,
16357    ) {
16358        if !self.diagnostics_enabled() {
16359            return;
16360        }
16361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16362        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16363    }
16364
16365    pub fn go_to_prev_diagnostic(
16366        &mut self,
16367        action: &GoToPreviousDiagnostic,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) {
16371        if !self.diagnostics_enabled() {
16372            return;
16373        }
16374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16375        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16376    }
16377
16378    pub fn go_to_diagnostic_impl(
16379        &mut self,
16380        direction: Direction,
16381        severity: GoToDiagnosticSeverityFilter,
16382        window: &mut Window,
16383        cx: &mut Context<Self>,
16384    ) {
16385        let buffer = self.buffer.read(cx).snapshot(cx);
16386        let selection = self
16387            .selections
16388            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16389
16390        let mut active_group_id = None;
16391        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16392            && active_group.active_range.start.to_offset(&buffer) == selection.start
16393        {
16394            active_group_id = Some(active_group.group_id);
16395        }
16396
16397        fn filtered<'a>(
16398            severity: GoToDiagnosticSeverityFilter,
16399            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16400        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16401            diagnostics
16402                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16403                .filter(|entry| entry.range.start != entry.range.end)
16404                .filter(|entry| !entry.diagnostic.is_unnecessary)
16405        }
16406
16407        let before = filtered(
16408            severity,
16409            buffer
16410                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16411                .filter(|entry| entry.range.start <= selection.start),
16412        );
16413        let after = filtered(
16414            severity,
16415            buffer
16416                .diagnostics_in_range(selection.start..buffer.len())
16417                .filter(|entry| entry.range.start >= selection.start),
16418        );
16419
16420        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16421        if direction == Direction::Prev {
16422            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16423            {
16424                for diagnostic in prev_diagnostics.into_iter().rev() {
16425                    if diagnostic.range.start != selection.start
16426                        || active_group_id
16427                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16428                    {
16429                        found = Some(diagnostic);
16430                        break 'outer;
16431                    }
16432                }
16433            }
16434        } else {
16435            for diagnostic in after.chain(before) {
16436                if diagnostic.range.start != selection.start
16437                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16438                {
16439                    found = Some(diagnostic);
16440                    break;
16441                }
16442            }
16443        }
16444        let Some(next_diagnostic) = found else {
16445            return;
16446        };
16447
16448        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16449        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16450            return;
16451        };
16452        let snapshot = self.snapshot(window, cx);
16453        if snapshot.intersects_fold(next_diagnostic.range.start) {
16454            self.unfold_ranges(
16455                std::slice::from_ref(&next_diagnostic.range),
16456                true,
16457                false,
16458                cx,
16459            );
16460        }
16461        self.change_selections(Default::default(), window, cx, |s| {
16462            s.select_ranges(vec![
16463                next_diagnostic.range.start..next_diagnostic.range.start,
16464            ])
16465        });
16466        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16467        self.refresh_edit_prediction(false, true, window, cx);
16468    }
16469
16470    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16472        let snapshot = self.snapshot(window, cx);
16473        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16474        self.go_to_hunk_before_or_after_position(
16475            &snapshot,
16476            selection.head(),
16477            Direction::Next,
16478            window,
16479            cx,
16480        );
16481    }
16482
16483    pub fn go_to_hunk_before_or_after_position(
16484        &mut self,
16485        snapshot: &EditorSnapshot,
16486        position: Point,
16487        direction: Direction,
16488        window: &mut Window,
16489        cx: &mut Context<Editor>,
16490    ) {
16491        let row = if direction == Direction::Next {
16492            self.hunk_after_position(snapshot, position)
16493                .map(|hunk| hunk.row_range.start)
16494        } else {
16495            self.hunk_before_position(snapshot, position)
16496        };
16497
16498        if let Some(row) = row {
16499            let destination = Point::new(row.0, 0);
16500            let autoscroll = Autoscroll::center();
16501
16502            self.unfold_ranges(&[destination..destination], false, false, cx);
16503            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16504                s.select_ranges([destination..destination]);
16505            });
16506        }
16507    }
16508
16509    fn hunk_after_position(
16510        &mut self,
16511        snapshot: &EditorSnapshot,
16512        position: Point,
16513    ) -> Option<MultiBufferDiffHunk> {
16514        snapshot
16515            .buffer_snapshot()
16516            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16517            .find(|hunk| hunk.row_range.start.0 > position.row)
16518            .or_else(|| {
16519                snapshot
16520                    .buffer_snapshot()
16521                    .diff_hunks_in_range(Point::zero()..position)
16522                    .find(|hunk| hunk.row_range.end.0 < position.row)
16523            })
16524    }
16525
16526    fn go_to_prev_hunk(
16527        &mut self,
16528        _: &GoToPreviousHunk,
16529        window: &mut Window,
16530        cx: &mut Context<Self>,
16531    ) {
16532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16533        let snapshot = self.snapshot(window, cx);
16534        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16535        self.go_to_hunk_before_or_after_position(
16536            &snapshot,
16537            selection.head(),
16538            Direction::Prev,
16539            window,
16540            cx,
16541        );
16542    }
16543
16544    fn hunk_before_position(
16545        &mut self,
16546        snapshot: &EditorSnapshot,
16547        position: Point,
16548    ) -> Option<MultiBufferRow> {
16549        snapshot
16550            .buffer_snapshot()
16551            .diff_hunk_before(position)
16552            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16553    }
16554
16555    fn go_to_next_change(
16556        &mut self,
16557        _: &GoToNextChange,
16558        window: &mut Window,
16559        cx: &mut Context<Self>,
16560    ) {
16561        if let Some(selections) = self
16562            .change_list
16563            .next_change(1, Direction::Next)
16564            .map(|s| s.to_vec())
16565        {
16566            self.change_selections(Default::default(), window, cx, |s| {
16567                let map = s.display_snapshot();
16568                s.select_display_ranges(selections.iter().map(|a| {
16569                    let point = a.to_display_point(&map);
16570                    point..point
16571                }))
16572            })
16573        }
16574    }
16575
16576    fn go_to_previous_change(
16577        &mut self,
16578        _: &GoToPreviousChange,
16579        window: &mut Window,
16580        cx: &mut Context<Self>,
16581    ) {
16582        if let Some(selections) = self
16583            .change_list
16584            .next_change(1, Direction::Prev)
16585            .map(|s| s.to_vec())
16586        {
16587            self.change_selections(Default::default(), window, cx, |s| {
16588                let map = s.display_snapshot();
16589                s.select_display_ranges(selections.iter().map(|a| {
16590                    let point = a.to_display_point(&map);
16591                    point..point
16592                }))
16593            })
16594        }
16595    }
16596
16597    pub fn go_to_next_document_highlight(
16598        &mut self,
16599        _: &GoToNextDocumentHighlight,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16604    }
16605
16606    pub fn go_to_prev_document_highlight(
16607        &mut self,
16608        _: &GoToPreviousDocumentHighlight,
16609        window: &mut Window,
16610        cx: &mut Context<Self>,
16611    ) {
16612        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16613    }
16614
16615    pub fn go_to_document_highlight_before_or_after_position(
16616        &mut self,
16617        direction: Direction,
16618        window: &mut Window,
16619        cx: &mut Context<Editor>,
16620    ) {
16621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16622        let snapshot = self.snapshot(window, cx);
16623        let buffer = &snapshot.buffer_snapshot();
16624        let position = self
16625            .selections
16626            .newest::<Point>(&snapshot.display_snapshot)
16627            .head();
16628        let anchor_position = buffer.anchor_after(position);
16629
16630        // Get all document highlights (both read and write)
16631        let mut all_highlights = Vec::new();
16632
16633        if let Some((_, read_highlights)) = self
16634            .background_highlights
16635            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16636        {
16637            all_highlights.extend(read_highlights.iter());
16638        }
16639
16640        if let Some((_, write_highlights)) = self
16641            .background_highlights
16642            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16643        {
16644            all_highlights.extend(write_highlights.iter());
16645        }
16646
16647        if all_highlights.is_empty() {
16648            return;
16649        }
16650
16651        // Sort highlights by position
16652        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16653
16654        let target_highlight = match direction {
16655            Direction::Next => {
16656                // Find the first highlight after the current position
16657                all_highlights
16658                    .iter()
16659                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16660            }
16661            Direction::Prev => {
16662                // Find the last highlight before the current position
16663                all_highlights
16664                    .iter()
16665                    .rev()
16666                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16667            }
16668        };
16669
16670        if let Some(highlight) = target_highlight {
16671            let destination = highlight.start.to_point(buffer);
16672            let autoscroll = Autoscroll::center();
16673
16674            self.unfold_ranges(&[destination..destination], false, false, cx);
16675            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16676                s.select_ranges([destination..destination]);
16677            });
16678        }
16679    }
16680
16681    fn go_to_line<T: 'static>(
16682        &mut self,
16683        position: Anchor,
16684        highlight_color: Option<Hsla>,
16685        window: &mut Window,
16686        cx: &mut Context<Self>,
16687    ) {
16688        let snapshot = self.snapshot(window, cx).display_snapshot;
16689        let position = position.to_point(&snapshot.buffer_snapshot());
16690        let start = snapshot
16691            .buffer_snapshot()
16692            .clip_point(Point::new(position.row, 0), Bias::Left);
16693        let end = start + Point::new(1, 0);
16694        let start = snapshot.buffer_snapshot().anchor_before(start);
16695        let end = snapshot.buffer_snapshot().anchor_before(end);
16696
16697        self.highlight_rows::<T>(
16698            start..end,
16699            highlight_color
16700                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16701            Default::default(),
16702            cx,
16703        );
16704
16705        if self.buffer.read(cx).is_singleton() {
16706            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16707        }
16708    }
16709
16710    pub fn go_to_definition(
16711        &mut self,
16712        _: &GoToDefinition,
16713        window: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) -> Task<Result<Navigated>> {
16716        let definition =
16717            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16718        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16719        cx.spawn_in(window, async move |editor, cx| {
16720            if definition.await? == Navigated::Yes {
16721                return Ok(Navigated::Yes);
16722            }
16723            match fallback_strategy {
16724                GoToDefinitionFallback::None => Ok(Navigated::No),
16725                GoToDefinitionFallback::FindAllReferences => {
16726                    match editor.update_in(cx, |editor, window, cx| {
16727                        editor.find_all_references(&FindAllReferences, window, cx)
16728                    })? {
16729                        Some(references) => references.await,
16730                        None => Ok(Navigated::No),
16731                    }
16732                }
16733            }
16734        })
16735    }
16736
16737    pub fn go_to_declaration(
16738        &mut self,
16739        _: &GoToDeclaration,
16740        window: &mut Window,
16741        cx: &mut Context<Self>,
16742    ) -> Task<Result<Navigated>> {
16743        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16744    }
16745
16746    pub fn go_to_declaration_split(
16747        &mut self,
16748        _: &GoToDeclaration,
16749        window: &mut Window,
16750        cx: &mut Context<Self>,
16751    ) -> Task<Result<Navigated>> {
16752        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16753    }
16754
16755    pub fn go_to_implementation(
16756        &mut self,
16757        _: &GoToImplementation,
16758        window: &mut Window,
16759        cx: &mut Context<Self>,
16760    ) -> Task<Result<Navigated>> {
16761        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16762    }
16763
16764    pub fn go_to_implementation_split(
16765        &mut self,
16766        _: &GoToImplementationSplit,
16767        window: &mut Window,
16768        cx: &mut Context<Self>,
16769    ) -> Task<Result<Navigated>> {
16770        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16771    }
16772
16773    pub fn go_to_type_definition(
16774        &mut self,
16775        _: &GoToTypeDefinition,
16776        window: &mut Window,
16777        cx: &mut Context<Self>,
16778    ) -> Task<Result<Navigated>> {
16779        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16780    }
16781
16782    pub fn go_to_definition_split(
16783        &mut self,
16784        _: &GoToDefinitionSplit,
16785        window: &mut Window,
16786        cx: &mut Context<Self>,
16787    ) -> Task<Result<Navigated>> {
16788        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16789    }
16790
16791    pub fn go_to_type_definition_split(
16792        &mut self,
16793        _: &GoToTypeDefinitionSplit,
16794        window: &mut Window,
16795        cx: &mut Context<Self>,
16796    ) -> Task<Result<Navigated>> {
16797        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16798    }
16799
16800    fn go_to_definition_of_kind(
16801        &mut self,
16802        kind: GotoDefinitionKind,
16803        split: bool,
16804        window: &mut Window,
16805        cx: &mut Context<Self>,
16806    ) -> Task<Result<Navigated>> {
16807        let Some(provider) = self.semantics_provider.clone() else {
16808            return Task::ready(Ok(Navigated::No));
16809        };
16810        let head = self
16811            .selections
16812            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16813            .head();
16814        let buffer = self.buffer.read(cx);
16815        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16816            return Task::ready(Ok(Navigated::No));
16817        };
16818        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16819            return Task::ready(Ok(Navigated::No));
16820        };
16821
16822        cx.spawn_in(window, async move |editor, cx| {
16823            let Some(definitions) = definitions.await? else {
16824                return Ok(Navigated::No);
16825            };
16826            let navigated = editor
16827                .update_in(cx, |editor, window, cx| {
16828                    editor.navigate_to_hover_links(
16829                        Some(kind),
16830                        definitions
16831                            .into_iter()
16832                            .filter(|location| {
16833                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16834                            })
16835                            .map(HoverLink::Text)
16836                            .collect::<Vec<_>>(),
16837                        split,
16838                        window,
16839                        cx,
16840                    )
16841                })?
16842                .await?;
16843            anyhow::Ok(navigated)
16844        })
16845    }
16846
16847    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16848        let selection = self.selections.newest_anchor();
16849        let head = selection.head();
16850        let tail = selection.tail();
16851
16852        let Some((buffer, start_position)) =
16853            self.buffer.read(cx).text_anchor_for_position(head, cx)
16854        else {
16855            return;
16856        };
16857
16858        let end_position = if head != tail {
16859            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16860                return;
16861            };
16862            Some(pos)
16863        } else {
16864            None
16865        };
16866
16867        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16868            let url = if let Some(end_pos) = end_position {
16869                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16870            } else {
16871                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16872            };
16873
16874            if let Some(url) = url {
16875                cx.update(|window, cx| {
16876                    if parse_zed_link(&url, cx).is_some() {
16877                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16878                    } else {
16879                        cx.open_url(&url);
16880                    }
16881                })?;
16882            }
16883
16884            anyhow::Ok(())
16885        });
16886
16887        url_finder.detach();
16888    }
16889
16890    pub fn open_selected_filename(
16891        &mut self,
16892        _: &OpenSelectedFilename,
16893        window: &mut Window,
16894        cx: &mut Context<Self>,
16895    ) {
16896        let Some(workspace) = self.workspace() else {
16897            return;
16898        };
16899
16900        let position = self.selections.newest_anchor().head();
16901
16902        let Some((buffer, buffer_position)) =
16903            self.buffer.read(cx).text_anchor_for_position(position, cx)
16904        else {
16905            return;
16906        };
16907
16908        let project = self.project.clone();
16909
16910        cx.spawn_in(window, async move |_, cx| {
16911            let result = find_file(&buffer, project, buffer_position, cx).await;
16912
16913            if let Some((_, path)) = result {
16914                workspace
16915                    .update_in(cx, |workspace, window, cx| {
16916                        workspace.open_resolved_path(path, window, cx)
16917                    })?
16918                    .await?;
16919            }
16920            anyhow::Ok(())
16921        })
16922        .detach();
16923    }
16924
16925    pub(crate) fn navigate_to_hover_links(
16926        &mut self,
16927        kind: Option<GotoDefinitionKind>,
16928        definitions: Vec<HoverLink>,
16929        split: bool,
16930        window: &mut Window,
16931        cx: &mut Context<Editor>,
16932    ) -> Task<Result<Navigated>> {
16933        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16934        let mut first_url_or_file = None;
16935        let definitions: Vec<_> = definitions
16936            .into_iter()
16937            .filter_map(|def| match def {
16938                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16939                HoverLink::InlayHint(lsp_location, server_id) => {
16940                    let computation =
16941                        self.compute_target_location(lsp_location, server_id, window, cx);
16942                    Some(cx.background_spawn(computation))
16943                }
16944                HoverLink::Url(url) => {
16945                    first_url_or_file = Some(Either::Left(url));
16946                    None
16947                }
16948                HoverLink::File(path) => {
16949                    first_url_or_file = Some(Either::Right(path));
16950                    None
16951                }
16952            })
16953            .collect();
16954
16955        let workspace = self.workspace();
16956
16957        cx.spawn_in(window, async move |editor, cx| {
16958            let locations: Vec<Location> = future::join_all(definitions)
16959                .await
16960                .into_iter()
16961                .filter_map(|location| location.transpose())
16962                .collect::<Result<_>>()
16963                .context("location tasks")?;
16964            let mut locations = cx.update(|_, cx| {
16965                locations
16966                    .into_iter()
16967                    .map(|location| {
16968                        let buffer = location.buffer.read(cx);
16969                        (location.buffer, location.range.to_point(buffer))
16970                    })
16971                    .into_group_map()
16972            })?;
16973            let mut num_locations = 0;
16974            for ranges in locations.values_mut() {
16975                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16976                ranges.dedup();
16977                num_locations += ranges.len();
16978            }
16979
16980            if num_locations > 1 {
16981                let Some(workspace) = workspace else {
16982                    return Ok(Navigated::No);
16983                };
16984
16985                let tab_kind = match kind {
16986                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16987                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16988                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16989                    Some(GotoDefinitionKind::Type) => "Types",
16990                };
16991                let title = editor
16992                    .update_in(cx, |_, _, cx| {
16993                        let target = locations
16994                            .iter()
16995                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16996                            .map(|(buffer, location)| {
16997                                buffer
16998                                    .read(cx)
16999                                    .text_for_range(location.clone())
17000                                    .collect::<String>()
17001                            })
17002                            .filter(|text| !text.contains('\n'))
17003                            .unique()
17004                            .take(3)
17005                            .join(", ");
17006                        if target.is_empty() {
17007                            tab_kind.to_owned()
17008                        } else {
17009                            format!("{tab_kind} for {target}")
17010                        }
17011                    })
17012                    .context("buffer title")?;
17013
17014                let opened = workspace
17015                    .update_in(cx, |workspace, window, cx| {
17016                        Self::open_locations_in_multibuffer(
17017                            workspace,
17018                            locations,
17019                            title,
17020                            split,
17021                            MultibufferSelectionMode::First,
17022                            window,
17023                            cx,
17024                        )
17025                    })
17026                    .is_ok();
17027
17028                anyhow::Ok(Navigated::from_bool(opened))
17029            } else if num_locations == 0 {
17030                // If there is one url or file, open it directly
17031                match first_url_or_file {
17032                    Some(Either::Left(url)) => {
17033                        cx.update(|_, cx| cx.open_url(&url))?;
17034                        Ok(Navigated::Yes)
17035                    }
17036                    Some(Either::Right(path)) => {
17037                        let Some(workspace) = workspace else {
17038                            return Ok(Navigated::No);
17039                        };
17040
17041                        workspace
17042                            .update_in(cx, |workspace, window, cx| {
17043                                workspace.open_resolved_path(path, window, cx)
17044                            })?
17045                            .await?;
17046                        Ok(Navigated::Yes)
17047                    }
17048                    None => Ok(Navigated::No),
17049                }
17050            } else {
17051                let Some(workspace) = workspace else {
17052                    return Ok(Navigated::No);
17053                };
17054
17055                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17056                let target_range = target_ranges.first().unwrap().clone();
17057
17058                editor.update_in(cx, |editor, window, cx| {
17059                    let range = target_range.to_point(target_buffer.read(cx));
17060                    let range = editor.range_for_match(&range);
17061                    let range = collapse_multiline_range(range);
17062
17063                    if !split
17064                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17065                    {
17066                        editor.go_to_singleton_buffer_range(range, window, cx);
17067                    } else {
17068                        let pane = workspace.read(cx).active_pane().clone();
17069                        window.defer(cx, move |window, cx| {
17070                            let target_editor: Entity<Self> =
17071                                workspace.update(cx, |workspace, cx| {
17072                                    let pane = if split {
17073                                        workspace.adjacent_pane(window, cx)
17074                                    } else {
17075                                        workspace.active_pane().clone()
17076                                    };
17077
17078                                    workspace.open_project_item(
17079                                        pane,
17080                                        target_buffer.clone(),
17081                                        true,
17082                                        true,
17083                                        window,
17084                                        cx,
17085                                    )
17086                                });
17087                            target_editor.update(cx, |target_editor, cx| {
17088                                // When selecting a definition in a different buffer, disable the nav history
17089                                // to avoid creating a history entry at the previous cursor location.
17090                                pane.update(cx, |pane, _| pane.disable_history());
17091                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17092                                pane.update(cx, |pane, _| pane.enable_history());
17093                            });
17094                        });
17095                    }
17096                    Navigated::Yes
17097                })
17098            }
17099        })
17100    }
17101
17102    fn compute_target_location(
17103        &self,
17104        lsp_location: lsp::Location,
17105        server_id: LanguageServerId,
17106        window: &mut Window,
17107        cx: &mut Context<Self>,
17108    ) -> Task<anyhow::Result<Option<Location>>> {
17109        let Some(project) = self.project.clone() else {
17110            return Task::ready(Ok(None));
17111        };
17112
17113        cx.spawn_in(window, async move |editor, cx| {
17114            let location_task = editor.update(cx, |_, cx| {
17115                project.update(cx, |project, cx| {
17116                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17117                })
17118            })?;
17119            let location = Some({
17120                let target_buffer_handle = location_task.await.context("open local buffer")?;
17121                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17122                    let target_start = target_buffer
17123                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17124                    let target_end = target_buffer
17125                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17126                    target_buffer.anchor_after(target_start)
17127                        ..target_buffer.anchor_before(target_end)
17128                })?;
17129                Location {
17130                    buffer: target_buffer_handle,
17131                    range,
17132                }
17133            });
17134            Ok(location)
17135        })
17136    }
17137
17138    fn go_to_next_reference(
17139        &mut self,
17140        _: &GoToNextReference,
17141        window: &mut Window,
17142        cx: &mut Context<Self>,
17143    ) {
17144        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17145        if let Some(task) = task {
17146            task.detach();
17147        };
17148    }
17149
17150    fn go_to_prev_reference(
17151        &mut self,
17152        _: &GoToPreviousReference,
17153        window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17157        if let Some(task) = task {
17158            task.detach();
17159        };
17160    }
17161
17162    pub fn go_to_reference_before_or_after_position(
17163        &mut self,
17164        direction: Direction,
17165        count: usize,
17166        window: &mut Window,
17167        cx: &mut Context<Self>,
17168    ) -> Option<Task<Result<()>>> {
17169        let selection = self.selections.newest_anchor();
17170        let head = selection.head();
17171
17172        let multi_buffer = self.buffer.read(cx);
17173
17174        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17175        let workspace = self.workspace()?;
17176        let project = workspace.read(cx).project().clone();
17177        let references =
17178            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17179        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17180            let Some(locations) = references.await? else {
17181                return Ok(());
17182            };
17183
17184            if locations.is_empty() {
17185                // totally normal - the cursor may be on something which is not
17186                // a symbol (e.g. a keyword)
17187                log::info!("no references found under cursor");
17188                return Ok(());
17189            }
17190
17191            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17192
17193            let (locations, current_location_index) =
17194                multi_buffer.update(cx, |multi_buffer, cx| {
17195                    let mut locations = locations
17196                        .into_iter()
17197                        .filter_map(|loc| {
17198                            let start = multi_buffer.buffer_anchor_to_anchor(
17199                                &loc.buffer,
17200                                loc.range.start,
17201                                cx,
17202                            )?;
17203                            let end = multi_buffer.buffer_anchor_to_anchor(
17204                                &loc.buffer,
17205                                loc.range.end,
17206                                cx,
17207                            )?;
17208                            Some(start..end)
17209                        })
17210                        .collect::<Vec<_>>();
17211
17212                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17213                    // There is an O(n) implementation, but given this list will be
17214                    // small (usually <100 items), the extra O(log(n)) factor isn't
17215                    // worth the (surprisingly large amount of) extra complexity.
17216                    locations
17217                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17218
17219                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17220
17221                    let current_location_index = locations.iter().position(|loc| {
17222                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17223                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17224                    });
17225
17226                    (locations, current_location_index)
17227                })?;
17228
17229            let Some(current_location_index) = current_location_index else {
17230                // This indicates something has gone wrong, because we already
17231                // handle the "no references" case above
17232                log::error!(
17233                    "failed to find current reference under cursor. Total references: {}",
17234                    locations.len()
17235                );
17236                return Ok(());
17237            };
17238
17239            let destination_location_index = match direction {
17240                Direction::Next => (current_location_index + count) % locations.len(),
17241                Direction::Prev => {
17242                    (current_location_index + locations.len() - count % locations.len())
17243                        % locations.len()
17244                }
17245            };
17246
17247            // TODO(cameron): is this needed?
17248            // the thinking is to avoid "jumping to the current location" (avoid
17249            // polluting "jumplist" in vim terms)
17250            if current_location_index == destination_location_index {
17251                return Ok(());
17252            }
17253
17254            let Range { start, end } = locations[destination_location_index];
17255
17256            editor.update_in(cx, |editor, window, cx| {
17257                let effects = SelectionEffects::default();
17258
17259                editor.unfold_ranges(&[start..end], false, false, cx);
17260                editor.change_selections(effects, window, cx, |s| {
17261                    s.select_ranges([start..start]);
17262                });
17263            })?;
17264
17265            Ok(())
17266        }))
17267    }
17268
17269    pub fn find_all_references(
17270        &mut self,
17271        _: &FindAllReferences,
17272        window: &mut Window,
17273        cx: &mut Context<Self>,
17274    ) -> Option<Task<Result<Navigated>>> {
17275        let selection = self
17276            .selections
17277            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17278        let multi_buffer = self.buffer.read(cx);
17279        let head = selection.head();
17280
17281        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17282        let head_anchor = multi_buffer_snapshot.anchor_at(
17283            head,
17284            if head < selection.tail() {
17285                Bias::Right
17286            } else {
17287                Bias::Left
17288            },
17289        );
17290
17291        match self
17292            .find_all_references_task_sources
17293            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17294        {
17295            Ok(_) => {
17296                log::info!(
17297                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17298                );
17299                return None;
17300            }
17301            Err(i) => {
17302                self.find_all_references_task_sources.insert(i, head_anchor);
17303            }
17304        }
17305
17306        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17307        let workspace = self.workspace()?;
17308        let project = workspace.read(cx).project().clone();
17309        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17310        Some(cx.spawn_in(window, async move |editor, cx| {
17311            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17312                if let Ok(i) = editor
17313                    .find_all_references_task_sources
17314                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17315                {
17316                    editor.find_all_references_task_sources.remove(i);
17317                }
17318            });
17319
17320            let Some(locations) = references.await? else {
17321                return anyhow::Ok(Navigated::No);
17322            };
17323            let mut locations = cx.update(|_, cx| {
17324                locations
17325                    .into_iter()
17326                    .map(|location| {
17327                        let buffer = location.buffer.read(cx);
17328                        (location.buffer, location.range.to_point(buffer))
17329                    })
17330                    .into_group_map()
17331            })?;
17332            if locations.is_empty() {
17333                return anyhow::Ok(Navigated::No);
17334            }
17335            for ranges in locations.values_mut() {
17336                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17337                ranges.dedup();
17338            }
17339
17340            workspace.update_in(cx, |workspace, window, cx| {
17341                let target = locations
17342                    .iter()
17343                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17344                    .map(|(buffer, location)| {
17345                        buffer
17346                            .read(cx)
17347                            .text_for_range(location.clone())
17348                            .collect::<String>()
17349                    })
17350                    .filter(|text| !text.contains('\n'))
17351                    .unique()
17352                    .take(3)
17353                    .join(", ");
17354                let title = if target.is_empty() {
17355                    "References".to_owned()
17356                } else {
17357                    format!("References to {target}")
17358                };
17359                Self::open_locations_in_multibuffer(
17360                    workspace,
17361                    locations,
17362                    title,
17363                    false,
17364                    MultibufferSelectionMode::First,
17365                    window,
17366                    cx,
17367                );
17368                Navigated::Yes
17369            })
17370        }))
17371    }
17372
17373    /// Opens a multibuffer with the given project locations in it
17374    pub fn open_locations_in_multibuffer(
17375        workspace: &mut Workspace,
17376        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17377        title: String,
17378        split: bool,
17379        multibuffer_selection_mode: MultibufferSelectionMode,
17380        window: &mut Window,
17381        cx: &mut Context<Workspace>,
17382    ) {
17383        if locations.is_empty() {
17384            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17385            return;
17386        }
17387
17388        let capability = workspace.project().read(cx).capability();
17389        let mut ranges = <Vec<Range<Anchor>>>::new();
17390
17391        // a key to find existing multibuffer editors with the same set of locations
17392        // to prevent us from opening more and more multibuffer tabs for searches and the like
17393        let mut key = (title.clone(), vec![]);
17394        let excerpt_buffer = cx.new(|cx| {
17395            let key = &mut key.1;
17396            let mut multibuffer = MultiBuffer::new(capability);
17397            for (buffer, mut ranges_for_buffer) in locations {
17398                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17399                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17400                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17401                    PathKey::for_buffer(&buffer, cx),
17402                    buffer.clone(),
17403                    ranges_for_buffer,
17404                    multibuffer_context_lines(cx),
17405                    cx,
17406                );
17407                ranges.extend(new_ranges)
17408            }
17409
17410            multibuffer.with_title(title)
17411        });
17412        let existing = workspace.active_pane().update(cx, |pane, cx| {
17413            pane.items()
17414                .filter_map(|item| item.downcast::<Editor>())
17415                .find(|editor| {
17416                    editor
17417                        .read(cx)
17418                        .lookup_key
17419                        .as_ref()
17420                        .and_then(|it| {
17421                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17422                        })
17423                        .is_some_and(|it| *it == key)
17424                })
17425        });
17426        let editor = existing.unwrap_or_else(|| {
17427            cx.new(|cx| {
17428                let mut editor = Editor::for_multibuffer(
17429                    excerpt_buffer,
17430                    Some(workspace.project().clone()),
17431                    window,
17432                    cx,
17433                );
17434                editor.lookup_key = Some(Box::new(key));
17435                editor
17436            })
17437        });
17438        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17439            MultibufferSelectionMode::First => {
17440                if let Some(first_range) = ranges.first() {
17441                    editor.change_selections(
17442                        SelectionEffects::no_scroll(),
17443                        window,
17444                        cx,
17445                        |selections| {
17446                            selections.clear_disjoint();
17447                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17448                        },
17449                    );
17450                }
17451                editor.highlight_background::<Self>(
17452                    &ranges,
17453                    |theme| theme.colors().editor_highlighted_line_background,
17454                    cx,
17455                );
17456            }
17457            MultibufferSelectionMode::All => {
17458                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17459                    selections.clear_disjoint();
17460                    selections.select_anchor_ranges(ranges);
17461                });
17462            }
17463        });
17464
17465        let item = Box::new(editor);
17466        let item_id = item.item_id();
17467
17468        if split {
17469            let pane = workspace.adjacent_pane(window, cx);
17470            workspace.add_item(pane, item, None, true, true, window, cx);
17471        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17472            let (preview_item_id, preview_item_idx) =
17473                workspace.active_pane().read_with(cx, |pane, _| {
17474                    (pane.preview_item_id(), pane.preview_item_idx())
17475                });
17476
17477            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17478
17479            if let Some(preview_item_id) = preview_item_id {
17480                workspace.active_pane().update(cx, |pane, cx| {
17481                    pane.remove_item(preview_item_id, false, false, window, cx);
17482                });
17483            }
17484        } else {
17485            workspace.add_item_to_active_pane(item, None, true, window, cx);
17486        }
17487        workspace.active_pane().update(cx, |pane, cx| {
17488            pane.set_preview_item_id(Some(item_id), cx);
17489        });
17490    }
17491
17492    pub fn rename(
17493        &mut self,
17494        _: &Rename,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) -> Option<Task<Result<()>>> {
17498        use language::ToOffset as _;
17499
17500        let provider = self.semantics_provider.clone()?;
17501        let selection = self.selections.newest_anchor().clone();
17502        let (cursor_buffer, cursor_buffer_position) = self
17503            .buffer
17504            .read(cx)
17505            .text_anchor_for_position(selection.head(), cx)?;
17506        let (tail_buffer, cursor_buffer_position_end) = self
17507            .buffer
17508            .read(cx)
17509            .text_anchor_for_position(selection.tail(), cx)?;
17510        if tail_buffer != cursor_buffer {
17511            return None;
17512        }
17513
17514        let snapshot = cursor_buffer.read(cx).snapshot();
17515        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17516        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17517        let prepare_rename = provider
17518            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17519            .unwrap_or_else(|| Task::ready(Ok(None)));
17520        drop(snapshot);
17521
17522        Some(cx.spawn_in(window, async move |this, cx| {
17523            let rename_range = if let Some(range) = prepare_rename.await? {
17524                Some(range)
17525            } else {
17526                this.update(cx, |this, cx| {
17527                    let buffer = this.buffer.read(cx).snapshot(cx);
17528                    let mut buffer_highlights = this
17529                        .document_highlights_for_position(selection.head(), &buffer)
17530                        .filter(|highlight| {
17531                            highlight.start.excerpt_id == selection.head().excerpt_id
17532                                && highlight.end.excerpt_id == selection.head().excerpt_id
17533                        });
17534                    buffer_highlights
17535                        .next()
17536                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17537                })?
17538            };
17539            if let Some(rename_range) = rename_range {
17540                this.update_in(cx, |this, window, cx| {
17541                    let snapshot = cursor_buffer.read(cx).snapshot();
17542                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17543                    let cursor_offset_in_rename_range =
17544                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17545                    let cursor_offset_in_rename_range_end =
17546                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17547
17548                    this.take_rename(false, window, cx);
17549                    let buffer = this.buffer.read(cx).read(cx);
17550                    let cursor_offset = selection.head().to_offset(&buffer);
17551                    let rename_start =
17552                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17553                    let rename_end = rename_start + rename_buffer_range.len();
17554                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17555                    let mut old_highlight_id = None;
17556                    let old_name: Arc<str> = buffer
17557                        .chunks(rename_start..rename_end, true)
17558                        .map(|chunk| {
17559                            if old_highlight_id.is_none() {
17560                                old_highlight_id = chunk.syntax_highlight_id;
17561                            }
17562                            chunk.text
17563                        })
17564                        .collect::<String>()
17565                        .into();
17566
17567                    drop(buffer);
17568
17569                    // Position the selection in the rename editor so that it matches the current selection.
17570                    this.show_local_selections = false;
17571                    let rename_editor = cx.new(|cx| {
17572                        let mut editor = Editor::single_line(window, cx);
17573                        editor.buffer.update(cx, |buffer, cx| {
17574                            buffer.edit(
17575                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17576                                None,
17577                                cx,
17578                            )
17579                        });
17580                        let cursor_offset_in_rename_range =
17581                            MultiBufferOffset(cursor_offset_in_rename_range);
17582                        let cursor_offset_in_rename_range_end =
17583                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17584                        let rename_selection_range = match cursor_offset_in_rename_range
17585                            .cmp(&cursor_offset_in_rename_range_end)
17586                        {
17587                            Ordering::Equal => {
17588                                editor.select_all(&SelectAll, window, cx);
17589                                return editor;
17590                            }
17591                            Ordering::Less => {
17592                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17593                            }
17594                            Ordering::Greater => {
17595                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17596                            }
17597                        };
17598                        if rename_selection_range.end.0 > old_name.len() {
17599                            editor.select_all(&SelectAll, window, cx);
17600                        } else {
17601                            editor.change_selections(Default::default(), window, cx, |s| {
17602                                s.select_ranges([rename_selection_range]);
17603                            });
17604                        }
17605                        editor
17606                    });
17607                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17608                        if e == &EditorEvent::Focused {
17609                            cx.emit(EditorEvent::FocusedIn)
17610                        }
17611                    })
17612                    .detach();
17613
17614                    let write_highlights =
17615                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17616                    let read_highlights =
17617                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17618                    let ranges = write_highlights
17619                        .iter()
17620                        .flat_map(|(_, ranges)| ranges.iter())
17621                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17622                        .cloned()
17623                        .collect();
17624
17625                    this.highlight_text::<Rename>(
17626                        ranges,
17627                        HighlightStyle {
17628                            fade_out: Some(0.6),
17629                            ..Default::default()
17630                        },
17631                        cx,
17632                    );
17633                    let rename_focus_handle = rename_editor.focus_handle(cx);
17634                    window.focus(&rename_focus_handle);
17635                    let block_id = this.insert_blocks(
17636                        [BlockProperties {
17637                            style: BlockStyle::Flex,
17638                            placement: BlockPlacement::Below(range.start),
17639                            height: Some(1),
17640                            render: Arc::new({
17641                                let rename_editor = rename_editor.clone();
17642                                move |cx: &mut BlockContext| {
17643                                    let mut text_style = cx.editor_style.text.clone();
17644                                    if let Some(highlight_style) = old_highlight_id
17645                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17646                                    {
17647                                        text_style = text_style.highlight(highlight_style);
17648                                    }
17649                                    div()
17650                                        .block_mouse_except_scroll()
17651                                        .pl(cx.anchor_x)
17652                                        .child(EditorElement::new(
17653                                            &rename_editor,
17654                                            EditorStyle {
17655                                                background: cx.theme().system().transparent,
17656                                                local_player: cx.editor_style.local_player,
17657                                                text: text_style,
17658                                                scrollbar_width: cx.editor_style.scrollbar_width,
17659                                                syntax: cx.editor_style.syntax.clone(),
17660                                                status: cx.editor_style.status.clone(),
17661                                                inlay_hints_style: HighlightStyle {
17662                                                    font_weight: Some(FontWeight::BOLD),
17663                                                    ..make_inlay_hints_style(cx.app)
17664                                                },
17665                                                edit_prediction_styles: make_suggestion_styles(
17666                                                    cx.app,
17667                                                ),
17668                                                ..EditorStyle::default()
17669                                            },
17670                                        ))
17671                                        .into_any_element()
17672                                }
17673                            }),
17674                            priority: 0,
17675                        }],
17676                        Some(Autoscroll::fit()),
17677                        cx,
17678                    )[0];
17679                    this.pending_rename = Some(RenameState {
17680                        range,
17681                        old_name,
17682                        editor: rename_editor,
17683                        block_id,
17684                    });
17685                })?;
17686            }
17687
17688            Ok(())
17689        }))
17690    }
17691
17692    pub fn confirm_rename(
17693        &mut self,
17694        _: &ConfirmRename,
17695        window: &mut Window,
17696        cx: &mut Context<Self>,
17697    ) -> Option<Task<Result<()>>> {
17698        let rename = self.take_rename(false, window, cx)?;
17699        let workspace = self.workspace()?.downgrade();
17700        let (buffer, start) = self
17701            .buffer
17702            .read(cx)
17703            .text_anchor_for_position(rename.range.start, cx)?;
17704        let (end_buffer, _) = self
17705            .buffer
17706            .read(cx)
17707            .text_anchor_for_position(rename.range.end, cx)?;
17708        if buffer != end_buffer {
17709            return None;
17710        }
17711
17712        let old_name = rename.old_name;
17713        let new_name = rename.editor.read(cx).text(cx);
17714
17715        let rename = self.semantics_provider.as_ref()?.perform_rename(
17716            &buffer,
17717            start,
17718            new_name.clone(),
17719            cx,
17720        )?;
17721
17722        Some(cx.spawn_in(window, async move |editor, cx| {
17723            let project_transaction = rename.await?;
17724            Self::open_project_transaction(
17725                &editor,
17726                workspace,
17727                project_transaction,
17728                format!("Rename: {}{}", old_name, new_name),
17729                cx,
17730            )
17731            .await?;
17732
17733            editor.update(cx, |editor, cx| {
17734                editor.refresh_document_highlights(cx);
17735            })?;
17736            Ok(())
17737        }))
17738    }
17739
17740    fn take_rename(
17741        &mut self,
17742        moving_cursor: bool,
17743        window: &mut Window,
17744        cx: &mut Context<Self>,
17745    ) -> Option<RenameState> {
17746        let rename = self.pending_rename.take()?;
17747        if rename.editor.focus_handle(cx).is_focused(window) {
17748            window.focus(&self.focus_handle);
17749        }
17750
17751        self.remove_blocks(
17752            [rename.block_id].into_iter().collect(),
17753            Some(Autoscroll::fit()),
17754            cx,
17755        );
17756        self.clear_highlights::<Rename>(cx);
17757        self.show_local_selections = true;
17758
17759        if moving_cursor {
17760            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17761                editor
17762                    .selections
17763                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17764                    .head()
17765            });
17766
17767            // Update the selection to match the position of the selection inside
17768            // the rename editor.
17769            let snapshot = self.buffer.read(cx).read(cx);
17770            let rename_range = rename.range.to_offset(&snapshot);
17771            let cursor_in_editor = snapshot
17772                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17773                .min(rename_range.end);
17774            drop(snapshot);
17775
17776            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17777                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17778            });
17779        } else {
17780            self.refresh_document_highlights(cx);
17781        }
17782
17783        Some(rename)
17784    }
17785
17786    pub fn pending_rename(&self) -> Option<&RenameState> {
17787        self.pending_rename.as_ref()
17788    }
17789
17790    fn format(
17791        &mut self,
17792        _: &Format,
17793        window: &mut Window,
17794        cx: &mut Context<Self>,
17795    ) -> Option<Task<Result<()>>> {
17796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17797
17798        let project = match &self.project {
17799            Some(project) => project.clone(),
17800            None => return None,
17801        };
17802
17803        Some(self.perform_format(
17804            project,
17805            FormatTrigger::Manual,
17806            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17807            window,
17808            cx,
17809        ))
17810    }
17811
17812    fn format_selections(
17813        &mut self,
17814        _: &FormatSelections,
17815        window: &mut Window,
17816        cx: &mut Context<Self>,
17817    ) -> Option<Task<Result<()>>> {
17818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17819
17820        let project = match &self.project {
17821            Some(project) => project.clone(),
17822            None => return None,
17823        };
17824
17825        let ranges = self
17826            .selections
17827            .all_adjusted(&self.display_snapshot(cx))
17828            .into_iter()
17829            .map(|selection| selection.range())
17830            .collect_vec();
17831
17832        Some(self.perform_format(
17833            project,
17834            FormatTrigger::Manual,
17835            FormatTarget::Ranges(ranges),
17836            window,
17837            cx,
17838        ))
17839    }
17840
17841    fn perform_format(
17842        &mut self,
17843        project: Entity<Project>,
17844        trigger: FormatTrigger,
17845        target: FormatTarget,
17846        window: &mut Window,
17847        cx: &mut Context<Self>,
17848    ) -> Task<Result<()>> {
17849        let buffer = self.buffer.clone();
17850        let (buffers, target) = match target {
17851            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17852            FormatTarget::Ranges(selection_ranges) => {
17853                let multi_buffer = buffer.read(cx);
17854                let snapshot = multi_buffer.read(cx);
17855                let mut buffers = HashSet::default();
17856                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17857                    BTreeMap::new();
17858                for selection_range in selection_ranges {
17859                    for (buffer, buffer_range, _) in
17860                        snapshot.range_to_buffer_ranges(selection_range)
17861                    {
17862                        let buffer_id = buffer.remote_id();
17863                        let start = buffer.anchor_before(buffer_range.start);
17864                        let end = buffer.anchor_after(buffer_range.end);
17865                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17866                        buffer_id_to_ranges
17867                            .entry(buffer_id)
17868                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17869                            .or_insert_with(|| vec![start..end]);
17870                    }
17871                }
17872                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17873            }
17874        };
17875
17876        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17877        let selections_prev = transaction_id_prev
17878            .and_then(|transaction_id_prev| {
17879                // default to selections as they were after the last edit, if we have them,
17880                // instead of how they are now.
17881                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17882                // will take you back to where you made the last edit, instead of staying where you scrolled
17883                self.selection_history
17884                    .transaction(transaction_id_prev)
17885                    .map(|t| t.0.clone())
17886            })
17887            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17888
17889        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17890        let format = project.update(cx, |project, cx| {
17891            project.format(buffers, target, true, trigger, cx)
17892        });
17893
17894        cx.spawn_in(window, async move |editor, cx| {
17895            let transaction = futures::select_biased! {
17896                transaction = format.log_err().fuse() => transaction,
17897                () = timeout => {
17898                    log::warn!("timed out waiting for formatting");
17899                    None
17900                }
17901            };
17902
17903            buffer
17904                .update(cx, |buffer, cx| {
17905                    if let Some(transaction) = transaction
17906                        && !buffer.is_singleton()
17907                    {
17908                        buffer.push_transaction(&transaction.0, cx);
17909                    }
17910                    cx.notify();
17911                })
17912                .ok();
17913
17914            if let Some(transaction_id_now) =
17915                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17916            {
17917                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17918                if has_new_transaction {
17919                    _ = editor.update(cx, |editor, _| {
17920                        editor
17921                            .selection_history
17922                            .insert_transaction(transaction_id_now, selections_prev);
17923                    });
17924                }
17925            }
17926
17927            Ok(())
17928        })
17929    }
17930
17931    fn organize_imports(
17932        &mut self,
17933        _: &OrganizeImports,
17934        window: &mut Window,
17935        cx: &mut Context<Self>,
17936    ) -> Option<Task<Result<()>>> {
17937        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17938        let project = match &self.project {
17939            Some(project) => project.clone(),
17940            None => return None,
17941        };
17942        Some(self.perform_code_action_kind(
17943            project,
17944            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17945            window,
17946            cx,
17947        ))
17948    }
17949
17950    fn perform_code_action_kind(
17951        &mut self,
17952        project: Entity<Project>,
17953        kind: CodeActionKind,
17954        window: &mut Window,
17955        cx: &mut Context<Self>,
17956    ) -> Task<Result<()>> {
17957        let buffer = self.buffer.clone();
17958        let buffers = buffer.read(cx).all_buffers();
17959        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17960        let apply_action = project.update(cx, |project, cx| {
17961            project.apply_code_action_kind(buffers, kind, true, cx)
17962        });
17963        cx.spawn_in(window, async move |_, cx| {
17964            let transaction = futures::select_biased! {
17965                () = timeout => {
17966                    log::warn!("timed out waiting for executing code action");
17967                    None
17968                }
17969                transaction = apply_action.log_err().fuse() => transaction,
17970            };
17971            buffer
17972                .update(cx, |buffer, cx| {
17973                    // check if we need this
17974                    if let Some(transaction) = transaction
17975                        && !buffer.is_singleton()
17976                    {
17977                        buffer.push_transaction(&transaction.0, cx);
17978                    }
17979                    cx.notify();
17980                })
17981                .ok();
17982            Ok(())
17983        })
17984    }
17985
17986    pub fn restart_language_server(
17987        &mut self,
17988        _: &RestartLanguageServer,
17989        _: &mut Window,
17990        cx: &mut Context<Self>,
17991    ) {
17992        if let Some(project) = self.project.clone() {
17993            self.buffer.update(cx, |multi_buffer, cx| {
17994                project.update(cx, |project, cx| {
17995                    project.restart_language_servers_for_buffers(
17996                        multi_buffer.all_buffers().into_iter().collect(),
17997                        HashSet::default(),
17998                        cx,
17999                    );
18000                });
18001            })
18002        }
18003    }
18004
18005    pub fn stop_language_server(
18006        &mut self,
18007        _: &StopLanguageServer,
18008        _: &mut Window,
18009        cx: &mut Context<Self>,
18010    ) {
18011        if let Some(project) = self.project.clone() {
18012            self.buffer.update(cx, |multi_buffer, cx| {
18013                project.update(cx, |project, cx| {
18014                    project.stop_language_servers_for_buffers(
18015                        multi_buffer.all_buffers().into_iter().collect(),
18016                        HashSet::default(),
18017                        cx,
18018                    );
18019                });
18020            });
18021            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18022        }
18023    }
18024
18025    fn cancel_language_server_work(
18026        workspace: &mut Workspace,
18027        _: &actions::CancelLanguageServerWork,
18028        _: &mut Window,
18029        cx: &mut Context<Workspace>,
18030    ) {
18031        let project = workspace.project();
18032        let buffers = workspace
18033            .active_item(cx)
18034            .and_then(|item| item.act_as::<Editor>(cx))
18035            .map_or(HashSet::default(), |editor| {
18036                editor.read(cx).buffer.read(cx).all_buffers()
18037            });
18038        project.update(cx, |project, cx| {
18039            project.cancel_language_server_work_for_buffers(buffers, cx);
18040        });
18041    }
18042
18043    fn show_character_palette(
18044        &mut self,
18045        _: &ShowCharacterPalette,
18046        window: &mut Window,
18047        _: &mut Context<Self>,
18048    ) {
18049        window.show_character_palette();
18050    }
18051
18052    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18053        if !self.diagnostics_enabled() {
18054            return;
18055        }
18056
18057        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18058            let buffer = self.buffer.read(cx).snapshot(cx);
18059            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18060            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18061            let is_valid = buffer
18062                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18063                .any(|entry| {
18064                    entry.diagnostic.is_primary
18065                        && !entry.range.is_empty()
18066                        && entry.range.start == primary_range_start
18067                        && entry.diagnostic.message == active_diagnostics.active_message
18068                });
18069
18070            if !is_valid {
18071                self.dismiss_diagnostics(cx);
18072            }
18073        }
18074    }
18075
18076    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18077        match &self.active_diagnostics {
18078            ActiveDiagnostic::Group(group) => Some(group),
18079            _ => None,
18080        }
18081    }
18082
18083    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18084        if !self.diagnostics_enabled() {
18085            return;
18086        }
18087        self.dismiss_diagnostics(cx);
18088        self.active_diagnostics = ActiveDiagnostic::All;
18089    }
18090
18091    fn activate_diagnostics(
18092        &mut self,
18093        buffer_id: BufferId,
18094        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18095        window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18099            return;
18100        }
18101        self.dismiss_diagnostics(cx);
18102        let snapshot = self.snapshot(window, cx);
18103        let buffer = self.buffer.read(cx).snapshot(cx);
18104        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18105            return;
18106        };
18107
18108        let diagnostic_group = buffer
18109            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18110            .collect::<Vec<_>>();
18111
18112        let language_registry = self
18113            .project()
18114            .map(|project| project.read(cx).languages().clone());
18115
18116        let blocks = renderer.render_group(
18117            diagnostic_group,
18118            buffer_id,
18119            snapshot,
18120            cx.weak_entity(),
18121            language_registry,
18122            cx,
18123        );
18124
18125        let blocks = self.display_map.update(cx, |display_map, cx| {
18126            display_map.insert_blocks(blocks, cx).into_iter().collect()
18127        });
18128        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18129            active_range: buffer.anchor_before(diagnostic.range.start)
18130                ..buffer.anchor_after(diagnostic.range.end),
18131            active_message: diagnostic.diagnostic.message.clone(),
18132            group_id: diagnostic.diagnostic.group_id,
18133            blocks,
18134        });
18135        cx.notify();
18136    }
18137
18138    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18139        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18140            return;
18141        };
18142
18143        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18144        if let ActiveDiagnostic::Group(group) = prev {
18145            self.display_map.update(cx, |display_map, cx| {
18146                display_map.remove_blocks(group.blocks, cx);
18147            });
18148            cx.notify();
18149        }
18150    }
18151
18152    /// Disable inline diagnostics rendering for this editor.
18153    pub fn disable_inline_diagnostics(&mut self) {
18154        self.inline_diagnostics_enabled = false;
18155        self.inline_diagnostics_update = Task::ready(());
18156        self.inline_diagnostics.clear();
18157    }
18158
18159    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18160        self.diagnostics_enabled = false;
18161        self.dismiss_diagnostics(cx);
18162        self.inline_diagnostics_update = Task::ready(());
18163        self.inline_diagnostics.clear();
18164    }
18165
18166    pub fn disable_word_completions(&mut self) {
18167        self.word_completions_enabled = false;
18168    }
18169
18170    pub fn diagnostics_enabled(&self) -> bool {
18171        self.diagnostics_enabled && self.mode.is_full()
18172    }
18173
18174    pub fn inline_diagnostics_enabled(&self) -> bool {
18175        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18176    }
18177
18178    pub fn show_inline_diagnostics(&self) -> bool {
18179        self.show_inline_diagnostics
18180    }
18181
18182    pub fn toggle_inline_diagnostics(
18183        &mut self,
18184        _: &ToggleInlineDiagnostics,
18185        window: &mut Window,
18186        cx: &mut Context<Editor>,
18187    ) {
18188        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18189        self.refresh_inline_diagnostics(false, window, cx);
18190    }
18191
18192    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18193        self.diagnostics_max_severity = severity;
18194        self.display_map.update(cx, |display_map, _| {
18195            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18196        });
18197    }
18198
18199    pub fn toggle_diagnostics(
18200        &mut self,
18201        _: &ToggleDiagnostics,
18202        window: &mut Window,
18203        cx: &mut Context<Editor>,
18204    ) {
18205        if !self.diagnostics_enabled() {
18206            return;
18207        }
18208
18209        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18210            EditorSettings::get_global(cx)
18211                .diagnostics_max_severity
18212                .filter(|severity| severity != &DiagnosticSeverity::Off)
18213                .unwrap_or(DiagnosticSeverity::Hint)
18214        } else {
18215            DiagnosticSeverity::Off
18216        };
18217        self.set_max_diagnostics_severity(new_severity, cx);
18218        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18219            self.active_diagnostics = ActiveDiagnostic::None;
18220            self.inline_diagnostics_update = Task::ready(());
18221            self.inline_diagnostics.clear();
18222        } else {
18223            self.refresh_inline_diagnostics(false, window, cx);
18224        }
18225
18226        cx.notify();
18227    }
18228
18229    pub fn toggle_minimap(
18230        &mut self,
18231        _: &ToggleMinimap,
18232        window: &mut Window,
18233        cx: &mut Context<Editor>,
18234    ) {
18235        if self.supports_minimap(cx) {
18236            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18237        }
18238    }
18239
18240    fn refresh_inline_diagnostics(
18241        &mut self,
18242        debounce: bool,
18243        window: &mut Window,
18244        cx: &mut Context<Self>,
18245    ) {
18246        let max_severity = ProjectSettings::get_global(cx)
18247            .diagnostics
18248            .inline
18249            .max_severity
18250            .unwrap_or(self.diagnostics_max_severity);
18251
18252        if !self.inline_diagnostics_enabled()
18253            || !self.diagnostics_enabled()
18254            || !self.show_inline_diagnostics
18255            || max_severity == DiagnosticSeverity::Off
18256        {
18257            self.inline_diagnostics_update = Task::ready(());
18258            self.inline_diagnostics.clear();
18259            return;
18260        }
18261
18262        let debounce_ms = ProjectSettings::get_global(cx)
18263            .diagnostics
18264            .inline
18265            .update_debounce_ms;
18266        let debounce = if debounce && debounce_ms > 0 {
18267            Some(Duration::from_millis(debounce_ms))
18268        } else {
18269            None
18270        };
18271        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18272            if let Some(debounce) = debounce {
18273                cx.background_executor().timer(debounce).await;
18274            }
18275            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18276                editor
18277                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18278                    .ok()
18279            }) else {
18280                return;
18281            };
18282
18283            let new_inline_diagnostics = cx
18284                .background_spawn(async move {
18285                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18286                    for diagnostic_entry in
18287                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18288                    {
18289                        let message = diagnostic_entry
18290                            .diagnostic
18291                            .message
18292                            .split_once('\n')
18293                            .map(|(line, _)| line)
18294                            .map(SharedString::new)
18295                            .unwrap_or_else(|| {
18296                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18297                            });
18298                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18299                        let (Ok(i) | Err(i)) = inline_diagnostics
18300                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18301                        inline_diagnostics.insert(
18302                            i,
18303                            (
18304                                start_anchor,
18305                                InlineDiagnostic {
18306                                    message,
18307                                    group_id: diagnostic_entry.diagnostic.group_id,
18308                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18309                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18310                                    severity: diagnostic_entry.diagnostic.severity,
18311                                },
18312                            ),
18313                        );
18314                    }
18315                    inline_diagnostics
18316                })
18317                .await;
18318
18319            editor
18320                .update(cx, |editor, cx| {
18321                    editor.inline_diagnostics = new_inline_diagnostics;
18322                    cx.notify();
18323                })
18324                .ok();
18325        });
18326    }
18327
18328    fn pull_diagnostics(
18329        &mut self,
18330        buffer_id: Option<BufferId>,
18331        window: &Window,
18332        cx: &mut Context<Self>,
18333    ) -> Option<()> {
18334        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18335            return None;
18336        }
18337        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18338            .diagnostics
18339            .lsp_pull_diagnostics;
18340        if !pull_diagnostics_settings.enabled {
18341            return None;
18342        }
18343        let project = self.project()?.downgrade();
18344        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18345        let mut buffers = self.buffer.read(cx).all_buffers();
18346        buffers.retain(|buffer| {
18347            let buffer_id_to_retain = buffer.read(cx).remote_id();
18348            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18349                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18350        });
18351        if buffers.is_empty() {
18352            self.pull_diagnostics_task = Task::ready(());
18353            return None;
18354        }
18355
18356        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18357            cx.background_executor().timer(debounce).await;
18358
18359            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18360                buffers
18361                    .into_iter()
18362                    .filter_map(|buffer| {
18363                        project
18364                            .update(cx, |project, cx| {
18365                                project.lsp_store().update(cx, |lsp_store, cx| {
18366                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18367                                })
18368                            })
18369                            .ok()
18370                    })
18371                    .collect::<FuturesUnordered<_>>()
18372            }) else {
18373                return;
18374            };
18375
18376            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18377                match pull_task {
18378                    Ok(()) => {
18379                        if editor
18380                            .update_in(cx, |editor, window, cx| {
18381                                editor.update_diagnostics_state(window, cx);
18382                            })
18383                            .is_err()
18384                        {
18385                            return;
18386                        }
18387                    }
18388                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18389                }
18390            }
18391        });
18392
18393        Some(())
18394    }
18395
18396    pub fn set_selections_from_remote(
18397        &mut self,
18398        selections: Vec<Selection<Anchor>>,
18399        pending_selection: Option<Selection<Anchor>>,
18400        window: &mut Window,
18401        cx: &mut Context<Self>,
18402    ) {
18403        let old_cursor_position = self.selections.newest_anchor().head();
18404        self.selections
18405            .change_with(&self.display_snapshot(cx), |s| {
18406                s.select_anchors(selections);
18407                if let Some(pending_selection) = pending_selection {
18408                    s.set_pending(pending_selection, SelectMode::Character);
18409                } else {
18410                    s.clear_pending();
18411                }
18412            });
18413        self.selections_did_change(
18414            false,
18415            &old_cursor_position,
18416            SelectionEffects::default(),
18417            window,
18418            cx,
18419        );
18420    }
18421
18422    pub fn transact(
18423        &mut self,
18424        window: &mut Window,
18425        cx: &mut Context<Self>,
18426        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18427    ) -> Option<TransactionId> {
18428        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18429            this.start_transaction_at(Instant::now(), window, cx);
18430            update(this, window, cx);
18431            this.end_transaction_at(Instant::now(), cx)
18432        })
18433    }
18434
18435    pub fn start_transaction_at(
18436        &mut self,
18437        now: Instant,
18438        window: &mut Window,
18439        cx: &mut Context<Self>,
18440    ) -> Option<TransactionId> {
18441        self.end_selection(window, cx);
18442        if let Some(tx_id) = self
18443            .buffer
18444            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18445        {
18446            self.selection_history
18447                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18448            cx.emit(EditorEvent::TransactionBegun {
18449                transaction_id: tx_id,
18450            });
18451            Some(tx_id)
18452        } else {
18453            None
18454        }
18455    }
18456
18457    pub fn end_transaction_at(
18458        &mut self,
18459        now: Instant,
18460        cx: &mut Context<Self>,
18461    ) -> Option<TransactionId> {
18462        if let Some(transaction_id) = self
18463            .buffer
18464            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18465        {
18466            if let Some((_, end_selections)) =
18467                self.selection_history.transaction_mut(transaction_id)
18468            {
18469                *end_selections = Some(self.selections.disjoint_anchors_arc());
18470            } else {
18471                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18472            }
18473
18474            cx.emit(EditorEvent::Edited { transaction_id });
18475            Some(transaction_id)
18476        } else {
18477            None
18478        }
18479    }
18480
18481    pub fn modify_transaction_selection_history(
18482        &mut self,
18483        transaction_id: TransactionId,
18484        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18485    ) -> bool {
18486        self.selection_history
18487            .transaction_mut(transaction_id)
18488            .map(modify)
18489            .is_some()
18490    }
18491
18492    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18493        if self.selection_mark_mode {
18494            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18495                s.move_with(|_, sel| {
18496                    sel.collapse_to(sel.head(), SelectionGoal::None);
18497                });
18498            })
18499        }
18500        self.selection_mark_mode = true;
18501        cx.notify();
18502    }
18503
18504    pub fn swap_selection_ends(
18505        &mut self,
18506        _: &actions::SwapSelectionEnds,
18507        window: &mut Window,
18508        cx: &mut Context<Self>,
18509    ) {
18510        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18511            s.move_with(|_, sel| {
18512                if sel.start != sel.end {
18513                    sel.reversed = !sel.reversed
18514                }
18515            });
18516        });
18517        self.request_autoscroll(Autoscroll::newest(), cx);
18518        cx.notify();
18519    }
18520
18521    pub fn toggle_focus(
18522        workspace: &mut Workspace,
18523        _: &actions::ToggleFocus,
18524        window: &mut Window,
18525        cx: &mut Context<Workspace>,
18526    ) {
18527        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18528            return;
18529        };
18530        workspace.activate_item(&item, true, true, window, cx);
18531    }
18532
18533    pub fn toggle_fold(
18534        &mut self,
18535        _: &actions::ToggleFold,
18536        window: &mut Window,
18537        cx: &mut Context<Self>,
18538    ) {
18539        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18540            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18541            let selection = self.selections.newest::<Point>(&display_map);
18542
18543            let range = if selection.is_empty() {
18544                let point = selection.head().to_display_point(&display_map);
18545                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18546                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18547                    .to_point(&display_map);
18548                start..end
18549            } else {
18550                selection.range()
18551            };
18552            if display_map.folds_in_range(range).next().is_some() {
18553                self.unfold_lines(&Default::default(), window, cx)
18554            } else {
18555                self.fold(&Default::default(), window, cx)
18556            }
18557        } else {
18558            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18559            let buffer_ids: HashSet<_> = self
18560                .selections
18561                .disjoint_anchor_ranges()
18562                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18563                .collect();
18564
18565            let should_unfold = buffer_ids
18566                .iter()
18567                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18568
18569            for buffer_id in buffer_ids {
18570                if should_unfold {
18571                    self.unfold_buffer(buffer_id, cx);
18572                } else {
18573                    self.fold_buffer(buffer_id, cx);
18574                }
18575            }
18576        }
18577    }
18578
18579    pub fn toggle_fold_recursive(
18580        &mut self,
18581        _: &actions::ToggleFoldRecursive,
18582        window: &mut Window,
18583        cx: &mut Context<Self>,
18584    ) {
18585        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18586
18587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18588        let range = if selection.is_empty() {
18589            let point = selection.head().to_display_point(&display_map);
18590            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18591            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18592                .to_point(&display_map);
18593            start..end
18594        } else {
18595            selection.range()
18596        };
18597        if display_map.folds_in_range(range).next().is_some() {
18598            self.unfold_recursive(&Default::default(), window, cx)
18599        } else {
18600            self.fold_recursive(&Default::default(), window, cx)
18601        }
18602    }
18603
18604    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18605        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18606            let mut to_fold = Vec::new();
18607            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18608            let selections = self.selections.all_adjusted(&display_map);
18609
18610            for selection in selections {
18611                let range = selection.range().sorted();
18612                let buffer_start_row = range.start.row;
18613
18614                if range.start.row != range.end.row {
18615                    let mut found = false;
18616                    let mut row = range.start.row;
18617                    while row <= range.end.row {
18618                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18619                        {
18620                            found = true;
18621                            row = crease.range().end.row + 1;
18622                            to_fold.push(crease);
18623                        } else {
18624                            row += 1
18625                        }
18626                    }
18627                    if found {
18628                        continue;
18629                    }
18630                }
18631
18632                for row in (0..=range.start.row).rev() {
18633                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18634                        && crease.range().end.row >= buffer_start_row
18635                    {
18636                        to_fold.push(crease);
18637                        if row <= range.start.row {
18638                            break;
18639                        }
18640                    }
18641                }
18642            }
18643
18644            self.fold_creases(to_fold, true, window, cx);
18645        } else {
18646            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18647            let buffer_ids = self
18648                .selections
18649                .disjoint_anchor_ranges()
18650                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18651                .collect::<HashSet<_>>();
18652            for buffer_id in buffer_ids {
18653                self.fold_buffer(buffer_id, cx);
18654            }
18655        }
18656    }
18657
18658    pub fn toggle_fold_all(
18659        &mut self,
18660        _: &actions::ToggleFoldAll,
18661        window: &mut Window,
18662        cx: &mut Context<Self>,
18663    ) {
18664        if self.buffer.read(cx).is_singleton() {
18665            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18666            let has_folds = display_map
18667                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18668                .next()
18669                .is_some();
18670
18671            if has_folds {
18672                self.unfold_all(&actions::UnfoldAll, window, cx);
18673            } else {
18674                self.fold_all(&actions::FoldAll, window, cx);
18675            }
18676        } else {
18677            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18678            let should_unfold = buffer_ids
18679                .iter()
18680                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18681
18682            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18683                editor
18684                    .update_in(cx, |editor, _, cx| {
18685                        for buffer_id in buffer_ids {
18686                            if should_unfold {
18687                                editor.unfold_buffer(buffer_id, cx);
18688                            } else {
18689                                editor.fold_buffer(buffer_id, cx);
18690                            }
18691                        }
18692                    })
18693                    .ok();
18694            });
18695        }
18696    }
18697
18698    fn fold_at_level(
18699        &mut self,
18700        fold_at: &FoldAtLevel,
18701        window: &mut Window,
18702        cx: &mut Context<Self>,
18703    ) {
18704        if !self.buffer.read(cx).is_singleton() {
18705            return;
18706        }
18707
18708        let fold_at_level = fold_at.0;
18709        let snapshot = self.buffer.read(cx).snapshot(cx);
18710        let mut to_fold = Vec::new();
18711        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18712
18713        let row_ranges_to_keep: Vec<Range<u32>> = self
18714            .selections
18715            .all::<Point>(&self.display_snapshot(cx))
18716            .into_iter()
18717            .map(|sel| sel.start.row..sel.end.row)
18718            .collect();
18719
18720        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18721            while start_row < end_row {
18722                match self
18723                    .snapshot(window, cx)
18724                    .crease_for_buffer_row(MultiBufferRow(start_row))
18725                {
18726                    Some(crease) => {
18727                        let nested_start_row = crease.range().start.row + 1;
18728                        let nested_end_row = crease.range().end.row;
18729
18730                        if current_level < fold_at_level {
18731                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18732                        } else if current_level == fold_at_level {
18733                            // Fold iff there is no selection completely contained within the fold region
18734                            if !row_ranges_to_keep.iter().any(|selection| {
18735                                selection.end >= nested_start_row
18736                                    && selection.start <= nested_end_row
18737                            }) {
18738                                to_fold.push(crease);
18739                            }
18740                        }
18741
18742                        start_row = nested_end_row + 1;
18743                    }
18744                    None => start_row += 1,
18745                }
18746            }
18747        }
18748
18749        self.fold_creases(to_fold, true, window, cx);
18750    }
18751
18752    pub fn fold_at_level_1(
18753        &mut self,
18754        _: &actions::FoldAtLevel1,
18755        window: &mut Window,
18756        cx: &mut Context<Self>,
18757    ) {
18758        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18759    }
18760
18761    pub fn fold_at_level_2(
18762        &mut self,
18763        _: &actions::FoldAtLevel2,
18764        window: &mut Window,
18765        cx: &mut Context<Self>,
18766    ) {
18767        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18768    }
18769
18770    pub fn fold_at_level_3(
18771        &mut self,
18772        _: &actions::FoldAtLevel3,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18777    }
18778
18779    pub fn fold_at_level_4(
18780        &mut self,
18781        _: &actions::FoldAtLevel4,
18782        window: &mut Window,
18783        cx: &mut Context<Self>,
18784    ) {
18785        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18786    }
18787
18788    pub fn fold_at_level_5(
18789        &mut self,
18790        _: &actions::FoldAtLevel5,
18791        window: &mut Window,
18792        cx: &mut Context<Self>,
18793    ) {
18794        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18795    }
18796
18797    pub fn fold_at_level_6(
18798        &mut self,
18799        _: &actions::FoldAtLevel6,
18800        window: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18804    }
18805
18806    pub fn fold_at_level_7(
18807        &mut self,
18808        _: &actions::FoldAtLevel7,
18809        window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18813    }
18814
18815    pub fn fold_at_level_8(
18816        &mut self,
18817        _: &actions::FoldAtLevel8,
18818        window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18822    }
18823
18824    pub fn fold_at_level_9(
18825        &mut self,
18826        _: &actions::FoldAtLevel9,
18827        window: &mut Window,
18828        cx: &mut Context<Self>,
18829    ) {
18830        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18831    }
18832
18833    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18834        if self.buffer.read(cx).is_singleton() {
18835            let mut fold_ranges = Vec::new();
18836            let snapshot = self.buffer.read(cx).snapshot(cx);
18837
18838            for row in 0..snapshot.max_row().0 {
18839                if let Some(foldable_range) = self
18840                    .snapshot(window, cx)
18841                    .crease_for_buffer_row(MultiBufferRow(row))
18842                {
18843                    fold_ranges.push(foldable_range);
18844                }
18845            }
18846
18847            self.fold_creases(fold_ranges, true, window, cx);
18848        } else {
18849            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18850                editor
18851                    .update_in(cx, |editor, _, cx| {
18852                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18853                            editor.fold_buffer(buffer_id, cx);
18854                        }
18855                    })
18856                    .ok();
18857            });
18858        }
18859    }
18860
18861    pub fn fold_function_bodies(
18862        &mut self,
18863        _: &actions::FoldFunctionBodies,
18864        window: &mut Window,
18865        cx: &mut Context<Self>,
18866    ) {
18867        let snapshot = self.buffer.read(cx).snapshot(cx);
18868
18869        let ranges = snapshot
18870            .text_object_ranges(
18871                MultiBufferOffset(0)..snapshot.len(),
18872                TreeSitterOptions::default(),
18873            )
18874            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18875            .collect::<Vec<_>>();
18876
18877        let creases = ranges
18878            .into_iter()
18879            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18880            .collect();
18881
18882        self.fold_creases(creases, true, window, cx);
18883    }
18884
18885    pub fn fold_recursive(
18886        &mut self,
18887        _: &actions::FoldRecursive,
18888        window: &mut Window,
18889        cx: &mut Context<Self>,
18890    ) {
18891        let mut to_fold = Vec::new();
18892        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18893        let selections = self.selections.all_adjusted(&display_map);
18894
18895        for selection in selections {
18896            let range = selection.range().sorted();
18897            let buffer_start_row = range.start.row;
18898
18899            if range.start.row != range.end.row {
18900                let mut found = false;
18901                for row in range.start.row..=range.end.row {
18902                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18903                        found = true;
18904                        to_fold.push(crease);
18905                    }
18906                }
18907                if found {
18908                    continue;
18909                }
18910            }
18911
18912            for row in (0..=range.start.row).rev() {
18913                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18914                    if crease.range().end.row >= buffer_start_row {
18915                        to_fold.push(crease);
18916                    } else {
18917                        break;
18918                    }
18919                }
18920            }
18921        }
18922
18923        self.fold_creases(to_fold, true, window, cx);
18924    }
18925
18926    pub fn fold_at(
18927        &mut self,
18928        buffer_row: MultiBufferRow,
18929        window: &mut Window,
18930        cx: &mut Context<Self>,
18931    ) {
18932        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18933
18934        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18935            let autoscroll = self
18936                .selections
18937                .all::<Point>(&display_map)
18938                .iter()
18939                .any(|selection| crease.range().overlaps(&selection.range()));
18940
18941            self.fold_creases(vec![crease], autoscroll, window, cx);
18942        }
18943    }
18944
18945    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18946        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18947            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18948            let buffer = display_map.buffer_snapshot();
18949            let selections = self.selections.all::<Point>(&display_map);
18950            let ranges = selections
18951                .iter()
18952                .map(|s| {
18953                    let range = s.display_range(&display_map).sorted();
18954                    let mut start = range.start.to_point(&display_map);
18955                    let mut end = range.end.to_point(&display_map);
18956                    start.column = 0;
18957                    end.column = buffer.line_len(MultiBufferRow(end.row));
18958                    start..end
18959                })
18960                .collect::<Vec<_>>();
18961
18962            self.unfold_ranges(&ranges, true, true, cx);
18963        } else {
18964            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18965            let buffer_ids = self
18966                .selections
18967                .disjoint_anchor_ranges()
18968                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18969                .collect::<HashSet<_>>();
18970            for buffer_id in buffer_ids {
18971                self.unfold_buffer(buffer_id, cx);
18972            }
18973        }
18974    }
18975
18976    pub fn unfold_recursive(
18977        &mut self,
18978        _: &UnfoldRecursive,
18979        _window: &mut Window,
18980        cx: &mut Context<Self>,
18981    ) {
18982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18983        let selections = self.selections.all::<Point>(&display_map);
18984        let ranges = selections
18985            .iter()
18986            .map(|s| {
18987                let mut range = s.display_range(&display_map).sorted();
18988                *range.start.column_mut() = 0;
18989                *range.end.column_mut() = display_map.line_len(range.end.row());
18990                let start = range.start.to_point(&display_map);
18991                let end = range.end.to_point(&display_map);
18992                start..end
18993            })
18994            .collect::<Vec<_>>();
18995
18996        self.unfold_ranges(&ranges, true, true, cx);
18997    }
18998
18999    pub fn unfold_at(
19000        &mut self,
19001        buffer_row: MultiBufferRow,
19002        _window: &mut Window,
19003        cx: &mut Context<Self>,
19004    ) {
19005        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19006
19007        let intersection_range = Point::new(buffer_row.0, 0)
19008            ..Point::new(
19009                buffer_row.0,
19010                display_map.buffer_snapshot().line_len(buffer_row),
19011            );
19012
19013        let autoscroll = self
19014            .selections
19015            .all::<Point>(&display_map)
19016            .iter()
19017            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19018
19019        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19020    }
19021
19022    pub fn unfold_all(
19023        &mut self,
19024        _: &actions::UnfoldAll,
19025        _window: &mut Window,
19026        cx: &mut Context<Self>,
19027    ) {
19028        if self.buffer.read(cx).is_singleton() {
19029            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19030            self.unfold_ranges(
19031                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19032                true,
19033                true,
19034                cx,
19035            );
19036        } else {
19037            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19038                editor
19039                    .update(cx, |editor, cx| {
19040                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19041                            editor.unfold_buffer(buffer_id, cx);
19042                        }
19043                    })
19044                    .ok();
19045            });
19046        }
19047    }
19048
19049    pub fn fold_selected_ranges(
19050        &mut self,
19051        _: &FoldSelectedRanges,
19052        window: &mut Window,
19053        cx: &mut Context<Self>,
19054    ) {
19055        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19056        let selections = self.selections.all_adjusted(&display_map);
19057        let ranges = selections
19058            .into_iter()
19059            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19060            .collect::<Vec<_>>();
19061        self.fold_creases(ranges, true, window, cx);
19062    }
19063
19064    pub fn fold_ranges<T: ToOffset + Clone>(
19065        &mut self,
19066        ranges: Vec<Range<T>>,
19067        auto_scroll: bool,
19068        window: &mut Window,
19069        cx: &mut Context<Self>,
19070    ) {
19071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19072        let ranges = ranges
19073            .into_iter()
19074            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19075            .collect::<Vec<_>>();
19076        self.fold_creases(ranges, auto_scroll, window, cx);
19077    }
19078
19079    pub fn fold_creases<T: ToOffset + Clone>(
19080        &mut self,
19081        creases: Vec<Crease<T>>,
19082        auto_scroll: bool,
19083        _window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        if creases.is_empty() {
19087            return;
19088        }
19089
19090        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19091
19092        if auto_scroll {
19093            self.request_autoscroll(Autoscroll::fit(), cx);
19094        }
19095
19096        cx.notify();
19097
19098        self.scrollbar_marker_state.dirty = true;
19099        self.folds_did_change(cx);
19100    }
19101
19102    /// Removes any folds whose ranges intersect any of the given ranges.
19103    pub fn unfold_ranges<T: ToOffset + Clone>(
19104        &mut self,
19105        ranges: &[Range<T>],
19106        inclusive: bool,
19107        auto_scroll: bool,
19108        cx: &mut Context<Self>,
19109    ) {
19110        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19111            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19112        });
19113        self.folds_did_change(cx);
19114    }
19115
19116    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19117        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19118            return;
19119        }
19120
19121        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19122        self.display_map.update(cx, |display_map, cx| {
19123            display_map.fold_buffers([buffer_id], cx)
19124        });
19125
19126        let snapshot = self.display_snapshot(cx);
19127        self.selections.change_with(&snapshot, |selections| {
19128            selections.remove_selections_from_buffer(buffer_id);
19129        });
19130
19131        cx.emit(EditorEvent::BufferFoldToggled {
19132            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19133            folded: true,
19134        });
19135        cx.notify();
19136    }
19137
19138    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19139        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19140            return;
19141        }
19142        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19143        self.display_map.update(cx, |display_map, cx| {
19144            display_map.unfold_buffers([buffer_id], cx);
19145        });
19146        cx.emit(EditorEvent::BufferFoldToggled {
19147            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19148            folded: false,
19149        });
19150        cx.notify();
19151    }
19152
19153    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19154        self.display_map.read(cx).is_buffer_folded(buffer)
19155    }
19156
19157    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19158        self.display_map.read(cx).folded_buffers()
19159    }
19160
19161    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19162        self.display_map.update(cx, |display_map, cx| {
19163            display_map.disable_header_for_buffer(buffer_id, cx);
19164        });
19165        cx.notify();
19166    }
19167
19168    /// Removes any folds with the given ranges.
19169    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19170        &mut self,
19171        ranges: &[Range<T>],
19172        type_id: TypeId,
19173        auto_scroll: bool,
19174        cx: &mut Context<Self>,
19175    ) {
19176        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19177            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19178        });
19179        self.folds_did_change(cx);
19180    }
19181
19182    fn remove_folds_with<T: ToOffset + Clone>(
19183        &mut self,
19184        ranges: &[Range<T>],
19185        auto_scroll: bool,
19186        cx: &mut Context<Self>,
19187        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19188    ) {
19189        if ranges.is_empty() {
19190            return;
19191        }
19192
19193        let mut buffers_affected = HashSet::default();
19194        let multi_buffer = self.buffer().read(cx);
19195        for range in ranges {
19196            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19197                buffers_affected.insert(buffer.read(cx).remote_id());
19198            };
19199        }
19200
19201        self.display_map.update(cx, update);
19202
19203        if auto_scroll {
19204            self.request_autoscroll(Autoscroll::fit(), cx);
19205        }
19206
19207        cx.notify();
19208        self.scrollbar_marker_state.dirty = true;
19209        self.active_indent_guides_state.dirty = true;
19210    }
19211
19212    pub fn update_renderer_widths(
19213        &mut self,
19214        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19215        cx: &mut Context<Self>,
19216    ) -> bool {
19217        self.display_map
19218            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19219    }
19220
19221    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19222        self.display_map.read(cx).fold_placeholder.clone()
19223    }
19224
19225    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19226        self.use_base_text_line_numbers = show;
19227    }
19228
19229    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19230        self.buffer.update(cx, |buffer, cx| {
19231            buffer.set_all_diff_hunks_expanded(cx);
19232        });
19233    }
19234
19235    pub fn expand_all_diff_hunks(
19236        &mut self,
19237        _: &ExpandAllDiffHunks,
19238        _window: &mut Window,
19239        cx: &mut Context<Self>,
19240    ) {
19241        self.buffer.update(cx, |buffer, cx| {
19242            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19243        });
19244    }
19245
19246    pub fn collapse_all_diff_hunks(
19247        &mut self,
19248        _: &CollapseAllDiffHunks,
19249        _window: &mut Window,
19250        cx: &mut Context<Self>,
19251    ) {
19252        self.buffer.update(cx, |buffer, cx| {
19253            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19254        });
19255    }
19256
19257    pub fn toggle_selected_diff_hunks(
19258        &mut self,
19259        _: &ToggleSelectedDiffHunks,
19260        _window: &mut Window,
19261        cx: &mut Context<Self>,
19262    ) {
19263        let ranges: Vec<_> = self
19264            .selections
19265            .disjoint_anchors()
19266            .iter()
19267            .map(|s| s.range())
19268            .collect();
19269        self.toggle_diff_hunks_in_ranges(ranges, cx);
19270    }
19271
19272    pub fn diff_hunks_in_ranges<'a>(
19273        &'a self,
19274        ranges: &'a [Range<Anchor>],
19275        buffer: &'a MultiBufferSnapshot,
19276    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19277        ranges.iter().flat_map(move |range| {
19278            let end_excerpt_id = range.end.excerpt_id;
19279            let range = range.to_point(buffer);
19280            let mut peek_end = range.end;
19281            if range.end.row < buffer.max_row().0 {
19282                peek_end = Point::new(range.end.row + 1, 0);
19283            }
19284            buffer
19285                .diff_hunks_in_range(range.start..peek_end)
19286                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19287        })
19288    }
19289
19290    pub fn has_stageable_diff_hunks_in_ranges(
19291        &self,
19292        ranges: &[Range<Anchor>],
19293        snapshot: &MultiBufferSnapshot,
19294    ) -> bool {
19295        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19296        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19297    }
19298
19299    pub fn toggle_staged_selected_diff_hunks(
19300        &mut self,
19301        _: &::git::ToggleStaged,
19302        _: &mut Window,
19303        cx: &mut Context<Self>,
19304    ) {
19305        let snapshot = self.buffer.read(cx).snapshot(cx);
19306        let ranges: Vec<_> = self
19307            .selections
19308            .disjoint_anchors()
19309            .iter()
19310            .map(|s| s.range())
19311            .collect();
19312        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19313        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19314    }
19315
19316    pub fn set_render_diff_hunk_controls(
19317        &mut self,
19318        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19319        cx: &mut Context<Self>,
19320    ) {
19321        self.render_diff_hunk_controls = render_diff_hunk_controls;
19322        cx.notify();
19323    }
19324
19325    pub fn stage_and_next(
19326        &mut self,
19327        _: &::git::StageAndNext,
19328        window: &mut Window,
19329        cx: &mut Context<Self>,
19330    ) {
19331        self.do_stage_or_unstage_and_next(true, window, cx);
19332    }
19333
19334    pub fn unstage_and_next(
19335        &mut self,
19336        _: &::git::UnstageAndNext,
19337        window: &mut Window,
19338        cx: &mut Context<Self>,
19339    ) {
19340        self.do_stage_or_unstage_and_next(false, window, cx);
19341    }
19342
19343    pub fn stage_or_unstage_diff_hunks(
19344        &mut self,
19345        stage: bool,
19346        ranges: Vec<Range<Anchor>>,
19347        cx: &mut Context<Self>,
19348    ) {
19349        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19350        cx.spawn(async move |this, cx| {
19351            task.await?;
19352            this.update(cx, |this, cx| {
19353                let snapshot = this.buffer.read(cx).snapshot(cx);
19354                let chunk_by = this
19355                    .diff_hunks_in_ranges(&ranges, &snapshot)
19356                    .chunk_by(|hunk| hunk.buffer_id);
19357                for (buffer_id, hunks) in &chunk_by {
19358                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19359                }
19360            })
19361        })
19362        .detach_and_log_err(cx);
19363    }
19364
19365    fn save_buffers_for_ranges_if_needed(
19366        &mut self,
19367        ranges: &[Range<Anchor>],
19368        cx: &mut Context<Editor>,
19369    ) -> Task<Result<()>> {
19370        let multibuffer = self.buffer.read(cx);
19371        let snapshot = multibuffer.read(cx);
19372        let buffer_ids: HashSet<_> = ranges
19373            .iter()
19374            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19375            .collect();
19376        drop(snapshot);
19377
19378        let mut buffers = HashSet::default();
19379        for buffer_id in buffer_ids {
19380            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19381                let buffer = buffer_entity.read(cx);
19382                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19383                {
19384                    buffers.insert(buffer_entity);
19385                }
19386            }
19387        }
19388
19389        if let Some(project) = &self.project {
19390            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19391        } else {
19392            Task::ready(Ok(()))
19393        }
19394    }
19395
19396    fn do_stage_or_unstage_and_next(
19397        &mut self,
19398        stage: bool,
19399        window: &mut Window,
19400        cx: &mut Context<Self>,
19401    ) {
19402        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19403
19404        if ranges.iter().any(|range| range.start != range.end) {
19405            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19406            return;
19407        }
19408
19409        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19410        let snapshot = self.snapshot(window, cx);
19411        let position = self
19412            .selections
19413            .newest::<Point>(&snapshot.display_snapshot)
19414            .head();
19415        let mut row = snapshot
19416            .buffer_snapshot()
19417            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19418            .find(|hunk| hunk.row_range.start.0 > position.row)
19419            .map(|hunk| hunk.row_range.start);
19420
19421        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19422        // Outside of the project diff editor, wrap around to the beginning.
19423        if !all_diff_hunks_expanded {
19424            row = row.or_else(|| {
19425                snapshot
19426                    .buffer_snapshot()
19427                    .diff_hunks_in_range(Point::zero()..position)
19428                    .find(|hunk| hunk.row_range.end.0 < position.row)
19429                    .map(|hunk| hunk.row_range.start)
19430            });
19431        }
19432
19433        if let Some(row) = row {
19434            let destination = Point::new(row.0, 0);
19435            let autoscroll = Autoscroll::center();
19436
19437            self.unfold_ranges(&[destination..destination], false, false, cx);
19438            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19439                s.select_ranges([destination..destination]);
19440            });
19441        }
19442    }
19443
19444    fn do_stage_or_unstage(
19445        &self,
19446        stage: bool,
19447        buffer_id: BufferId,
19448        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19449        cx: &mut App,
19450    ) -> Option<()> {
19451        let project = self.project()?;
19452        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19453        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19454        let buffer_snapshot = buffer.read(cx).snapshot();
19455        let file_exists = buffer_snapshot
19456            .file()
19457            .is_some_and(|file| file.disk_state().exists());
19458        diff.update(cx, |diff, cx| {
19459            diff.stage_or_unstage_hunks(
19460                stage,
19461                &hunks
19462                    .map(|hunk| buffer_diff::DiffHunk {
19463                        buffer_range: hunk.buffer_range,
19464                        // We don't need to pass in word diffs here because they're only used for rendering and
19465                        // this function changes internal state
19466                        base_word_diffs: Vec::default(),
19467                        buffer_word_diffs: Vec::default(),
19468                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19469                            ..hunk.diff_base_byte_range.end.0,
19470                        secondary_status: hunk.secondary_status,
19471                        range: Point::zero()..Point::zero(), // unused
19472                    })
19473                    .collect::<Vec<_>>(),
19474                &buffer_snapshot,
19475                file_exists,
19476                cx,
19477            )
19478        });
19479        None
19480    }
19481
19482    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19483        let ranges: Vec<_> = self
19484            .selections
19485            .disjoint_anchors()
19486            .iter()
19487            .map(|s| s.range())
19488            .collect();
19489        self.buffer
19490            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19491    }
19492
19493    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19494        self.buffer.update(cx, |buffer, cx| {
19495            let ranges = vec![Anchor::min()..Anchor::max()];
19496            if !buffer.all_diff_hunks_expanded()
19497                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19498            {
19499                buffer.collapse_diff_hunks(ranges, cx);
19500                true
19501            } else {
19502                false
19503            }
19504        })
19505    }
19506
19507    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19508        if self.buffer.read(cx).all_diff_hunks_expanded() {
19509            return true;
19510        }
19511        let ranges = vec![Anchor::min()..Anchor::max()];
19512        self.buffer
19513            .read(cx)
19514            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19515    }
19516
19517    fn toggle_diff_hunks_in_ranges(
19518        &mut self,
19519        ranges: Vec<Range<Anchor>>,
19520        cx: &mut Context<Editor>,
19521    ) {
19522        self.buffer.update(cx, |buffer, cx| {
19523            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19524            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19525        })
19526    }
19527
19528    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19529        self.buffer.update(cx, |buffer, cx| {
19530            let snapshot = buffer.snapshot(cx);
19531            let excerpt_id = range.end.excerpt_id;
19532            let point_range = range.to_point(&snapshot);
19533            let expand = !buffer.single_hunk_is_expanded(range, cx);
19534            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19535        })
19536    }
19537
19538    pub(crate) fn apply_all_diff_hunks(
19539        &mut self,
19540        _: &ApplyAllDiffHunks,
19541        window: &mut Window,
19542        cx: &mut Context<Self>,
19543    ) {
19544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19545
19546        let buffers = self.buffer.read(cx).all_buffers();
19547        for branch_buffer in buffers {
19548            branch_buffer.update(cx, |branch_buffer, cx| {
19549                branch_buffer.merge_into_base(Vec::new(), cx);
19550            });
19551        }
19552
19553        if let Some(project) = self.project.clone() {
19554            self.save(
19555                SaveOptions {
19556                    format: true,
19557                    autosave: false,
19558                },
19559                project,
19560                window,
19561                cx,
19562            )
19563            .detach_and_log_err(cx);
19564        }
19565    }
19566
19567    pub(crate) fn apply_selected_diff_hunks(
19568        &mut self,
19569        _: &ApplyDiffHunk,
19570        window: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19574        let snapshot = self.snapshot(window, cx);
19575        let hunks = snapshot.hunks_for_ranges(
19576            self.selections
19577                .all(&snapshot.display_snapshot)
19578                .into_iter()
19579                .map(|selection| selection.range()),
19580        );
19581        let mut ranges_by_buffer = HashMap::default();
19582        self.transact(window, cx, |editor, _window, cx| {
19583            for hunk in hunks {
19584                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19585                    ranges_by_buffer
19586                        .entry(buffer.clone())
19587                        .or_insert_with(Vec::new)
19588                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19589                }
19590            }
19591
19592            for (buffer, ranges) in ranges_by_buffer {
19593                buffer.update(cx, |buffer, cx| {
19594                    buffer.merge_into_base(ranges, cx);
19595                });
19596            }
19597        });
19598
19599        if let Some(project) = self.project.clone() {
19600            self.save(
19601                SaveOptions {
19602                    format: true,
19603                    autosave: false,
19604                },
19605                project,
19606                window,
19607                cx,
19608            )
19609            .detach_and_log_err(cx);
19610        }
19611    }
19612
19613    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19614        if hovered != self.gutter_hovered {
19615            self.gutter_hovered = hovered;
19616            cx.notify();
19617        }
19618    }
19619
19620    pub fn insert_blocks(
19621        &mut self,
19622        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19623        autoscroll: Option<Autoscroll>,
19624        cx: &mut Context<Self>,
19625    ) -> Vec<CustomBlockId> {
19626        let blocks = self
19627            .display_map
19628            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19629        if let Some(autoscroll) = autoscroll {
19630            self.request_autoscroll(autoscroll, cx);
19631        }
19632        cx.notify();
19633        blocks
19634    }
19635
19636    pub fn resize_blocks(
19637        &mut self,
19638        heights: HashMap<CustomBlockId, u32>,
19639        autoscroll: Option<Autoscroll>,
19640        cx: &mut Context<Self>,
19641    ) {
19642        self.display_map
19643            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19644        if let Some(autoscroll) = autoscroll {
19645            self.request_autoscroll(autoscroll, cx);
19646        }
19647        cx.notify();
19648    }
19649
19650    pub fn replace_blocks(
19651        &mut self,
19652        renderers: HashMap<CustomBlockId, RenderBlock>,
19653        autoscroll: Option<Autoscroll>,
19654        cx: &mut Context<Self>,
19655    ) {
19656        self.display_map
19657            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19658        if let Some(autoscroll) = autoscroll {
19659            self.request_autoscroll(autoscroll, cx);
19660        }
19661        cx.notify();
19662    }
19663
19664    pub fn remove_blocks(
19665        &mut self,
19666        block_ids: HashSet<CustomBlockId>,
19667        autoscroll: Option<Autoscroll>,
19668        cx: &mut Context<Self>,
19669    ) {
19670        self.display_map.update(cx, |display_map, cx| {
19671            display_map.remove_blocks(block_ids, cx)
19672        });
19673        if let Some(autoscroll) = autoscroll {
19674            self.request_autoscroll(autoscroll, cx);
19675        }
19676        cx.notify();
19677    }
19678
19679    pub fn row_for_block(
19680        &self,
19681        block_id: CustomBlockId,
19682        cx: &mut Context<Self>,
19683    ) -> Option<DisplayRow> {
19684        self.display_map
19685            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19686    }
19687
19688    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19689        self.focused_block = Some(focused_block);
19690    }
19691
19692    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19693        self.focused_block.take()
19694    }
19695
19696    pub fn insert_creases(
19697        &mut self,
19698        creases: impl IntoIterator<Item = Crease<Anchor>>,
19699        cx: &mut Context<Self>,
19700    ) -> Vec<CreaseId> {
19701        self.display_map
19702            .update(cx, |map, cx| map.insert_creases(creases, cx))
19703    }
19704
19705    pub fn remove_creases(
19706        &mut self,
19707        ids: impl IntoIterator<Item = CreaseId>,
19708        cx: &mut Context<Self>,
19709    ) -> Vec<(CreaseId, Range<Anchor>)> {
19710        self.display_map
19711            .update(cx, |map, cx| map.remove_creases(ids, cx))
19712    }
19713
19714    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19715        self.display_map
19716            .update(cx, |map, cx| map.snapshot(cx))
19717            .longest_row()
19718    }
19719
19720    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19721        self.display_map
19722            .update(cx, |map, cx| map.snapshot(cx))
19723            .max_point()
19724    }
19725
19726    pub fn text(&self, cx: &App) -> String {
19727        self.buffer.read(cx).read(cx).text()
19728    }
19729
19730    pub fn is_empty(&self, cx: &App) -> bool {
19731        self.buffer.read(cx).read(cx).is_empty()
19732    }
19733
19734    pub fn text_option(&self, cx: &App) -> Option<String> {
19735        let text = self.text(cx);
19736        let text = text.trim();
19737
19738        if text.is_empty() {
19739            return None;
19740        }
19741
19742        Some(text.to_string())
19743    }
19744
19745    pub fn set_text(
19746        &mut self,
19747        text: impl Into<Arc<str>>,
19748        window: &mut Window,
19749        cx: &mut Context<Self>,
19750    ) {
19751        self.transact(window, cx, |this, _, cx| {
19752            this.buffer
19753                .read(cx)
19754                .as_singleton()
19755                .expect("you can only call set_text on editors for singleton buffers")
19756                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19757        });
19758    }
19759
19760    pub fn display_text(&self, cx: &mut App) -> String {
19761        self.display_map
19762            .update(cx, |map, cx| map.snapshot(cx))
19763            .text()
19764    }
19765
19766    fn create_minimap(
19767        &self,
19768        minimap_settings: MinimapSettings,
19769        window: &mut Window,
19770        cx: &mut Context<Self>,
19771    ) -> Option<Entity<Self>> {
19772        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19773            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19774    }
19775
19776    fn initialize_new_minimap(
19777        &self,
19778        minimap_settings: MinimapSettings,
19779        window: &mut Window,
19780        cx: &mut Context<Self>,
19781    ) -> Entity<Self> {
19782        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19783
19784        let mut minimap = Editor::new_internal(
19785            EditorMode::Minimap {
19786                parent: cx.weak_entity(),
19787            },
19788            self.buffer.clone(),
19789            None,
19790            Some(self.display_map.clone()),
19791            window,
19792            cx,
19793        );
19794        minimap.scroll_manager.clone_state(&self.scroll_manager);
19795        minimap.set_text_style_refinement(TextStyleRefinement {
19796            font_size: Some(MINIMAP_FONT_SIZE),
19797            font_weight: Some(MINIMAP_FONT_WEIGHT),
19798            ..Default::default()
19799        });
19800        minimap.update_minimap_configuration(minimap_settings, cx);
19801        cx.new(|_| minimap)
19802    }
19803
19804    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19805        let current_line_highlight = minimap_settings
19806            .current_line_highlight
19807            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19808        self.set_current_line_highlight(Some(current_line_highlight));
19809    }
19810
19811    pub fn minimap(&self) -> Option<&Entity<Self>> {
19812        self.minimap
19813            .as_ref()
19814            .filter(|_| self.minimap_visibility.visible())
19815    }
19816
19817    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19818        let mut wrap_guides = smallvec![];
19819
19820        if self.show_wrap_guides == Some(false) {
19821            return wrap_guides;
19822        }
19823
19824        let settings = self.buffer.read(cx).language_settings(cx);
19825        if settings.show_wrap_guides {
19826            match self.soft_wrap_mode(cx) {
19827                SoftWrap::Column(soft_wrap) => {
19828                    wrap_guides.push((soft_wrap as usize, true));
19829                }
19830                SoftWrap::Bounded(soft_wrap) => {
19831                    wrap_guides.push((soft_wrap as usize, true));
19832                }
19833                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19834            }
19835            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19836        }
19837
19838        wrap_guides
19839    }
19840
19841    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19842        let settings = self.buffer.read(cx).language_settings(cx);
19843        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19844        match mode {
19845            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19846                SoftWrap::None
19847            }
19848            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19849            language_settings::SoftWrap::PreferredLineLength => {
19850                SoftWrap::Column(settings.preferred_line_length)
19851            }
19852            language_settings::SoftWrap::Bounded => {
19853                SoftWrap::Bounded(settings.preferred_line_length)
19854            }
19855        }
19856    }
19857
19858    pub fn set_soft_wrap_mode(
19859        &mut self,
19860        mode: language_settings::SoftWrap,
19861
19862        cx: &mut Context<Self>,
19863    ) {
19864        self.soft_wrap_mode_override = Some(mode);
19865        cx.notify();
19866    }
19867
19868    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19869        self.hard_wrap = hard_wrap;
19870        cx.notify();
19871    }
19872
19873    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19874        self.text_style_refinement = Some(style);
19875    }
19876
19877    /// called by the Element so we know what style we were most recently rendered with.
19878    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19879        // We intentionally do not inform the display map about the minimap style
19880        // so that wrapping is not recalculated and stays consistent for the editor
19881        // and its linked minimap.
19882        if !self.mode.is_minimap() {
19883            let font = style.text.font();
19884            let font_size = style.text.font_size.to_pixels(window.rem_size());
19885            let display_map = self
19886                .placeholder_display_map
19887                .as_ref()
19888                .filter(|_| self.is_empty(cx))
19889                .unwrap_or(&self.display_map);
19890
19891            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19892        }
19893        self.style = Some(style);
19894    }
19895
19896    pub fn style(&self) -> Option<&EditorStyle> {
19897        self.style.as_ref()
19898    }
19899
19900    // Called by the element. This method is not designed to be called outside of the editor
19901    // element's layout code because it does not notify when rewrapping is computed synchronously.
19902    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19903        if self.is_empty(cx) {
19904            self.placeholder_display_map
19905                .as_ref()
19906                .map_or(false, |display_map| {
19907                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19908                })
19909        } else {
19910            self.display_map
19911                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19912        }
19913    }
19914
19915    pub fn set_soft_wrap(&mut self) {
19916        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19917    }
19918
19919    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19920        if self.soft_wrap_mode_override.is_some() {
19921            self.soft_wrap_mode_override.take();
19922        } else {
19923            let soft_wrap = match self.soft_wrap_mode(cx) {
19924                SoftWrap::GitDiff => return,
19925                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19926                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19927                    language_settings::SoftWrap::None
19928                }
19929            };
19930            self.soft_wrap_mode_override = Some(soft_wrap);
19931        }
19932        cx.notify();
19933    }
19934
19935    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19936        let Some(workspace) = self.workspace() else {
19937            return;
19938        };
19939        let fs = workspace.read(cx).app_state().fs.clone();
19940        let current_show = TabBarSettings::get_global(cx).show;
19941        update_settings_file(fs, cx, move |setting, _| {
19942            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19943        });
19944    }
19945
19946    pub fn toggle_indent_guides(
19947        &mut self,
19948        _: &ToggleIndentGuides,
19949        _: &mut Window,
19950        cx: &mut Context<Self>,
19951    ) {
19952        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19953            self.buffer
19954                .read(cx)
19955                .language_settings(cx)
19956                .indent_guides
19957                .enabled
19958        });
19959        self.show_indent_guides = Some(!currently_enabled);
19960        cx.notify();
19961    }
19962
19963    fn should_show_indent_guides(&self) -> Option<bool> {
19964        self.show_indent_guides
19965    }
19966
19967    pub fn toggle_line_numbers(
19968        &mut self,
19969        _: &ToggleLineNumbers,
19970        _: &mut Window,
19971        cx: &mut Context<Self>,
19972    ) {
19973        let mut editor_settings = EditorSettings::get_global(cx).clone();
19974        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19975        EditorSettings::override_global(editor_settings, cx);
19976    }
19977
19978    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19979        if let Some(show_line_numbers) = self.show_line_numbers {
19980            return show_line_numbers;
19981        }
19982        EditorSettings::get_global(cx).gutter.line_numbers
19983    }
19984
19985    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19986        match (
19987            self.use_relative_line_numbers,
19988            EditorSettings::get_global(cx).relative_line_numbers,
19989        ) {
19990            (None, setting) => setting,
19991            (Some(false), _) => RelativeLineNumbers::Disabled,
19992            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19993            (Some(true), _) => RelativeLineNumbers::Enabled,
19994        }
19995    }
19996
19997    pub fn toggle_relative_line_numbers(
19998        &mut self,
19999        _: &ToggleRelativeLineNumbers,
20000        _: &mut Window,
20001        cx: &mut Context<Self>,
20002    ) {
20003        let is_relative = self.relative_line_numbers(cx);
20004        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20005    }
20006
20007    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20008        self.use_relative_line_numbers = is_relative;
20009        cx.notify();
20010    }
20011
20012    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20013        self.show_gutter = show_gutter;
20014        cx.notify();
20015    }
20016
20017    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20018        self.show_scrollbars = ScrollbarAxes {
20019            horizontal: show,
20020            vertical: show,
20021        };
20022        cx.notify();
20023    }
20024
20025    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20026        self.show_scrollbars.vertical = show;
20027        cx.notify();
20028    }
20029
20030    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20031        self.show_scrollbars.horizontal = show;
20032        cx.notify();
20033    }
20034
20035    pub fn set_minimap_visibility(
20036        &mut self,
20037        minimap_visibility: MinimapVisibility,
20038        window: &mut Window,
20039        cx: &mut Context<Self>,
20040    ) {
20041        if self.minimap_visibility != minimap_visibility {
20042            if minimap_visibility.visible() && self.minimap.is_none() {
20043                let minimap_settings = EditorSettings::get_global(cx).minimap;
20044                self.minimap =
20045                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20046            }
20047            self.minimap_visibility = minimap_visibility;
20048            cx.notify();
20049        }
20050    }
20051
20052    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20053        self.set_show_scrollbars(false, cx);
20054        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20055    }
20056
20057    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20058        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20059    }
20060
20061    /// Normally the text in full mode and auto height editors is padded on the
20062    /// left side by roughly half a character width for improved hit testing.
20063    ///
20064    /// Use this method to disable this for cases where this is not wanted (e.g.
20065    /// if you want to align the editor text with some other text above or below)
20066    /// or if you want to add this padding to single-line editors.
20067    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20068        self.offset_content = offset_content;
20069        cx.notify();
20070    }
20071
20072    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20073        self.show_line_numbers = Some(show_line_numbers);
20074        cx.notify();
20075    }
20076
20077    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20078        self.disable_expand_excerpt_buttons = true;
20079        cx.notify();
20080    }
20081
20082    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20083        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20084        cx.notify();
20085    }
20086
20087    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20088        self.show_code_actions = Some(show_code_actions);
20089        cx.notify();
20090    }
20091
20092    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20093        self.show_runnables = Some(show_runnables);
20094        cx.notify();
20095    }
20096
20097    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20098        self.show_breakpoints = Some(show_breakpoints);
20099        cx.notify();
20100    }
20101
20102    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20103        if self.display_map.read(cx).masked != masked {
20104            self.display_map.update(cx, |map, _| map.masked = masked);
20105        }
20106        cx.notify()
20107    }
20108
20109    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20110        self.show_wrap_guides = Some(show_wrap_guides);
20111        cx.notify();
20112    }
20113
20114    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20115        self.show_indent_guides = Some(show_indent_guides);
20116        cx.notify();
20117    }
20118
20119    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20120        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20121            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20122                && let Some(dir) = file.abs_path(cx).parent()
20123            {
20124                return Some(dir.to_owned());
20125            }
20126        }
20127
20128        None
20129    }
20130
20131    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20132        self.active_excerpt(cx)?
20133            .1
20134            .read(cx)
20135            .file()
20136            .and_then(|f| f.as_local())
20137    }
20138
20139    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20140        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20141            let buffer = buffer.read(cx);
20142            if let Some(project_path) = buffer.project_path(cx) {
20143                let project = self.project()?.read(cx);
20144                project.absolute_path(&project_path, cx)
20145            } else {
20146                buffer
20147                    .file()
20148                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20149            }
20150        })
20151    }
20152
20153    pub fn reveal_in_finder(
20154        &mut self,
20155        _: &RevealInFileManager,
20156        _window: &mut Window,
20157        cx: &mut Context<Self>,
20158    ) {
20159        if let Some(target) = self.target_file(cx) {
20160            cx.reveal_path(&target.abs_path(cx));
20161        }
20162    }
20163
20164    pub fn copy_path(
20165        &mut self,
20166        _: &zed_actions::workspace::CopyPath,
20167        _window: &mut Window,
20168        cx: &mut Context<Self>,
20169    ) {
20170        if let Some(path) = self.target_file_abs_path(cx)
20171            && let Some(path) = path.to_str()
20172        {
20173            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20174        } else {
20175            cx.propagate();
20176        }
20177    }
20178
20179    pub fn copy_relative_path(
20180        &mut self,
20181        _: &zed_actions::workspace::CopyRelativePath,
20182        _window: &mut Window,
20183        cx: &mut Context<Self>,
20184    ) {
20185        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20186            let project = self.project()?.read(cx);
20187            let path = buffer.read(cx).file()?.path();
20188            let path = path.display(project.path_style(cx));
20189            Some(path)
20190        }) {
20191            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20192        } else {
20193            cx.propagate();
20194        }
20195    }
20196
20197    /// Returns the project path for the editor's buffer, if any buffer is
20198    /// opened in the editor.
20199    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20200        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20201            buffer.read(cx).project_path(cx)
20202        } else {
20203            None
20204        }
20205    }
20206
20207    // Returns true if the editor handled a go-to-line request
20208    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20209        maybe!({
20210            let breakpoint_store = self.breakpoint_store.as_ref()?;
20211
20212            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20213            else {
20214                self.clear_row_highlights::<ActiveDebugLine>();
20215                return None;
20216            };
20217
20218            let position = active_stack_frame.position;
20219            let buffer_id = position.buffer_id?;
20220            let snapshot = self
20221                .project
20222                .as_ref()?
20223                .read(cx)
20224                .buffer_for_id(buffer_id, cx)?
20225                .read(cx)
20226                .snapshot();
20227
20228            let mut handled = false;
20229            for (id, ExcerptRange { context, .. }) in
20230                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20231            {
20232                if context.start.cmp(&position, &snapshot).is_ge()
20233                    || context.end.cmp(&position, &snapshot).is_lt()
20234                {
20235                    continue;
20236                }
20237                let snapshot = self.buffer.read(cx).snapshot(cx);
20238                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20239
20240                handled = true;
20241                self.clear_row_highlights::<ActiveDebugLine>();
20242
20243                self.go_to_line::<ActiveDebugLine>(
20244                    multibuffer_anchor,
20245                    Some(cx.theme().colors().editor_debugger_active_line_background),
20246                    window,
20247                    cx,
20248                );
20249
20250                cx.notify();
20251            }
20252
20253            handled.then_some(())
20254        })
20255        .is_some()
20256    }
20257
20258    pub fn copy_file_name_without_extension(
20259        &mut self,
20260        _: &CopyFileNameWithoutExtension,
20261        _: &mut Window,
20262        cx: &mut Context<Self>,
20263    ) {
20264        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20265            let file = buffer.read(cx).file()?;
20266            file.path().file_stem()
20267        }) {
20268            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20269        }
20270    }
20271
20272    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20273        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20274            let file = buffer.read(cx).file()?;
20275            Some(file.file_name(cx))
20276        }) {
20277            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20278        }
20279    }
20280
20281    pub fn toggle_git_blame(
20282        &mut self,
20283        _: &::git::Blame,
20284        window: &mut Window,
20285        cx: &mut Context<Self>,
20286    ) {
20287        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20288
20289        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20290            self.start_git_blame(true, window, cx);
20291        }
20292
20293        cx.notify();
20294    }
20295
20296    pub fn toggle_git_blame_inline(
20297        &mut self,
20298        _: &ToggleGitBlameInline,
20299        window: &mut Window,
20300        cx: &mut Context<Self>,
20301    ) {
20302        self.toggle_git_blame_inline_internal(true, window, cx);
20303        cx.notify();
20304    }
20305
20306    pub fn open_git_blame_commit(
20307        &mut self,
20308        _: &OpenGitBlameCommit,
20309        window: &mut Window,
20310        cx: &mut Context<Self>,
20311    ) {
20312        self.open_git_blame_commit_internal(window, cx);
20313    }
20314
20315    fn open_git_blame_commit_internal(
20316        &mut self,
20317        window: &mut Window,
20318        cx: &mut Context<Self>,
20319    ) -> Option<()> {
20320        let blame = self.blame.as_ref()?;
20321        let snapshot = self.snapshot(window, cx);
20322        let cursor = self
20323            .selections
20324            .newest::<Point>(&snapshot.display_snapshot)
20325            .head();
20326        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20327        let (_, blame_entry) = blame
20328            .update(cx, |blame, cx| {
20329                blame
20330                    .blame_for_rows(
20331                        &[RowInfo {
20332                            buffer_id: Some(buffer.remote_id()),
20333                            buffer_row: Some(point.row),
20334                            ..Default::default()
20335                        }],
20336                        cx,
20337                    )
20338                    .next()
20339            })
20340            .flatten()?;
20341        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20342        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20343        let workspace = self.workspace()?.downgrade();
20344        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20345        None
20346    }
20347
20348    pub fn git_blame_inline_enabled(&self) -> bool {
20349        self.git_blame_inline_enabled
20350    }
20351
20352    pub fn toggle_selection_menu(
20353        &mut self,
20354        _: &ToggleSelectionMenu,
20355        _: &mut Window,
20356        cx: &mut Context<Self>,
20357    ) {
20358        self.show_selection_menu = self
20359            .show_selection_menu
20360            .map(|show_selections_menu| !show_selections_menu)
20361            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20362
20363        cx.notify();
20364    }
20365
20366    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20367        self.show_selection_menu
20368            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20369    }
20370
20371    fn start_git_blame(
20372        &mut self,
20373        user_triggered: bool,
20374        window: &mut Window,
20375        cx: &mut Context<Self>,
20376    ) {
20377        if let Some(project) = self.project() {
20378            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20379                && buffer.read(cx).file().is_none()
20380            {
20381                return;
20382            }
20383
20384            let focused = self.focus_handle(cx).contains_focused(window, cx);
20385
20386            let project = project.clone();
20387            let blame = cx
20388                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20389            self.blame_subscription =
20390                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20391            self.blame = Some(blame);
20392        }
20393    }
20394
20395    fn toggle_git_blame_inline_internal(
20396        &mut self,
20397        user_triggered: bool,
20398        window: &mut Window,
20399        cx: &mut Context<Self>,
20400    ) {
20401        if self.git_blame_inline_enabled {
20402            self.git_blame_inline_enabled = false;
20403            self.show_git_blame_inline = false;
20404            self.show_git_blame_inline_delay_task.take();
20405        } else {
20406            self.git_blame_inline_enabled = true;
20407            self.start_git_blame_inline(user_triggered, window, cx);
20408        }
20409
20410        cx.notify();
20411    }
20412
20413    fn start_git_blame_inline(
20414        &mut self,
20415        user_triggered: bool,
20416        window: &mut Window,
20417        cx: &mut Context<Self>,
20418    ) {
20419        self.start_git_blame(user_triggered, window, cx);
20420
20421        if ProjectSettings::get_global(cx)
20422            .git
20423            .inline_blame_delay()
20424            .is_some()
20425        {
20426            self.start_inline_blame_timer(window, cx);
20427        } else {
20428            self.show_git_blame_inline = true
20429        }
20430    }
20431
20432    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20433        self.blame.as_ref()
20434    }
20435
20436    pub fn show_git_blame_gutter(&self) -> bool {
20437        self.show_git_blame_gutter
20438    }
20439
20440    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20441        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20442    }
20443
20444    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20445        self.show_git_blame_inline
20446            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20447            && !self.newest_selection_head_on_empty_line(cx)
20448            && self.has_blame_entries(cx)
20449    }
20450
20451    fn has_blame_entries(&self, cx: &App) -> bool {
20452        self.blame()
20453            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20454    }
20455
20456    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20457        let cursor_anchor = self.selections.newest_anchor().head();
20458
20459        let snapshot = self.buffer.read(cx).snapshot(cx);
20460        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20461
20462        snapshot.line_len(buffer_row) == 0
20463    }
20464
20465    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20466        let buffer_and_selection = maybe!({
20467            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20468            let selection_range = selection.range();
20469
20470            let multi_buffer = self.buffer().read(cx);
20471            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20472            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20473
20474            let (buffer, range, _) = if selection.reversed {
20475                buffer_ranges.first()
20476            } else {
20477                buffer_ranges.last()
20478            }?;
20479
20480            let selection = text::ToPoint::to_point(&range.start, buffer).row
20481                ..text::ToPoint::to_point(&range.end, buffer).row;
20482            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20483        });
20484
20485        let Some((buffer, selection)) = buffer_and_selection else {
20486            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20487        };
20488
20489        let Some(project) = self.project() else {
20490            return Task::ready(Err(anyhow!("editor does not have project")));
20491        };
20492
20493        project.update(cx, |project, cx| {
20494            project.get_permalink_to_line(&buffer, selection, cx)
20495        })
20496    }
20497
20498    pub fn copy_permalink_to_line(
20499        &mut self,
20500        _: &CopyPermalinkToLine,
20501        window: &mut Window,
20502        cx: &mut Context<Self>,
20503    ) {
20504        let permalink_task = self.get_permalink_to_line(cx);
20505        let workspace = self.workspace();
20506
20507        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20508            Ok(permalink) => {
20509                cx.update(|_, cx| {
20510                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20511                })
20512                .ok();
20513            }
20514            Err(err) => {
20515                let message = format!("Failed to copy permalink: {err}");
20516
20517                anyhow::Result::<()>::Err(err).log_err();
20518
20519                if let Some(workspace) = workspace {
20520                    workspace
20521                        .update_in(cx, |workspace, _, cx| {
20522                            struct CopyPermalinkToLine;
20523
20524                            workspace.show_toast(
20525                                Toast::new(
20526                                    NotificationId::unique::<CopyPermalinkToLine>(),
20527                                    message,
20528                                ),
20529                                cx,
20530                            )
20531                        })
20532                        .ok();
20533                }
20534            }
20535        })
20536        .detach();
20537    }
20538
20539    pub fn copy_file_location(
20540        &mut self,
20541        _: &CopyFileLocation,
20542        _: &mut Window,
20543        cx: &mut Context<Self>,
20544    ) {
20545        let selection = self
20546            .selections
20547            .newest::<Point>(&self.display_snapshot(cx))
20548            .start
20549            .row
20550            + 1;
20551        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20552            let project = self.project()?.read(cx);
20553            let file = buffer.read(cx).file()?;
20554            let path = file.path().display(project.path_style(cx));
20555
20556            Some(format!("{path}:{selection}"))
20557        }) {
20558            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20559        }
20560    }
20561
20562    pub fn open_permalink_to_line(
20563        &mut self,
20564        _: &OpenPermalinkToLine,
20565        window: &mut Window,
20566        cx: &mut Context<Self>,
20567    ) {
20568        let permalink_task = self.get_permalink_to_line(cx);
20569        let workspace = self.workspace();
20570
20571        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20572            Ok(permalink) => {
20573                cx.update(|_, cx| {
20574                    cx.open_url(permalink.as_ref());
20575                })
20576                .ok();
20577            }
20578            Err(err) => {
20579                let message = format!("Failed to open permalink: {err}");
20580
20581                anyhow::Result::<()>::Err(err).log_err();
20582
20583                if let Some(workspace) = workspace {
20584                    workspace
20585                        .update(cx, |workspace, cx| {
20586                            struct OpenPermalinkToLine;
20587
20588                            workspace.show_toast(
20589                                Toast::new(
20590                                    NotificationId::unique::<OpenPermalinkToLine>(),
20591                                    message,
20592                                ),
20593                                cx,
20594                            )
20595                        })
20596                        .ok();
20597                }
20598            }
20599        })
20600        .detach();
20601    }
20602
20603    pub fn insert_uuid_v4(
20604        &mut self,
20605        _: &InsertUuidV4,
20606        window: &mut Window,
20607        cx: &mut Context<Self>,
20608    ) {
20609        self.insert_uuid(UuidVersion::V4, window, cx);
20610    }
20611
20612    pub fn insert_uuid_v7(
20613        &mut self,
20614        _: &InsertUuidV7,
20615        window: &mut Window,
20616        cx: &mut Context<Self>,
20617    ) {
20618        self.insert_uuid(UuidVersion::V7, window, cx);
20619    }
20620
20621    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20623        self.transact(window, cx, |this, window, cx| {
20624            let edits = this
20625                .selections
20626                .all::<Point>(&this.display_snapshot(cx))
20627                .into_iter()
20628                .map(|selection| {
20629                    let uuid = match version {
20630                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20631                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20632                    };
20633
20634                    (selection.range(), uuid.to_string())
20635                });
20636            this.edit(edits, cx);
20637            this.refresh_edit_prediction(true, false, window, cx);
20638        });
20639    }
20640
20641    pub fn open_selections_in_multibuffer(
20642        &mut self,
20643        _: &OpenSelectionsInMultibuffer,
20644        window: &mut Window,
20645        cx: &mut Context<Self>,
20646    ) {
20647        let multibuffer = self.buffer.read(cx);
20648
20649        let Some(buffer) = multibuffer.as_singleton() else {
20650            return;
20651        };
20652
20653        let Some(workspace) = self.workspace() else {
20654            return;
20655        };
20656
20657        let title = multibuffer.title(cx).to_string();
20658
20659        let locations = self
20660            .selections
20661            .all_anchors(&self.display_snapshot(cx))
20662            .iter()
20663            .map(|selection| {
20664                (
20665                    buffer.clone(),
20666                    (selection.start.text_anchor..selection.end.text_anchor)
20667                        .to_point(buffer.read(cx)),
20668                )
20669            })
20670            .into_group_map();
20671
20672        cx.spawn_in(window, async move |_, cx| {
20673            workspace.update_in(cx, |workspace, window, cx| {
20674                Self::open_locations_in_multibuffer(
20675                    workspace,
20676                    locations,
20677                    format!("Selections for '{title}'"),
20678                    false,
20679                    MultibufferSelectionMode::All,
20680                    window,
20681                    cx,
20682                );
20683            })
20684        })
20685        .detach();
20686    }
20687
20688    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20689    /// last highlight added will be used.
20690    ///
20691    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20692    pub fn highlight_rows<T: 'static>(
20693        &mut self,
20694        range: Range<Anchor>,
20695        color: Hsla,
20696        options: RowHighlightOptions,
20697        cx: &mut Context<Self>,
20698    ) {
20699        let snapshot = self.buffer().read(cx).snapshot(cx);
20700        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20701        let ix = row_highlights.binary_search_by(|highlight| {
20702            Ordering::Equal
20703                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20704                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20705        });
20706
20707        if let Err(mut ix) = ix {
20708            let index = post_inc(&mut self.highlight_order);
20709
20710            // If this range intersects with the preceding highlight, then merge it with
20711            // the preceding highlight. Otherwise insert a new highlight.
20712            let mut merged = false;
20713            if ix > 0 {
20714                let prev_highlight = &mut row_highlights[ix - 1];
20715                if prev_highlight
20716                    .range
20717                    .end
20718                    .cmp(&range.start, &snapshot)
20719                    .is_ge()
20720                {
20721                    ix -= 1;
20722                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20723                        prev_highlight.range.end = range.end;
20724                    }
20725                    merged = true;
20726                    prev_highlight.index = index;
20727                    prev_highlight.color = color;
20728                    prev_highlight.options = options;
20729                }
20730            }
20731
20732            if !merged {
20733                row_highlights.insert(
20734                    ix,
20735                    RowHighlight {
20736                        range,
20737                        index,
20738                        color,
20739                        options,
20740                        type_id: TypeId::of::<T>(),
20741                    },
20742                );
20743            }
20744
20745            // If any of the following highlights intersect with this one, merge them.
20746            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20747                let highlight = &row_highlights[ix];
20748                if next_highlight
20749                    .range
20750                    .start
20751                    .cmp(&highlight.range.end, &snapshot)
20752                    .is_le()
20753                {
20754                    if next_highlight
20755                        .range
20756                        .end
20757                        .cmp(&highlight.range.end, &snapshot)
20758                        .is_gt()
20759                    {
20760                        row_highlights[ix].range.end = next_highlight.range.end;
20761                    }
20762                    row_highlights.remove(ix + 1);
20763                } else {
20764                    break;
20765                }
20766            }
20767        }
20768    }
20769
20770    /// Remove any highlighted row ranges of the given type that intersect the
20771    /// given ranges.
20772    pub fn remove_highlighted_rows<T: 'static>(
20773        &mut self,
20774        ranges_to_remove: Vec<Range<Anchor>>,
20775        cx: &mut Context<Self>,
20776    ) {
20777        let snapshot = self.buffer().read(cx).snapshot(cx);
20778        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20779        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20780        row_highlights.retain(|highlight| {
20781            while let Some(range_to_remove) = ranges_to_remove.peek() {
20782                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20783                    Ordering::Less | Ordering::Equal => {
20784                        ranges_to_remove.next();
20785                    }
20786                    Ordering::Greater => {
20787                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20788                            Ordering::Less | Ordering::Equal => {
20789                                return false;
20790                            }
20791                            Ordering::Greater => break,
20792                        }
20793                    }
20794                }
20795            }
20796
20797            true
20798        })
20799    }
20800
20801    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20802    pub fn clear_row_highlights<T: 'static>(&mut self) {
20803        self.highlighted_rows.remove(&TypeId::of::<T>());
20804    }
20805
20806    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20807    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20808        self.highlighted_rows
20809            .get(&TypeId::of::<T>())
20810            .map_or(&[] as &[_], |vec| vec.as_slice())
20811            .iter()
20812            .map(|highlight| (highlight.range.clone(), highlight.color))
20813    }
20814
20815    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20816    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20817    /// Allows to ignore certain kinds of highlights.
20818    pub fn highlighted_display_rows(
20819        &self,
20820        window: &mut Window,
20821        cx: &mut App,
20822    ) -> BTreeMap<DisplayRow, LineHighlight> {
20823        let snapshot = self.snapshot(window, cx);
20824        let mut used_highlight_orders = HashMap::default();
20825        self.highlighted_rows
20826            .iter()
20827            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20828            .fold(
20829                BTreeMap::<DisplayRow, LineHighlight>::new(),
20830                |mut unique_rows, highlight| {
20831                    let start = highlight.range.start.to_display_point(&snapshot);
20832                    let end = highlight.range.end.to_display_point(&snapshot);
20833                    let start_row = start.row().0;
20834                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20835                    {
20836                        end.row().0.saturating_sub(1)
20837                    } else {
20838                        end.row().0
20839                    };
20840                    for row in start_row..=end_row {
20841                        let used_index =
20842                            used_highlight_orders.entry(row).or_insert(highlight.index);
20843                        if highlight.index >= *used_index {
20844                            *used_index = highlight.index;
20845                            unique_rows.insert(
20846                                DisplayRow(row),
20847                                LineHighlight {
20848                                    include_gutter: highlight.options.include_gutter,
20849                                    border: None,
20850                                    background: highlight.color.into(),
20851                                    type_id: Some(highlight.type_id),
20852                                },
20853                            );
20854                        }
20855                    }
20856                    unique_rows
20857                },
20858            )
20859    }
20860
20861    pub fn highlighted_display_row_for_autoscroll(
20862        &self,
20863        snapshot: &DisplaySnapshot,
20864    ) -> Option<DisplayRow> {
20865        self.highlighted_rows
20866            .values()
20867            .flat_map(|highlighted_rows| highlighted_rows.iter())
20868            .filter_map(|highlight| {
20869                if highlight.options.autoscroll {
20870                    Some(highlight.range.start.to_display_point(snapshot).row())
20871                } else {
20872                    None
20873                }
20874            })
20875            .min()
20876    }
20877
20878    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20879        self.highlight_background::<SearchWithinRange>(
20880            ranges,
20881            |colors| colors.colors().editor_document_highlight_read_background,
20882            cx,
20883        )
20884    }
20885
20886    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20887        self.breadcrumb_header = Some(new_header);
20888    }
20889
20890    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20891        self.clear_background_highlights::<SearchWithinRange>(cx);
20892    }
20893
20894    pub fn highlight_background<T: 'static>(
20895        &mut self,
20896        ranges: &[Range<Anchor>],
20897        color_fetcher: fn(&Theme) -> Hsla,
20898        cx: &mut Context<Self>,
20899    ) {
20900        self.background_highlights.insert(
20901            HighlightKey::Type(TypeId::of::<T>()),
20902            (color_fetcher, Arc::from(ranges)),
20903        );
20904        self.scrollbar_marker_state.dirty = true;
20905        cx.notify();
20906    }
20907
20908    pub fn highlight_background_key<T: 'static>(
20909        &mut self,
20910        key: usize,
20911        ranges: &[Range<Anchor>],
20912        color_fetcher: fn(&Theme) -> Hsla,
20913        cx: &mut Context<Self>,
20914    ) {
20915        self.background_highlights.insert(
20916            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20917            (color_fetcher, Arc::from(ranges)),
20918        );
20919        self.scrollbar_marker_state.dirty = true;
20920        cx.notify();
20921    }
20922
20923    pub fn clear_background_highlights<T: 'static>(
20924        &mut self,
20925        cx: &mut Context<Self>,
20926    ) -> Option<BackgroundHighlight> {
20927        let text_highlights = self
20928            .background_highlights
20929            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20930        if !text_highlights.1.is_empty() {
20931            self.scrollbar_marker_state.dirty = true;
20932            cx.notify();
20933        }
20934        Some(text_highlights)
20935    }
20936
20937    pub fn highlight_gutter<T: 'static>(
20938        &mut self,
20939        ranges: impl Into<Vec<Range<Anchor>>>,
20940        color_fetcher: fn(&App) -> Hsla,
20941        cx: &mut Context<Self>,
20942    ) {
20943        self.gutter_highlights
20944            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20945        cx.notify();
20946    }
20947
20948    pub fn clear_gutter_highlights<T: 'static>(
20949        &mut self,
20950        cx: &mut Context<Self>,
20951    ) -> Option<GutterHighlight> {
20952        cx.notify();
20953        self.gutter_highlights.remove(&TypeId::of::<T>())
20954    }
20955
20956    pub fn insert_gutter_highlight<T: 'static>(
20957        &mut self,
20958        range: Range<Anchor>,
20959        color_fetcher: fn(&App) -> Hsla,
20960        cx: &mut Context<Self>,
20961    ) {
20962        let snapshot = self.buffer().read(cx).snapshot(cx);
20963        let mut highlights = self
20964            .gutter_highlights
20965            .remove(&TypeId::of::<T>())
20966            .map(|(_, highlights)| highlights)
20967            .unwrap_or_default();
20968        let ix = highlights.binary_search_by(|highlight| {
20969            Ordering::Equal
20970                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20971                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20972        });
20973        if let Err(ix) = ix {
20974            highlights.insert(ix, range);
20975        }
20976        self.gutter_highlights
20977            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20978    }
20979
20980    pub fn remove_gutter_highlights<T: 'static>(
20981        &mut self,
20982        ranges_to_remove: Vec<Range<Anchor>>,
20983        cx: &mut Context<Self>,
20984    ) {
20985        let snapshot = self.buffer().read(cx).snapshot(cx);
20986        let Some((color_fetcher, mut gutter_highlights)) =
20987            self.gutter_highlights.remove(&TypeId::of::<T>())
20988        else {
20989            return;
20990        };
20991        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20992        gutter_highlights.retain(|highlight| {
20993            while let Some(range_to_remove) = ranges_to_remove.peek() {
20994                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20995                    Ordering::Less | Ordering::Equal => {
20996                        ranges_to_remove.next();
20997                    }
20998                    Ordering::Greater => {
20999                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21000                            Ordering::Less | Ordering::Equal => {
21001                                return false;
21002                            }
21003                            Ordering::Greater => break,
21004                        }
21005                    }
21006                }
21007            }
21008
21009            true
21010        });
21011        self.gutter_highlights
21012            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21013    }
21014
21015    #[cfg(feature = "test-support")]
21016    pub fn all_text_highlights(
21017        &self,
21018        window: &mut Window,
21019        cx: &mut Context<Self>,
21020    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21021        let snapshot = self.snapshot(window, cx);
21022        self.display_map.update(cx, |display_map, _| {
21023            display_map
21024                .all_text_highlights()
21025                .map(|highlight| {
21026                    let (style, ranges) = highlight.as_ref();
21027                    (
21028                        *style,
21029                        ranges
21030                            .iter()
21031                            .map(|range| range.clone().to_display_points(&snapshot))
21032                            .collect(),
21033                    )
21034                })
21035                .collect()
21036        })
21037    }
21038
21039    #[cfg(feature = "test-support")]
21040    pub fn all_text_background_highlights(
21041        &self,
21042        window: &mut Window,
21043        cx: &mut Context<Self>,
21044    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21045        let snapshot = self.snapshot(window, cx);
21046        let buffer = &snapshot.buffer_snapshot();
21047        let start = buffer.anchor_before(MultiBufferOffset(0));
21048        let end = buffer.anchor_after(buffer.len());
21049        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21050    }
21051
21052    #[cfg(any(test, feature = "test-support"))]
21053    pub fn sorted_background_highlights_in_range(
21054        &self,
21055        search_range: Range<Anchor>,
21056        display_snapshot: &DisplaySnapshot,
21057        theme: &Theme,
21058    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21059        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21060        res.sort_by(|a, b| {
21061            a.0.start
21062                .cmp(&b.0.start)
21063                .then_with(|| a.0.end.cmp(&b.0.end))
21064                .then_with(|| a.1.cmp(&b.1))
21065        });
21066        res
21067    }
21068
21069    #[cfg(feature = "test-support")]
21070    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21071        let snapshot = self.buffer().read(cx).snapshot(cx);
21072
21073        let highlights = self
21074            .background_highlights
21075            .get(&HighlightKey::Type(TypeId::of::<
21076                items::BufferSearchHighlights,
21077            >()));
21078
21079        if let Some((_color, ranges)) = highlights {
21080            ranges
21081                .iter()
21082                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21083                .collect_vec()
21084        } else {
21085            vec![]
21086        }
21087    }
21088
21089    fn document_highlights_for_position<'a>(
21090        &'a self,
21091        position: Anchor,
21092        buffer: &'a MultiBufferSnapshot,
21093    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21094        let read_highlights = self
21095            .background_highlights
21096            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21097            .map(|h| &h.1);
21098        let write_highlights = self
21099            .background_highlights
21100            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21101            .map(|h| &h.1);
21102        let left_position = position.bias_left(buffer);
21103        let right_position = position.bias_right(buffer);
21104        read_highlights
21105            .into_iter()
21106            .chain(write_highlights)
21107            .flat_map(move |ranges| {
21108                let start_ix = match ranges.binary_search_by(|probe| {
21109                    let cmp = probe.end.cmp(&left_position, buffer);
21110                    if cmp.is_ge() {
21111                        Ordering::Greater
21112                    } else {
21113                        Ordering::Less
21114                    }
21115                }) {
21116                    Ok(i) | Err(i) => i,
21117                };
21118
21119                ranges[start_ix..]
21120                    .iter()
21121                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21122            })
21123    }
21124
21125    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21126        self.background_highlights
21127            .get(&HighlightKey::Type(TypeId::of::<T>()))
21128            .is_some_and(|(_, highlights)| !highlights.is_empty())
21129    }
21130
21131    /// Returns all background highlights for a given range.
21132    ///
21133    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21134    pub fn background_highlights_in_range(
21135        &self,
21136        search_range: Range<Anchor>,
21137        display_snapshot: &DisplaySnapshot,
21138        theme: &Theme,
21139    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21140        let mut results = Vec::new();
21141        for (color_fetcher, ranges) in self.background_highlights.values() {
21142            let color = color_fetcher(theme);
21143            let start_ix = match ranges.binary_search_by(|probe| {
21144                let cmp = probe
21145                    .end
21146                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21147                if cmp.is_gt() {
21148                    Ordering::Greater
21149                } else {
21150                    Ordering::Less
21151                }
21152            }) {
21153                Ok(i) | Err(i) => i,
21154            };
21155            for range in &ranges[start_ix..] {
21156                if range
21157                    .start
21158                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21159                    .is_ge()
21160                {
21161                    break;
21162                }
21163
21164                let start = range.start.to_display_point(display_snapshot);
21165                let end = range.end.to_display_point(display_snapshot);
21166                results.push((start..end, color))
21167            }
21168        }
21169        results
21170    }
21171
21172    pub fn gutter_highlights_in_range(
21173        &self,
21174        search_range: Range<Anchor>,
21175        display_snapshot: &DisplaySnapshot,
21176        cx: &App,
21177    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21178        let mut results = Vec::new();
21179        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21180            let color = color_fetcher(cx);
21181            let start_ix = match ranges.binary_search_by(|probe| {
21182                let cmp = probe
21183                    .end
21184                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21185                if cmp.is_gt() {
21186                    Ordering::Greater
21187                } else {
21188                    Ordering::Less
21189                }
21190            }) {
21191                Ok(i) | Err(i) => i,
21192            };
21193            for range in &ranges[start_ix..] {
21194                if range
21195                    .start
21196                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21197                    .is_ge()
21198                {
21199                    break;
21200                }
21201
21202                let start = range.start.to_display_point(display_snapshot);
21203                let end = range.end.to_display_point(display_snapshot);
21204                results.push((start..end, color))
21205            }
21206        }
21207        results
21208    }
21209
21210    /// Get the text ranges corresponding to the redaction query
21211    pub fn redacted_ranges(
21212        &self,
21213        search_range: Range<Anchor>,
21214        display_snapshot: &DisplaySnapshot,
21215        cx: &App,
21216    ) -> Vec<Range<DisplayPoint>> {
21217        display_snapshot
21218            .buffer_snapshot()
21219            .redacted_ranges(search_range, |file| {
21220                if let Some(file) = file {
21221                    file.is_private()
21222                        && EditorSettings::get(
21223                            Some(SettingsLocation {
21224                                worktree_id: file.worktree_id(cx),
21225                                path: file.path().as_ref(),
21226                            }),
21227                            cx,
21228                        )
21229                        .redact_private_values
21230                } else {
21231                    false
21232                }
21233            })
21234            .map(|range| {
21235                range.start.to_display_point(display_snapshot)
21236                    ..range.end.to_display_point(display_snapshot)
21237            })
21238            .collect()
21239    }
21240
21241    pub fn highlight_text_key<T: 'static>(
21242        &mut self,
21243        key: usize,
21244        ranges: Vec<Range<Anchor>>,
21245        style: HighlightStyle,
21246        merge: bool,
21247        cx: &mut Context<Self>,
21248    ) {
21249        self.display_map.update(cx, |map, cx| {
21250            map.highlight_text(
21251                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21252                ranges,
21253                style,
21254                merge,
21255                cx,
21256            );
21257        });
21258        cx.notify();
21259    }
21260
21261    pub fn highlight_text<T: 'static>(
21262        &mut self,
21263        ranges: Vec<Range<Anchor>>,
21264        style: HighlightStyle,
21265        cx: &mut Context<Self>,
21266    ) {
21267        self.display_map.update(cx, |map, cx| {
21268            map.highlight_text(
21269                HighlightKey::Type(TypeId::of::<T>()),
21270                ranges,
21271                style,
21272                false,
21273                cx,
21274            )
21275        });
21276        cx.notify();
21277    }
21278
21279    pub fn text_highlights<'a, T: 'static>(
21280        &'a self,
21281        cx: &'a App,
21282    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21283        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21284    }
21285
21286    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21287        let cleared = self
21288            .display_map
21289            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21290        if cleared {
21291            cx.notify();
21292        }
21293    }
21294
21295    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21296        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21297            && self.focus_handle.is_focused(window)
21298    }
21299
21300    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21301        self.show_cursor_when_unfocused = is_enabled;
21302        cx.notify();
21303    }
21304
21305    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21306        cx.notify();
21307    }
21308
21309    fn on_debug_session_event(
21310        &mut self,
21311        _session: Entity<Session>,
21312        event: &SessionEvent,
21313        cx: &mut Context<Self>,
21314    ) {
21315        if let SessionEvent::InvalidateInlineValue = event {
21316            self.refresh_inline_values(cx);
21317        }
21318    }
21319
21320    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21321        let Some(project) = self.project.clone() else {
21322            return;
21323        };
21324
21325        if !self.inline_value_cache.enabled {
21326            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21327            self.splice_inlays(&inlays, Vec::new(), cx);
21328            return;
21329        }
21330
21331        let current_execution_position = self
21332            .highlighted_rows
21333            .get(&TypeId::of::<ActiveDebugLine>())
21334            .and_then(|lines| lines.last().map(|line| line.range.end));
21335
21336        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21337            let inline_values = editor
21338                .update(cx, |editor, cx| {
21339                    let Some(current_execution_position) = current_execution_position else {
21340                        return Some(Task::ready(Ok(Vec::new())));
21341                    };
21342
21343                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21344                        let snapshot = buffer.snapshot(cx);
21345
21346                        let excerpt = snapshot.excerpt_containing(
21347                            current_execution_position..current_execution_position,
21348                        )?;
21349
21350                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21351                    })?;
21352
21353                    let range =
21354                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21355
21356                    project.inline_values(buffer, range, cx)
21357                })
21358                .ok()
21359                .flatten()?
21360                .await
21361                .context("refreshing debugger inlays")
21362                .log_err()?;
21363
21364            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21365
21366            for (buffer_id, inline_value) in inline_values
21367                .into_iter()
21368                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21369            {
21370                buffer_inline_values
21371                    .entry(buffer_id)
21372                    .or_default()
21373                    .push(inline_value);
21374            }
21375
21376            editor
21377                .update(cx, |editor, cx| {
21378                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21379                    let mut new_inlays = Vec::default();
21380
21381                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21382                        let buffer_id = buffer_snapshot.remote_id();
21383                        buffer_inline_values
21384                            .get(&buffer_id)
21385                            .into_iter()
21386                            .flatten()
21387                            .for_each(|hint| {
21388                                let inlay = Inlay::debugger(
21389                                    post_inc(&mut editor.next_inlay_id),
21390                                    Anchor::in_buffer(excerpt_id, hint.position),
21391                                    hint.text(),
21392                                );
21393                                if !inlay.text().chars().contains(&'\n') {
21394                                    new_inlays.push(inlay);
21395                                }
21396                            });
21397                    }
21398
21399                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21400                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21401
21402                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21403                })
21404                .ok()?;
21405            Some(())
21406        });
21407    }
21408
21409    fn on_buffer_event(
21410        &mut self,
21411        multibuffer: &Entity<MultiBuffer>,
21412        event: &multi_buffer::Event,
21413        window: &mut Window,
21414        cx: &mut Context<Self>,
21415    ) {
21416        match event {
21417            multi_buffer::Event::Edited { edited_buffer } => {
21418                self.scrollbar_marker_state.dirty = true;
21419                self.active_indent_guides_state.dirty = true;
21420                self.refresh_active_diagnostics(cx);
21421                self.refresh_code_actions(window, cx);
21422                self.refresh_single_line_folds(window, cx);
21423                self.refresh_matching_bracket_highlights(window, cx);
21424                if self.has_active_edit_prediction() {
21425                    self.update_visible_edit_prediction(window, cx);
21426                }
21427
21428                if let Some(buffer) = edited_buffer {
21429                    if buffer.read(cx).file().is_none() {
21430                        cx.emit(EditorEvent::TitleChanged);
21431                    }
21432
21433                    if self.project.is_some() {
21434                        let buffer_id = buffer.read(cx).remote_id();
21435                        self.register_buffer(buffer_id, cx);
21436                        self.update_lsp_data(Some(buffer_id), window, cx);
21437                        self.refresh_inlay_hints(
21438                            InlayHintRefreshReason::BufferEdited(buffer_id),
21439                            cx,
21440                        );
21441                    }
21442                }
21443
21444                cx.emit(EditorEvent::BufferEdited);
21445                cx.emit(SearchEvent::MatchesInvalidated);
21446
21447                let Some(project) = &self.project else { return };
21448                let (telemetry, is_via_ssh) = {
21449                    let project = project.read(cx);
21450                    let telemetry = project.client().telemetry().clone();
21451                    let is_via_ssh = project.is_via_remote_server();
21452                    (telemetry, is_via_ssh)
21453                };
21454                telemetry.log_edit_event("editor", is_via_ssh);
21455            }
21456            multi_buffer::Event::ExcerptsAdded {
21457                buffer,
21458                predecessor,
21459                excerpts,
21460            } => {
21461                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21462                let buffer_id = buffer.read(cx).remote_id();
21463                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21464                    && let Some(project) = &self.project
21465                {
21466                    update_uncommitted_diff_for_buffer(
21467                        cx.entity(),
21468                        project,
21469                        [buffer.clone()],
21470                        self.buffer.clone(),
21471                        cx,
21472                    )
21473                    .detach();
21474                }
21475                self.update_lsp_data(Some(buffer_id), window, cx);
21476                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21477                self.colorize_brackets(false, cx);
21478                cx.emit(EditorEvent::ExcerptsAdded {
21479                    buffer: buffer.clone(),
21480                    predecessor: *predecessor,
21481                    excerpts: excerpts.clone(),
21482                });
21483            }
21484            multi_buffer::Event::ExcerptsRemoved {
21485                ids,
21486                removed_buffer_ids,
21487            } => {
21488                if let Some(inlay_hints) = &mut self.inlay_hints {
21489                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21490                }
21491                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21492                for buffer_id in removed_buffer_ids {
21493                    self.registered_buffers.remove(buffer_id);
21494                }
21495                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21496                cx.emit(EditorEvent::ExcerptsRemoved {
21497                    ids: ids.clone(),
21498                    removed_buffer_ids: removed_buffer_ids.clone(),
21499                });
21500            }
21501            multi_buffer::Event::ExcerptsEdited {
21502                excerpt_ids,
21503                buffer_ids,
21504            } => {
21505                self.display_map.update(cx, |map, cx| {
21506                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21507                });
21508                cx.emit(EditorEvent::ExcerptsEdited {
21509                    ids: excerpt_ids.clone(),
21510                });
21511            }
21512            multi_buffer::Event::ExcerptsExpanded { ids } => {
21513                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21514                self.refresh_document_highlights(cx);
21515                for id in ids {
21516                    self.fetched_tree_sitter_chunks.remove(id);
21517                }
21518                self.colorize_brackets(false, cx);
21519                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21520            }
21521            multi_buffer::Event::Reparsed(buffer_id) => {
21522                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21523                self.refresh_selected_text_highlights(true, window, cx);
21524                self.colorize_brackets(true, cx);
21525                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21526
21527                cx.emit(EditorEvent::Reparsed(*buffer_id));
21528            }
21529            multi_buffer::Event::DiffHunksToggled => {
21530                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21531            }
21532            multi_buffer::Event::LanguageChanged(buffer_id) => {
21533                self.registered_buffers.remove(&buffer_id);
21534                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21535                cx.emit(EditorEvent::Reparsed(*buffer_id));
21536                cx.notify();
21537            }
21538            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21539            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21540            multi_buffer::Event::FileHandleChanged
21541            | multi_buffer::Event::Reloaded
21542            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21543            multi_buffer::Event::DiagnosticsUpdated => {
21544                self.update_diagnostics_state(window, cx);
21545            }
21546            _ => {}
21547        };
21548    }
21549
21550    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21551        if !self.diagnostics_enabled() {
21552            return;
21553        }
21554        self.refresh_active_diagnostics(cx);
21555        self.refresh_inline_diagnostics(true, window, cx);
21556        self.scrollbar_marker_state.dirty = true;
21557        cx.notify();
21558    }
21559
21560    pub fn start_temporary_diff_override(&mut self) {
21561        self.load_diff_task.take();
21562        self.temporary_diff_override = true;
21563    }
21564
21565    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21566        self.temporary_diff_override = false;
21567        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21568        self.buffer.update(cx, |buffer, cx| {
21569            buffer.set_all_diff_hunks_collapsed(cx);
21570        });
21571
21572        if let Some(project) = self.project.clone() {
21573            self.load_diff_task = Some(
21574                update_uncommitted_diff_for_buffer(
21575                    cx.entity(),
21576                    &project,
21577                    self.buffer.read(cx).all_buffers(),
21578                    self.buffer.clone(),
21579                    cx,
21580                )
21581                .shared(),
21582            );
21583        }
21584    }
21585
21586    fn on_display_map_changed(
21587        &mut self,
21588        _: Entity<DisplayMap>,
21589        _: &mut Window,
21590        cx: &mut Context<Self>,
21591    ) {
21592        cx.notify();
21593    }
21594
21595    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21596        if !self.mode.is_full() {
21597            return Vec::new();
21598        }
21599
21600        let theme_settings = theme::ThemeSettings::get_global(cx);
21601
21602        theme_settings
21603            .theme_overrides
21604            .get(cx.theme().name.as_ref())
21605            .map(|theme_style| &theme_style.accents)
21606            .into_iter()
21607            .flatten()
21608            .chain(
21609                theme_settings
21610                    .experimental_theme_overrides
21611                    .as_ref()
21612                    .map(|overrides| &overrides.accents)
21613                    .into_iter()
21614                    .flatten(),
21615            )
21616            .flat_map(|accent| accent.0.clone())
21617            .collect()
21618    }
21619
21620    fn fetch_applicable_language_settings(
21621        &self,
21622        cx: &App,
21623    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21624        if !self.mode.is_full() {
21625            return HashMap::default();
21626        }
21627
21628        self.buffer().read(cx).all_buffers().into_iter().fold(
21629            HashMap::default(),
21630            |mut acc, buffer| {
21631                let buffer = buffer.read(cx);
21632                let language = buffer.language().map(|language| language.name());
21633                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21634                    let file = buffer.file();
21635                    v.insert(language_settings(language, file, cx).into_owned());
21636                }
21637                acc
21638            },
21639        )
21640    }
21641
21642    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21643        let new_language_settings = self.fetch_applicable_language_settings(cx);
21644        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21645        self.applicable_language_settings = new_language_settings;
21646
21647        let new_accent_overrides = self.fetch_accent_overrides(cx);
21648        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21649        self.accent_overrides = new_accent_overrides;
21650
21651        if self.diagnostics_enabled() {
21652            let new_severity = EditorSettings::get_global(cx)
21653                .diagnostics_max_severity
21654                .unwrap_or(DiagnosticSeverity::Hint);
21655            self.set_max_diagnostics_severity(new_severity, cx);
21656        }
21657        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21658        self.update_edit_prediction_settings(cx);
21659        self.refresh_edit_prediction(true, false, window, cx);
21660        self.refresh_inline_values(cx);
21661        self.refresh_inlay_hints(
21662            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21663                self.selections.newest_anchor().head(),
21664                &self.buffer.read(cx).snapshot(cx),
21665                cx,
21666            )),
21667            cx,
21668        );
21669
21670        let old_cursor_shape = self.cursor_shape;
21671        let old_show_breadcrumbs = self.show_breadcrumbs;
21672
21673        {
21674            let editor_settings = EditorSettings::get_global(cx);
21675            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21676            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21677            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21678            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21679        }
21680
21681        if old_cursor_shape != self.cursor_shape {
21682            cx.emit(EditorEvent::CursorShapeChanged);
21683        }
21684
21685        if old_show_breadcrumbs != self.show_breadcrumbs {
21686            cx.emit(EditorEvent::BreadcrumbsChanged);
21687        }
21688
21689        let project_settings = ProjectSettings::get_global(cx);
21690        self.buffer_serialization = self
21691            .should_serialize_buffer()
21692            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21693
21694        if self.mode.is_full() {
21695            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21696            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21697            if self.show_inline_diagnostics != show_inline_diagnostics {
21698                self.show_inline_diagnostics = show_inline_diagnostics;
21699                self.refresh_inline_diagnostics(false, window, cx);
21700            }
21701
21702            if self.git_blame_inline_enabled != inline_blame_enabled {
21703                self.toggle_git_blame_inline_internal(false, window, cx);
21704            }
21705
21706            let minimap_settings = EditorSettings::get_global(cx).minimap;
21707            if self.minimap_visibility != MinimapVisibility::Disabled {
21708                if self.minimap_visibility.settings_visibility()
21709                    != minimap_settings.minimap_enabled()
21710                {
21711                    self.set_minimap_visibility(
21712                        MinimapVisibility::for_mode(self.mode(), cx),
21713                        window,
21714                        cx,
21715                    );
21716                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21717                    minimap_entity.update(cx, |minimap_editor, cx| {
21718                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21719                    })
21720                }
21721            }
21722
21723            if language_settings_changed || accent_overrides_changed {
21724                self.colorize_brackets(true, cx);
21725            }
21726
21727            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21728                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21729            }) {
21730                if !inlay_splice.is_empty() {
21731                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21732                }
21733                self.refresh_colors_for_visible_range(None, window, cx);
21734            }
21735        }
21736
21737        cx.notify();
21738    }
21739
21740    pub fn set_searchable(&mut self, searchable: bool) {
21741        self.searchable = searchable;
21742    }
21743
21744    pub fn searchable(&self) -> bool {
21745        self.searchable
21746    }
21747
21748    pub fn open_excerpts_in_split(
21749        &mut self,
21750        _: &OpenExcerptsSplit,
21751        window: &mut Window,
21752        cx: &mut Context<Self>,
21753    ) {
21754        self.open_excerpts_common(None, true, window, cx)
21755    }
21756
21757    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21758        self.open_excerpts_common(None, false, window, cx)
21759    }
21760
21761    fn open_excerpts_common(
21762        &mut self,
21763        jump_data: Option<JumpData>,
21764        split: bool,
21765        window: &mut Window,
21766        cx: &mut Context<Self>,
21767    ) {
21768        let Some(workspace) = self.workspace() else {
21769            cx.propagate();
21770            return;
21771        };
21772
21773        if self.buffer.read(cx).is_singleton() {
21774            cx.propagate();
21775            return;
21776        }
21777
21778        let mut new_selections_by_buffer = HashMap::default();
21779        match &jump_data {
21780            Some(JumpData::MultiBufferPoint {
21781                excerpt_id,
21782                position,
21783                anchor,
21784                line_offset_from_top,
21785            }) => {
21786                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21787                if let Some(buffer) = multi_buffer_snapshot
21788                    .buffer_id_for_excerpt(*excerpt_id)
21789                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21790                {
21791                    let buffer_snapshot = buffer.read(cx).snapshot();
21792                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21793                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21794                    } else {
21795                        buffer_snapshot.clip_point(*position, Bias::Left)
21796                    };
21797                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21798                    new_selections_by_buffer.insert(
21799                        buffer,
21800                        (
21801                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21802                            Some(*line_offset_from_top),
21803                        ),
21804                    );
21805                }
21806            }
21807            Some(JumpData::MultiBufferRow {
21808                row,
21809                line_offset_from_top,
21810            }) => {
21811                let point = MultiBufferPoint::new(row.0, 0);
21812                if let Some((buffer, buffer_point, _)) =
21813                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21814                {
21815                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21816                    new_selections_by_buffer
21817                        .entry(buffer)
21818                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21819                        .0
21820                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21821                }
21822            }
21823            None => {
21824                let selections = self
21825                    .selections
21826                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21827                let multi_buffer = self.buffer.read(cx);
21828                for selection in selections {
21829                    for (snapshot, range, _, anchor) in multi_buffer
21830                        .snapshot(cx)
21831                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21832                    {
21833                        if let Some(anchor) = anchor {
21834                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21835                            else {
21836                                continue;
21837                            };
21838                            let offset = text::ToOffset::to_offset(
21839                                &anchor.text_anchor,
21840                                &buffer_handle.read(cx).snapshot(),
21841                            );
21842                            let range = BufferOffset(offset)..BufferOffset(offset);
21843                            new_selections_by_buffer
21844                                .entry(buffer_handle)
21845                                .or_insert((Vec::new(), None))
21846                                .0
21847                                .push(range)
21848                        } else {
21849                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21850                            else {
21851                                continue;
21852                            };
21853                            new_selections_by_buffer
21854                                .entry(buffer_handle)
21855                                .or_insert((Vec::new(), None))
21856                                .0
21857                                .push(range)
21858                        }
21859                    }
21860                }
21861            }
21862        }
21863
21864        new_selections_by_buffer
21865            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21866
21867        if new_selections_by_buffer.is_empty() {
21868            return;
21869        }
21870
21871        // We defer the pane interaction because we ourselves are a workspace item
21872        // and activating a new item causes the pane to call a method on us reentrantly,
21873        // which panics if we're on the stack.
21874        window.defer(cx, move |window, cx| {
21875            workspace.update(cx, |workspace, cx| {
21876                let pane = if split {
21877                    workspace.adjacent_pane(window, cx)
21878                } else {
21879                    workspace.active_pane().clone()
21880                };
21881
21882                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21883                    let editor = buffer
21884                        .read(cx)
21885                        .file()
21886                        .is_none()
21887                        .then(|| {
21888                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21889                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21890                            // Instead, we try to activate the existing editor in the pane first.
21891                            let (editor, pane_item_index) =
21892                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21893                                    let editor = item.downcast::<Editor>()?;
21894                                    let singleton_buffer =
21895                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21896                                    if singleton_buffer == buffer {
21897                                        Some((editor, i))
21898                                    } else {
21899                                        None
21900                                    }
21901                                })?;
21902                            pane.update(cx, |pane, cx| {
21903                                pane.activate_item(pane_item_index, true, true, window, cx)
21904                            });
21905                            Some(editor)
21906                        })
21907                        .flatten()
21908                        .unwrap_or_else(|| {
21909                            workspace.open_project_item::<Self>(
21910                                pane.clone(),
21911                                buffer,
21912                                true,
21913                                true,
21914                                window,
21915                                cx,
21916                            )
21917                        });
21918
21919                    editor.update(cx, |editor, cx| {
21920                        let autoscroll = match scroll_offset {
21921                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21922                            None => Autoscroll::newest(),
21923                        };
21924                        let nav_history = editor.nav_history.take();
21925                        editor.change_selections(
21926                            SelectionEffects::scroll(autoscroll),
21927                            window,
21928                            cx,
21929                            |s| {
21930                                s.select_ranges(ranges.into_iter().map(|range| {
21931                                    // we checked that the editor is a singleton editor so the offsets are valid
21932                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21933                                }));
21934                            },
21935                        );
21936                        editor.nav_history = nav_history;
21937                    });
21938                }
21939            })
21940        });
21941    }
21942
21943    // For now, don't allow opening excerpts in buffers that aren't backed by
21944    // regular project files.
21945    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21946        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21947    }
21948
21949    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21950        let snapshot = self.buffer.read(cx).read(cx);
21951        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21952        Some(
21953            ranges
21954                .iter()
21955                .map(move |range| {
21956                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21957                })
21958                .collect(),
21959        )
21960    }
21961
21962    fn selection_replacement_ranges(
21963        &self,
21964        range: Range<MultiBufferOffsetUtf16>,
21965        cx: &mut App,
21966    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21967        let selections = self
21968            .selections
21969            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21970        let newest_selection = selections
21971            .iter()
21972            .max_by_key(|selection| selection.id)
21973            .unwrap();
21974        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21975        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21976        let snapshot = self.buffer.read(cx).read(cx);
21977        selections
21978            .into_iter()
21979            .map(|mut selection| {
21980                selection.start.0.0 =
21981                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21982                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21983                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21984                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21985            })
21986            .collect()
21987    }
21988
21989    fn report_editor_event(
21990        &self,
21991        reported_event: ReportEditorEvent,
21992        file_extension: Option<String>,
21993        cx: &App,
21994    ) {
21995        if cfg!(any(test, feature = "test-support")) {
21996            return;
21997        }
21998
21999        let Some(project) = &self.project else { return };
22000
22001        // If None, we are in a file without an extension
22002        let file = self
22003            .buffer
22004            .read(cx)
22005            .as_singleton()
22006            .and_then(|b| b.read(cx).file());
22007        let file_extension = file_extension.or(file
22008            .as_ref()
22009            .and_then(|file| Path::new(file.file_name(cx)).extension())
22010            .and_then(|e| e.to_str())
22011            .map(|a| a.to_string()));
22012
22013        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22014            .map(|vim_mode| vim_mode.0)
22015            .unwrap_or(false);
22016
22017        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22018        let copilot_enabled = edit_predictions_provider
22019            == language::language_settings::EditPredictionProvider::Copilot;
22020        let copilot_enabled_for_language = self
22021            .buffer
22022            .read(cx)
22023            .language_settings(cx)
22024            .show_edit_predictions;
22025
22026        let project = project.read(cx);
22027        let event_type = reported_event.event_type();
22028
22029        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22030            telemetry::event!(
22031                event_type,
22032                type = if auto_saved {"autosave"} else {"manual"},
22033                file_extension,
22034                vim_mode,
22035                copilot_enabled,
22036                copilot_enabled_for_language,
22037                edit_predictions_provider,
22038                is_via_ssh = project.is_via_remote_server(),
22039            );
22040        } else {
22041            telemetry::event!(
22042                event_type,
22043                file_extension,
22044                vim_mode,
22045                copilot_enabled,
22046                copilot_enabled_for_language,
22047                edit_predictions_provider,
22048                is_via_ssh = project.is_via_remote_server(),
22049            );
22050        };
22051    }
22052
22053    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22054    /// with each line being an array of {text, highlight} objects.
22055    fn copy_highlight_json(
22056        &mut self,
22057        _: &CopyHighlightJson,
22058        window: &mut Window,
22059        cx: &mut Context<Self>,
22060    ) {
22061        #[derive(Serialize)]
22062        struct Chunk<'a> {
22063            text: String,
22064            highlight: Option<&'a str>,
22065        }
22066
22067        let snapshot = self.buffer.read(cx).snapshot(cx);
22068        let range = self
22069            .selected_text_range(false, window, cx)
22070            .and_then(|selection| {
22071                if selection.range.is_empty() {
22072                    None
22073                } else {
22074                    Some(
22075                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22076                            selection.range.start,
22077                        )))
22078                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22079                                selection.range.end,
22080                            ))),
22081                    )
22082                }
22083            })
22084            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22085
22086        let chunks = snapshot.chunks(range, true);
22087        let mut lines = Vec::new();
22088        let mut line: VecDeque<Chunk> = VecDeque::new();
22089
22090        let Some(style) = self.style.as_ref() else {
22091            return;
22092        };
22093
22094        for chunk in chunks {
22095            let highlight = chunk
22096                .syntax_highlight_id
22097                .and_then(|id| id.name(&style.syntax));
22098            let mut chunk_lines = chunk.text.split('\n').peekable();
22099            while let Some(text) = chunk_lines.next() {
22100                let mut merged_with_last_token = false;
22101                if let Some(last_token) = line.back_mut()
22102                    && last_token.highlight == highlight
22103                {
22104                    last_token.text.push_str(text);
22105                    merged_with_last_token = true;
22106                }
22107
22108                if !merged_with_last_token {
22109                    line.push_back(Chunk {
22110                        text: text.into(),
22111                        highlight,
22112                    });
22113                }
22114
22115                if chunk_lines.peek().is_some() {
22116                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22117                        line.pop_front();
22118                    }
22119                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22120                        line.pop_back();
22121                    }
22122
22123                    lines.push(mem::take(&mut line));
22124                }
22125            }
22126        }
22127
22128        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22129            return;
22130        };
22131        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22132    }
22133
22134    pub fn open_context_menu(
22135        &mut self,
22136        _: &OpenContextMenu,
22137        window: &mut Window,
22138        cx: &mut Context<Self>,
22139    ) {
22140        self.request_autoscroll(Autoscroll::newest(), cx);
22141        let position = self
22142            .selections
22143            .newest_display(&self.display_snapshot(cx))
22144            .start;
22145        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22146    }
22147
22148    pub fn replay_insert_event(
22149        &mut self,
22150        text: &str,
22151        relative_utf16_range: Option<Range<isize>>,
22152        window: &mut Window,
22153        cx: &mut Context<Self>,
22154    ) {
22155        if !self.input_enabled {
22156            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22157            return;
22158        }
22159        if let Some(relative_utf16_range) = relative_utf16_range {
22160            let selections = self
22161                .selections
22162                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22163            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22164                let new_ranges = selections.into_iter().map(|range| {
22165                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22166                        range
22167                            .head()
22168                            .0
22169                            .0
22170                            .saturating_add_signed(relative_utf16_range.start),
22171                    ));
22172                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22173                        range
22174                            .head()
22175                            .0
22176                            .0
22177                            .saturating_add_signed(relative_utf16_range.end),
22178                    ));
22179                    start..end
22180                });
22181                s.select_ranges(new_ranges);
22182            });
22183        }
22184
22185        self.handle_input(text, window, cx);
22186    }
22187
22188    pub fn is_focused(&self, window: &Window) -> bool {
22189        self.focus_handle.is_focused(window)
22190    }
22191
22192    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22193        cx.emit(EditorEvent::Focused);
22194
22195        if let Some(descendant) = self
22196            .last_focused_descendant
22197            .take()
22198            .and_then(|descendant| descendant.upgrade())
22199        {
22200            window.focus(&descendant);
22201        } else {
22202            if let Some(blame) = self.blame.as_ref() {
22203                blame.update(cx, GitBlame::focus)
22204            }
22205
22206            self.blink_manager.update(cx, BlinkManager::enable);
22207            self.show_cursor_names(window, cx);
22208            self.buffer.update(cx, |buffer, cx| {
22209                buffer.finalize_last_transaction(cx);
22210                if self.leader_id.is_none() {
22211                    buffer.set_active_selections(
22212                        &self.selections.disjoint_anchors_arc(),
22213                        self.selections.line_mode(),
22214                        self.cursor_shape,
22215                        cx,
22216                    );
22217                }
22218            });
22219
22220            if let Some(position_map) = self.last_position_map.clone() {
22221                EditorElement::mouse_moved(
22222                    self,
22223                    &MouseMoveEvent {
22224                        position: window.mouse_position(),
22225                        pressed_button: None,
22226                        modifiers: window.modifiers(),
22227                    },
22228                    &position_map,
22229                    window,
22230                    cx,
22231                );
22232            }
22233        }
22234    }
22235
22236    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22237        cx.emit(EditorEvent::FocusedIn)
22238    }
22239
22240    fn handle_focus_out(
22241        &mut self,
22242        event: FocusOutEvent,
22243        _window: &mut Window,
22244        cx: &mut Context<Self>,
22245    ) {
22246        if event.blurred != self.focus_handle {
22247            self.last_focused_descendant = Some(event.blurred);
22248        }
22249        self.selection_drag_state = SelectionDragState::None;
22250        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22251    }
22252
22253    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22254        self.blink_manager.update(cx, BlinkManager::disable);
22255        self.buffer
22256            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22257
22258        if let Some(blame) = self.blame.as_ref() {
22259            blame.update(cx, GitBlame::blur)
22260        }
22261        if !self.hover_state.focused(window, cx) {
22262            hide_hover(self, cx);
22263        }
22264        if !self
22265            .context_menu
22266            .borrow()
22267            .as_ref()
22268            .is_some_and(|context_menu| context_menu.focused(window, cx))
22269        {
22270            self.hide_context_menu(window, cx);
22271        }
22272        self.take_active_edit_prediction(cx);
22273        cx.emit(EditorEvent::Blurred);
22274        cx.notify();
22275    }
22276
22277    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22278        let mut pending: String = window
22279            .pending_input_keystrokes()
22280            .into_iter()
22281            .flatten()
22282            .filter_map(|keystroke| keystroke.key_char.clone())
22283            .collect();
22284
22285        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22286            pending = "".to_string();
22287        }
22288
22289        let existing_pending = self
22290            .text_highlights::<PendingInput>(cx)
22291            .map(|(_, ranges)| ranges.to_vec());
22292        if existing_pending.is_none() && pending.is_empty() {
22293            return;
22294        }
22295        let transaction =
22296            self.transact(window, cx, |this, window, cx| {
22297                let selections = this
22298                    .selections
22299                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22300                let edits = selections
22301                    .iter()
22302                    .map(|selection| (selection.end..selection.end, pending.clone()));
22303                this.edit(edits, cx);
22304                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22305                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22306                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22307                    }));
22308                });
22309                if let Some(existing_ranges) = existing_pending {
22310                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22311                    this.edit(edits, cx);
22312                }
22313            });
22314
22315        let snapshot = self.snapshot(window, cx);
22316        let ranges = self
22317            .selections
22318            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22319            .into_iter()
22320            .map(|selection| {
22321                snapshot.buffer_snapshot().anchor_after(selection.end)
22322                    ..snapshot
22323                        .buffer_snapshot()
22324                        .anchor_before(selection.end + pending.len())
22325            })
22326            .collect();
22327
22328        if pending.is_empty() {
22329            self.clear_highlights::<PendingInput>(cx);
22330        } else {
22331            self.highlight_text::<PendingInput>(
22332                ranges,
22333                HighlightStyle {
22334                    underline: Some(UnderlineStyle {
22335                        thickness: px(1.),
22336                        color: None,
22337                        wavy: false,
22338                    }),
22339                    ..Default::default()
22340                },
22341                cx,
22342            );
22343        }
22344
22345        self.ime_transaction = self.ime_transaction.or(transaction);
22346        if let Some(transaction) = self.ime_transaction {
22347            self.buffer.update(cx, |buffer, cx| {
22348                buffer.group_until_transaction(transaction, cx);
22349            });
22350        }
22351
22352        if self.text_highlights::<PendingInput>(cx).is_none() {
22353            self.ime_transaction.take();
22354        }
22355    }
22356
22357    pub fn register_action_renderer(
22358        &mut self,
22359        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22360    ) -> Subscription {
22361        let id = self.next_editor_action_id.post_inc();
22362        self.editor_actions
22363            .borrow_mut()
22364            .insert(id, Box::new(listener));
22365
22366        let editor_actions = self.editor_actions.clone();
22367        Subscription::new(move || {
22368            editor_actions.borrow_mut().remove(&id);
22369        })
22370    }
22371
22372    pub fn register_action<A: Action>(
22373        &mut self,
22374        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22375    ) -> Subscription {
22376        let id = self.next_editor_action_id.post_inc();
22377        let listener = Arc::new(listener);
22378        self.editor_actions.borrow_mut().insert(
22379            id,
22380            Box::new(move |_, window, _| {
22381                let listener = listener.clone();
22382                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22383                    let action = action.downcast_ref().unwrap();
22384                    if phase == DispatchPhase::Bubble {
22385                        listener(action, window, cx)
22386                    }
22387                })
22388            }),
22389        );
22390
22391        let editor_actions = self.editor_actions.clone();
22392        Subscription::new(move || {
22393            editor_actions.borrow_mut().remove(&id);
22394        })
22395    }
22396
22397    pub fn file_header_size(&self) -> u32 {
22398        FILE_HEADER_HEIGHT
22399    }
22400
22401    pub fn restore(
22402        &mut self,
22403        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22404        window: &mut Window,
22405        cx: &mut Context<Self>,
22406    ) {
22407        let workspace = self.workspace();
22408        let project = self.project();
22409        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22410            let mut tasks = Vec::new();
22411            for (buffer_id, changes) in revert_changes {
22412                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22413                    buffer.update(cx, |buffer, cx| {
22414                        buffer.edit(
22415                            changes
22416                                .into_iter()
22417                                .map(|(range, text)| (range, text.to_string())),
22418                            None,
22419                            cx,
22420                        );
22421                    });
22422
22423                    if let Some(project) =
22424                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22425                    {
22426                        project.update(cx, |project, cx| {
22427                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22428                        })
22429                    }
22430                }
22431            }
22432            tasks
22433        });
22434        cx.spawn_in(window, async move |_, cx| {
22435            for (buffer, task) in save_tasks {
22436                let result = task.await;
22437                if result.is_err() {
22438                    let Some(path) = buffer
22439                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22440                        .ok()
22441                    else {
22442                        continue;
22443                    };
22444                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22445                        let Some(task) = cx
22446                            .update_window_entity(workspace, |workspace, window, cx| {
22447                                workspace
22448                                    .open_path_preview(path, None, false, false, false, window, cx)
22449                            })
22450                            .ok()
22451                        else {
22452                            continue;
22453                        };
22454                        task.await.log_err();
22455                    }
22456                }
22457            }
22458        })
22459        .detach();
22460        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22461            selections.refresh()
22462        });
22463    }
22464
22465    pub fn to_pixel_point(
22466        &self,
22467        source: multi_buffer::Anchor,
22468        editor_snapshot: &EditorSnapshot,
22469        window: &mut Window,
22470    ) -> Option<gpui::Point<Pixels>> {
22471        let source_point = source.to_display_point(editor_snapshot);
22472        self.display_to_pixel_point(source_point, editor_snapshot, window)
22473    }
22474
22475    pub fn display_to_pixel_point(
22476        &self,
22477        source: DisplayPoint,
22478        editor_snapshot: &EditorSnapshot,
22479        window: &mut Window,
22480    ) -> Option<gpui::Point<Pixels>> {
22481        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22482        let text_layout_details = self.text_layout_details(window);
22483        let scroll_top = text_layout_details
22484            .scroll_anchor
22485            .scroll_position(editor_snapshot)
22486            .y;
22487
22488        if source.row().as_f64() < scroll_top.floor() {
22489            return None;
22490        }
22491        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22492        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22493        Some(gpui::Point::new(source_x, source_y))
22494    }
22495
22496    pub fn has_visible_completions_menu(&self) -> bool {
22497        !self.edit_prediction_preview_is_active()
22498            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22499                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22500            })
22501    }
22502
22503    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22504        if self.mode.is_minimap() {
22505            return;
22506        }
22507        self.addons
22508            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22509    }
22510
22511    pub fn unregister_addon<T: Addon>(&mut self) {
22512        self.addons.remove(&std::any::TypeId::of::<T>());
22513    }
22514
22515    pub fn addon<T: Addon>(&self) -> Option<&T> {
22516        let type_id = std::any::TypeId::of::<T>();
22517        self.addons
22518            .get(&type_id)
22519            .and_then(|item| item.to_any().downcast_ref::<T>())
22520    }
22521
22522    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22523        let type_id = std::any::TypeId::of::<T>();
22524        self.addons
22525            .get_mut(&type_id)
22526            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22527    }
22528
22529    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22530        let text_layout_details = self.text_layout_details(window);
22531        let style = &text_layout_details.editor_style;
22532        let font_id = window.text_system().resolve_font(&style.text.font());
22533        let font_size = style.text.font_size.to_pixels(window.rem_size());
22534        let line_height = style.text.line_height_in_pixels(window.rem_size());
22535        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22536        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22537
22538        CharacterDimensions {
22539            em_width,
22540            em_advance,
22541            line_height,
22542        }
22543    }
22544
22545    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22546        self.load_diff_task.clone()
22547    }
22548
22549    fn read_metadata_from_db(
22550        &mut self,
22551        item_id: u64,
22552        workspace_id: WorkspaceId,
22553        window: &mut Window,
22554        cx: &mut Context<Editor>,
22555    ) {
22556        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22557            && !self.mode.is_minimap()
22558            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22559        {
22560            let buffer_snapshot = OnceCell::new();
22561
22562            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22563                && !folds.is_empty()
22564            {
22565                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22566                self.fold_ranges(
22567                    folds
22568                        .into_iter()
22569                        .map(|(start, end)| {
22570                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22571                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22572                        })
22573                        .collect(),
22574                    false,
22575                    window,
22576                    cx,
22577                );
22578            }
22579
22580            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22581                && !selections.is_empty()
22582            {
22583                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22584                // skip adding the initial selection to selection history
22585                self.selection_history.mode = SelectionHistoryMode::Skipping;
22586                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22587                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22588                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22589                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22590                    }));
22591                });
22592                self.selection_history.mode = SelectionHistoryMode::Normal;
22593            };
22594        }
22595
22596        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22597    }
22598
22599    fn update_lsp_data(
22600        &mut self,
22601        for_buffer: Option<BufferId>,
22602        window: &mut Window,
22603        cx: &mut Context<'_, Self>,
22604    ) {
22605        self.pull_diagnostics(for_buffer, window, cx);
22606        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22607    }
22608
22609    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22610        if self.ignore_lsp_data() {
22611            return;
22612        }
22613        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22614            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22615        }
22616    }
22617
22618    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22619        if self.ignore_lsp_data() {
22620            return;
22621        }
22622
22623        if !self.registered_buffers.contains_key(&buffer_id)
22624            && let Some(project) = self.project.as_ref()
22625        {
22626            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22627                project.update(cx, |project, cx| {
22628                    self.registered_buffers.insert(
22629                        buffer_id,
22630                        project.register_buffer_with_language_servers(&buffer, cx),
22631                    );
22632                });
22633            } else {
22634                self.registered_buffers.remove(&buffer_id);
22635            }
22636        }
22637    }
22638
22639    fn ignore_lsp_data(&self) -> bool {
22640        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22641        // skip any LSP updates for it.
22642        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22643    }
22644}
22645
22646fn edit_for_markdown_paste<'a>(
22647    buffer: &MultiBufferSnapshot,
22648    range: Range<MultiBufferOffset>,
22649    to_insert: &'a str,
22650    url: Option<url::Url>,
22651) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22652    if url.is_none() {
22653        return (range, Cow::Borrowed(to_insert));
22654    };
22655
22656    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22657
22658    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22659        Cow::Borrowed(to_insert)
22660    } else {
22661        Cow::Owned(format!("[{old_text}]({to_insert})"))
22662    };
22663    (range, new_text)
22664}
22665
22666fn process_completion_for_edit(
22667    completion: &Completion,
22668    intent: CompletionIntent,
22669    buffer: &Entity<Buffer>,
22670    cursor_position: &text::Anchor,
22671    cx: &mut Context<Editor>,
22672) -> CompletionEdit {
22673    let buffer = buffer.read(cx);
22674    let buffer_snapshot = buffer.snapshot();
22675    let (snippet, new_text) = if completion.is_snippet() {
22676        let mut snippet_source = completion.new_text.clone();
22677        // Workaround for typescript language server issues so that methods don't expand within
22678        // strings and functions with type expressions. The previous point is used because the query
22679        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22680        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22681        let previous_point = if previous_point.column > 0 {
22682            cursor_position.to_previous_offset(&buffer_snapshot)
22683        } else {
22684            cursor_position.to_offset(&buffer_snapshot)
22685        };
22686        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22687            && scope.prefers_label_for_snippet_in_completion()
22688            && let Some(label) = completion.label()
22689            && matches!(
22690                completion.kind(),
22691                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22692            )
22693        {
22694            snippet_source = label;
22695        }
22696        match Snippet::parse(&snippet_source).log_err() {
22697            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22698            None => (None, completion.new_text.clone()),
22699        }
22700    } else {
22701        (None, completion.new_text.clone())
22702    };
22703
22704    let mut range_to_replace = {
22705        let replace_range = &completion.replace_range;
22706        if let CompletionSource::Lsp {
22707            insert_range: Some(insert_range),
22708            ..
22709        } = &completion.source
22710        {
22711            debug_assert_eq!(
22712                insert_range.start, replace_range.start,
22713                "insert_range and replace_range should start at the same position"
22714            );
22715            debug_assert!(
22716                insert_range
22717                    .start
22718                    .cmp(cursor_position, &buffer_snapshot)
22719                    .is_le(),
22720                "insert_range should start before or at cursor position"
22721            );
22722            debug_assert!(
22723                replace_range
22724                    .start
22725                    .cmp(cursor_position, &buffer_snapshot)
22726                    .is_le(),
22727                "replace_range should start before or at cursor position"
22728            );
22729
22730            let should_replace = match intent {
22731                CompletionIntent::CompleteWithInsert => false,
22732                CompletionIntent::CompleteWithReplace => true,
22733                CompletionIntent::Complete | CompletionIntent::Compose => {
22734                    let insert_mode =
22735                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22736                            .completions
22737                            .lsp_insert_mode;
22738                    match insert_mode {
22739                        LspInsertMode::Insert => false,
22740                        LspInsertMode::Replace => true,
22741                        LspInsertMode::ReplaceSubsequence => {
22742                            let mut text_to_replace = buffer.chars_for_range(
22743                                buffer.anchor_before(replace_range.start)
22744                                    ..buffer.anchor_after(replace_range.end),
22745                            );
22746                            let mut current_needle = text_to_replace.next();
22747                            for haystack_ch in completion.label.text.chars() {
22748                                if let Some(needle_ch) = current_needle
22749                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22750                                {
22751                                    current_needle = text_to_replace.next();
22752                                }
22753                            }
22754                            current_needle.is_none()
22755                        }
22756                        LspInsertMode::ReplaceSuffix => {
22757                            if replace_range
22758                                .end
22759                                .cmp(cursor_position, &buffer_snapshot)
22760                                .is_gt()
22761                            {
22762                                let range_after_cursor = *cursor_position..replace_range.end;
22763                                let text_after_cursor = buffer
22764                                    .text_for_range(
22765                                        buffer.anchor_before(range_after_cursor.start)
22766                                            ..buffer.anchor_after(range_after_cursor.end),
22767                                    )
22768                                    .collect::<String>()
22769                                    .to_ascii_lowercase();
22770                                completion
22771                                    .label
22772                                    .text
22773                                    .to_ascii_lowercase()
22774                                    .ends_with(&text_after_cursor)
22775                            } else {
22776                                true
22777                            }
22778                        }
22779                    }
22780                }
22781            };
22782
22783            if should_replace {
22784                replace_range.clone()
22785            } else {
22786                insert_range.clone()
22787            }
22788        } else {
22789            replace_range.clone()
22790        }
22791    };
22792
22793    if range_to_replace
22794        .end
22795        .cmp(cursor_position, &buffer_snapshot)
22796        .is_lt()
22797    {
22798        range_to_replace.end = *cursor_position;
22799    }
22800
22801    let replace_range = range_to_replace.to_offset(buffer);
22802    CompletionEdit {
22803        new_text,
22804        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22805        snippet,
22806    }
22807}
22808
22809struct CompletionEdit {
22810    new_text: String,
22811    replace_range: Range<BufferOffset>,
22812    snippet: Option<Snippet>,
22813}
22814
22815fn insert_extra_newline_brackets(
22816    buffer: &MultiBufferSnapshot,
22817    range: Range<MultiBufferOffset>,
22818    language: &language::LanguageScope,
22819) -> bool {
22820    let leading_whitespace_len = buffer
22821        .reversed_chars_at(range.start)
22822        .take_while(|c| c.is_whitespace() && *c != '\n')
22823        .map(|c| c.len_utf8())
22824        .sum::<usize>();
22825    let trailing_whitespace_len = buffer
22826        .chars_at(range.end)
22827        .take_while(|c| c.is_whitespace() && *c != '\n')
22828        .map(|c| c.len_utf8())
22829        .sum::<usize>();
22830    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22831
22832    language.brackets().any(|(pair, enabled)| {
22833        let pair_start = pair.start.trim_end();
22834        let pair_end = pair.end.trim_start();
22835
22836        enabled
22837            && pair.newline
22838            && buffer.contains_str_at(range.end, pair_end)
22839            && buffer.contains_str_at(
22840                range.start.saturating_sub_usize(pair_start.len()),
22841                pair_start,
22842            )
22843    })
22844}
22845
22846fn insert_extra_newline_tree_sitter(
22847    buffer: &MultiBufferSnapshot,
22848    range: Range<MultiBufferOffset>,
22849) -> bool {
22850    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22851        [(buffer, range, _)] => (*buffer, range.clone()),
22852        _ => return false,
22853    };
22854    let pair = {
22855        let mut result: Option<BracketMatch<usize>> = None;
22856
22857        for pair in buffer
22858            .all_bracket_ranges(range.start.0..range.end.0)
22859            .filter(move |pair| {
22860                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22861            })
22862        {
22863            let len = pair.close_range.end - pair.open_range.start;
22864
22865            if let Some(existing) = &result {
22866                let existing_len = existing.close_range.end - existing.open_range.start;
22867                if len > existing_len {
22868                    continue;
22869                }
22870            }
22871
22872            result = Some(pair);
22873        }
22874
22875        result
22876    };
22877    let Some(pair) = pair else {
22878        return false;
22879    };
22880    pair.newline_only
22881        && buffer
22882            .chars_for_range(pair.open_range.end..range.start.0)
22883            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22884            .all(|c| c.is_whitespace() && c != '\n')
22885}
22886
22887fn update_uncommitted_diff_for_buffer(
22888    editor: Entity<Editor>,
22889    project: &Entity<Project>,
22890    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22891    buffer: Entity<MultiBuffer>,
22892    cx: &mut App,
22893) -> Task<()> {
22894    let mut tasks = Vec::new();
22895    project.update(cx, |project, cx| {
22896        for buffer in buffers {
22897            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22898                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22899            }
22900        }
22901    });
22902    cx.spawn(async move |cx| {
22903        let diffs = future::join_all(tasks).await;
22904        if editor
22905            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22906            .unwrap_or(false)
22907        {
22908            return;
22909        }
22910
22911        buffer
22912            .update(cx, |buffer, cx| {
22913                for diff in diffs.into_iter().flatten() {
22914                    buffer.add_diff(diff, cx);
22915                }
22916            })
22917            .ok();
22918    })
22919}
22920
22921fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22922    let tab_size = tab_size.get() as usize;
22923    let mut width = offset;
22924
22925    for ch in text.chars() {
22926        width += if ch == '\t' {
22927            tab_size - (width % tab_size)
22928        } else {
22929            1
22930        };
22931    }
22932
22933    width - offset
22934}
22935
22936#[cfg(test)]
22937mod tests {
22938    use super::*;
22939
22940    #[test]
22941    fn test_string_size_with_expanded_tabs() {
22942        let nz = |val| NonZeroU32::new(val).unwrap();
22943        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22944        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22945        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22946        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22947        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22948        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22949        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22950        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22951    }
22952}
22953
22954/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22955struct WordBreakingTokenizer<'a> {
22956    input: &'a str,
22957}
22958
22959impl<'a> WordBreakingTokenizer<'a> {
22960    fn new(input: &'a str) -> Self {
22961        Self { input }
22962    }
22963}
22964
22965fn is_char_ideographic(ch: char) -> bool {
22966    use unicode_script::Script::*;
22967    use unicode_script::UnicodeScript;
22968    matches!(ch.script(), Han | Tangut | Yi)
22969}
22970
22971fn is_grapheme_ideographic(text: &str) -> bool {
22972    text.chars().any(is_char_ideographic)
22973}
22974
22975fn is_grapheme_whitespace(text: &str) -> bool {
22976    text.chars().any(|x| x.is_whitespace())
22977}
22978
22979fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22980    text.chars()
22981        .next()
22982        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22983}
22984
22985#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22986enum WordBreakToken<'a> {
22987    Word { token: &'a str, grapheme_len: usize },
22988    InlineWhitespace { token: &'a str, grapheme_len: usize },
22989    Newline,
22990}
22991
22992impl<'a> Iterator for WordBreakingTokenizer<'a> {
22993    /// Yields a span, the count of graphemes in the token, and whether it was
22994    /// whitespace. Note that it also breaks at word boundaries.
22995    type Item = WordBreakToken<'a>;
22996
22997    fn next(&mut self) -> Option<Self::Item> {
22998        use unicode_segmentation::UnicodeSegmentation;
22999        if self.input.is_empty() {
23000            return None;
23001        }
23002
23003        let mut iter = self.input.graphemes(true).peekable();
23004        let mut offset = 0;
23005        let mut grapheme_len = 0;
23006        if let Some(first_grapheme) = iter.next() {
23007            let is_newline = first_grapheme == "\n";
23008            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23009            offset += first_grapheme.len();
23010            grapheme_len += 1;
23011            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23012                if let Some(grapheme) = iter.peek().copied()
23013                    && should_stay_with_preceding_ideograph(grapheme)
23014                {
23015                    offset += grapheme.len();
23016                    grapheme_len += 1;
23017                }
23018            } else {
23019                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23020                let mut next_word_bound = words.peek().copied();
23021                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23022                    next_word_bound = words.next();
23023                }
23024                while let Some(grapheme) = iter.peek().copied() {
23025                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23026                        break;
23027                    };
23028                    if is_grapheme_whitespace(grapheme) != is_whitespace
23029                        || (grapheme == "\n") != is_newline
23030                    {
23031                        break;
23032                    };
23033                    offset += grapheme.len();
23034                    grapheme_len += 1;
23035                    iter.next();
23036                }
23037            }
23038            let token = &self.input[..offset];
23039            self.input = &self.input[offset..];
23040            if token == "\n" {
23041                Some(WordBreakToken::Newline)
23042            } else if is_whitespace {
23043                Some(WordBreakToken::InlineWhitespace {
23044                    token,
23045                    grapheme_len,
23046                })
23047            } else {
23048                Some(WordBreakToken::Word {
23049                    token,
23050                    grapheme_len,
23051                })
23052            }
23053        } else {
23054            None
23055        }
23056    }
23057}
23058
23059#[test]
23060fn test_word_breaking_tokenizer() {
23061    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23062        ("", &[]),
23063        ("  ", &[whitespace("  ", 2)]),
23064        ("Ʒ", &[word("Ʒ", 1)]),
23065        ("Ǽ", &[word("Ǽ", 1)]),
23066        ("", &[word("", 1)]),
23067        ("⋑⋑", &[word("⋑⋑", 2)]),
23068        (
23069            "原理,进而",
23070            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23071        ),
23072        (
23073            "hello world",
23074            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23075        ),
23076        (
23077            "hello, world",
23078            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23079        ),
23080        (
23081            "  hello world",
23082            &[
23083                whitespace("  ", 2),
23084                word("hello", 5),
23085                whitespace(" ", 1),
23086                word("world", 5),
23087            ],
23088        ),
23089        (
23090            "这是什么 \n 钢笔",
23091            &[
23092                word("", 1),
23093                word("", 1),
23094                word("", 1),
23095                word("", 1),
23096                whitespace(" ", 1),
23097                newline(),
23098                whitespace(" ", 1),
23099                word("", 1),
23100                word("", 1),
23101            ],
23102        ),
23103        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23104    ];
23105
23106    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23107        WordBreakToken::Word {
23108            token,
23109            grapheme_len,
23110        }
23111    }
23112
23113    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23114        WordBreakToken::InlineWhitespace {
23115            token,
23116            grapheme_len,
23117        }
23118    }
23119
23120    fn newline() -> WordBreakToken<'static> {
23121        WordBreakToken::Newline
23122    }
23123
23124    for (input, result) in tests {
23125        assert_eq!(
23126            WordBreakingTokenizer::new(input)
23127                .collect::<Vec<_>>()
23128                .as_slice(),
23129            *result,
23130        );
23131    }
23132}
23133
23134fn wrap_with_prefix(
23135    first_line_prefix: String,
23136    subsequent_lines_prefix: String,
23137    unwrapped_text: String,
23138    wrap_column: usize,
23139    tab_size: NonZeroU32,
23140    preserve_existing_whitespace: bool,
23141) -> String {
23142    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23143    let subsequent_lines_prefix_len =
23144        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23145    let mut wrapped_text = String::new();
23146    let mut current_line = first_line_prefix;
23147    let mut is_first_line = true;
23148
23149    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23150    let mut current_line_len = first_line_prefix_len;
23151    let mut in_whitespace = false;
23152    for token in tokenizer {
23153        let have_preceding_whitespace = in_whitespace;
23154        match token {
23155            WordBreakToken::Word {
23156                token,
23157                grapheme_len,
23158            } => {
23159                in_whitespace = false;
23160                let current_prefix_len = if is_first_line {
23161                    first_line_prefix_len
23162                } else {
23163                    subsequent_lines_prefix_len
23164                };
23165                if current_line_len + grapheme_len > wrap_column
23166                    && current_line_len != current_prefix_len
23167                {
23168                    wrapped_text.push_str(current_line.trim_end());
23169                    wrapped_text.push('\n');
23170                    is_first_line = false;
23171                    current_line = subsequent_lines_prefix.clone();
23172                    current_line_len = subsequent_lines_prefix_len;
23173                }
23174                current_line.push_str(token);
23175                current_line_len += grapheme_len;
23176            }
23177            WordBreakToken::InlineWhitespace {
23178                mut token,
23179                mut grapheme_len,
23180            } => {
23181                in_whitespace = true;
23182                if have_preceding_whitespace && !preserve_existing_whitespace {
23183                    continue;
23184                }
23185                if !preserve_existing_whitespace {
23186                    // Keep a single whitespace grapheme as-is
23187                    if let Some(first) =
23188                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23189                    {
23190                        token = first;
23191                    } else {
23192                        token = " ";
23193                    }
23194                    grapheme_len = 1;
23195                }
23196                let current_prefix_len = if is_first_line {
23197                    first_line_prefix_len
23198                } else {
23199                    subsequent_lines_prefix_len
23200                };
23201                if current_line_len + grapheme_len > wrap_column {
23202                    wrapped_text.push_str(current_line.trim_end());
23203                    wrapped_text.push('\n');
23204                    is_first_line = false;
23205                    current_line = subsequent_lines_prefix.clone();
23206                    current_line_len = subsequent_lines_prefix_len;
23207                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23208                    current_line.push_str(token);
23209                    current_line_len += grapheme_len;
23210                }
23211            }
23212            WordBreakToken::Newline => {
23213                in_whitespace = true;
23214                let current_prefix_len = if is_first_line {
23215                    first_line_prefix_len
23216                } else {
23217                    subsequent_lines_prefix_len
23218                };
23219                if preserve_existing_whitespace {
23220                    wrapped_text.push_str(current_line.trim_end());
23221                    wrapped_text.push('\n');
23222                    is_first_line = false;
23223                    current_line = subsequent_lines_prefix.clone();
23224                    current_line_len = subsequent_lines_prefix_len;
23225                } else if have_preceding_whitespace {
23226                    continue;
23227                } else if current_line_len + 1 > wrap_column
23228                    && current_line_len != current_prefix_len
23229                {
23230                    wrapped_text.push_str(current_line.trim_end());
23231                    wrapped_text.push('\n');
23232                    is_first_line = false;
23233                    current_line = subsequent_lines_prefix.clone();
23234                    current_line_len = subsequent_lines_prefix_len;
23235                } else if current_line_len != current_prefix_len {
23236                    current_line.push(' ');
23237                    current_line_len += 1;
23238                }
23239            }
23240        }
23241    }
23242
23243    if !current_line.is_empty() {
23244        wrapped_text.push_str(&current_line);
23245    }
23246    wrapped_text
23247}
23248
23249#[test]
23250fn test_wrap_with_prefix() {
23251    assert_eq!(
23252        wrap_with_prefix(
23253            "# ".to_string(),
23254            "# ".to_string(),
23255            "abcdefg".to_string(),
23256            4,
23257            NonZeroU32::new(4).unwrap(),
23258            false,
23259        ),
23260        "# abcdefg"
23261    );
23262    assert_eq!(
23263        wrap_with_prefix(
23264            "".to_string(),
23265            "".to_string(),
23266            "\thello world".to_string(),
23267            8,
23268            NonZeroU32::new(4).unwrap(),
23269            false,
23270        ),
23271        "hello\nworld"
23272    );
23273    assert_eq!(
23274        wrap_with_prefix(
23275            "// ".to_string(),
23276            "// ".to_string(),
23277            "xx \nyy zz aa bb cc".to_string(),
23278            12,
23279            NonZeroU32::new(4).unwrap(),
23280            false,
23281        ),
23282        "// xx yy zz\n// aa bb cc"
23283    );
23284    assert_eq!(
23285        wrap_with_prefix(
23286            String::new(),
23287            String::new(),
23288            "这是什么 \n 钢笔".to_string(),
23289            3,
23290            NonZeroU32::new(4).unwrap(),
23291            false,
23292        ),
23293        "这是什\n么 钢\n"
23294    );
23295    assert_eq!(
23296        wrap_with_prefix(
23297            String::new(),
23298            String::new(),
23299            format!("foo{}bar", '\u{2009}'), // thin space
23300            80,
23301            NonZeroU32::new(4).unwrap(),
23302            false,
23303        ),
23304        format!("foo{}bar", '\u{2009}')
23305    );
23306}
23307
23308pub trait CollaborationHub {
23309    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23310    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23311    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23312}
23313
23314impl CollaborationHub for Entity<Project> {
23315    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23316        self.read(cx).collaborators()
23317    }
23318
23319    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23320        self.read(cx).user_store().read(cx).participant_indices()
23321    }
23322
23323    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23324        let this = self.read(cx);
23325        let user_ids = this.collaborators().values().map(|c| c.user_id);
23326        this.user_store().read(cx).participant_names(user_ids, cx)
23327    }
23328}
23329
23330pub trait SemanticsProvider {
23331    fn hover(
23332        &self,
23333        buffer: &Entity<Buffer>,
23334        position: text::Anchor,
23335        cx: &mut App,
23336    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23337
23338    fn inline_values(
23339        &self,
23340        buffer_handle: Entity<Buffer>,
23341        range: Range<text::Anchor>,
23342        cx: &mut App,
23343    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23344
23345    fn applicable_inlay_chunks(
23346        &self,
23347        buffer: &Entity<Buffer>,
23348        ranges: &[Range<text::Anchor>],
23349        cx: &mut App,
23350    ) -> Vec<Range<BufferRow>>;
23351
23352    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23353
23354    fn inlay_hints(
23355        &self,
23356        invalidate: InvalidationStrategy,
23357        buffer: Entity<Buffer>,
23358        ranges: Vec<Range<text::Anchor>>,
23359        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23360        cx: &mut App,
23361    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23362
23363    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23364
23365    fn document_highlights(
23366        &self,
23367        buffer: &Entity<Buffer>,
23368        position: text::Anchor,
23369        cx: &mut App,
23370    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23371
23372    fn definitions(
23373        &self,
23374        buffer: &Entity<Buffer>,
23375        position: text::Anchor,
23376        kind: GotoDefinitionKind,
23377        cx: &mut App,
23378    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23379
23380    fn range_for_rename(
23381        &self,
23382        buffer: &Entity<Buffer>,
23383        position: text::Anchor,
23384        cx: &mut App,
23385    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23386
23387    fn perform_rename(
23388        &self,
23389        buffer: &Entity<Buffer>,
23390        position: text::Anchor,
23391        new_name: String,
23392        cx: &mut App,
23393    ) -> Option<Task<Result<ProjectTransaction>>>;
23394}
23395
23396pub trait CompletionProvider {
23397    fn completions(
23398        &self,
23399        excerpt_id: ExcerptId,
23400        buffer: &Entity<Buffer>,
23401        buffer_position: text::Anchor,
23402        trigger: CompletionContext,
23403        window: &mut Window,
23404        cx: &mut Context<Editor>,
23405    ) -> Task<Result<Vec<CompletionResponse>>>;
23406
23407    fn resolve_completions(
23408        &self,
23409        _buffer: Entity<Buffer>,
23410        _completion_indices: Vec<usize>,
23411        _completions: Rc<RefCell<Box<[Completion]>>>,
23412        _cx: &mut Context<Editor>,
23413    ) -> Task<Result<bool>> {
23414        Task::ready(Ok(false))
23415    }
23416
23417    fn apply_additional_edits_for_completion(
23418        &self,
23419        _buffer: Entity<Buffer>,
23420        _completions: Rc<RefCell<Box<[Completion]>>>,
23421        _completion_index: usize,
23422        _push_to_history: bool,
23423        _cx: &mut Context<Editor>,
23424    ) -> Task<Result<Option<language::Transaction>>> {
23425        Task::ready(Ok(None))
23426    }
23427
23428    fn is_completion_trigger(
23429        &self,
23430        buffer: &Entity<Buffer>,
23431        position: language::Anchor,
23432        text: &str,
23433        trigger_in_words: bool,
23434        menu_is_open: bool,
23435        cx: &mut Context<Editor>,
23436    ) -> bool;
23437
23438    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23439
23440    fn sort_completions(&self) -> bool {
23441        true
23442    }
23443
23444    fn filter_completions(&self) -> bool {
23445        true
23446    }
23447
23448    fn show_snippets(&self) -> bool {
23449        false
23450    }
23451}
23452
23453pub trait CodeActionProvider {
23454    fn id(&self) -> Arc<str>;
23455
23456    fn code_actions(
23457        &self,
23458        buffer: &Entity<Buffer>,
23459        range: Range<text::Anchor>,
23460        window: &mut Window,
23461        cx: &mut App,
23462    ) -> Task<Result<Vec<CodeAction>>>;
23463
23464    fn apply_code_action(
23465        &self,
23466        buffer_handle: Entity<Buffer>,
23467        action: CodeAction,
23468        excerpt_id: ExcerptId,
23469        push_to_history: bool,
23470        window: &mut Window,
23471        cx: &mut App,
23472    ) -> Task<Result<ProjectTransaction>>;
23473}
23474
23475impl CodeActionProvider for Entity<Project> {
23476    fn id(&self) -> Arc<str> {
23477        "project".into()
23478    }
23479
23480    fn code_actions(
23481        &self,
23482        buffer: &Entity<Buffer>,
23483        range: Range<text::Anchor>,
23484        _window: &mut Window,
23485        cx: &mut App,
23486    ) -> Task<Result<Vec<CodeAction>>> {
23487        self.update(cx, |project, cx| {
23488            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23489            let code_actions = project.code_actions(buffer, range, None, cx);
23490            cx.background_spawn(async move {
23491                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23492                Ok(code_lens_actions
23493                    .context("code lens fetch")?
23494                    .into_iter()
23495                    .flatten()
23496                    .chain(
23497                        code_actions
23498                            .context("code action fetch")?
23499                            .into_iter()
23500                            .flatten(),
23501                    )
23502                    .collect())
23503            })
23504        })
23505    }
23506
23507    fn apply_code_action(
23508        &self,
23509        buffer_handle: Entity<Buffer>,
23510        action: CodeAction,
23511        _excerpt_id: ExcerptId,
23512        push_to_history: bool,
23513        _window: &mut Window,
23514        cx: &mut App,
23515    ) -> Task<Result<ProjectTransaction>> {
23516        self.update(cx, |project, cx| {
23517            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23518        })
23519    }
23520}
23521
23522fn snippet_completions(
23523    project: &Project,
23524    buffer: &Entity<Buffer>,
23525    buffer_anchor: text::Anchor,
23526    classifier: CharClassifier,
23527    cx: &mut App,
23528) -> Task<Result<CompletionResponse>> {
23529    let languages = buffer.read(cx).languages_at(buffer_anchor);
23530    let snippet_store = project.snippets().read(cx);
23531
23532    let scopes: Vec<_> = languages
23533        .iter()
23534        .filter_map(|language| {
23535            let language_name = language.lsp_id();
23536            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23537
23538            if snippets.is_empty() {
23539                None
23540            } else {
23541                Some((language.default_scope(), snippets))
23542            }
23543        })
23544        .collect();
23545
23546    if scopes.is_empty() {
23547        return Task::ready(Ok(CompletionResponse {
23548            completions: vec![],
23549            display_options: CompletionDisplayOptions::default(),
23550            is_incomplete: false,
23551        }));
23552    }
23553
23554    let snapshot = buffer.read(cx).text_snapshot();
23555    let executor = cx.background_executor().clone();
23556
23557    cx.background_spawn(async move {
23558        let is_word_char = |c| classifier.is_word(c);
23559
23560        let mut is_incomplete = false;
23561        let mut completions: Vec<Completion> = Vec::new();
23562
23563        const MAX_PREFIX_LEN: usize = 128;
23564        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23565        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23566        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23567
23568        let max_buffer_window: String = snapshot
23569            .text_for_range(window_start..buffer_offset)
23570            .collect();
23571
23572        if max_buffer_window.is_empty() {
23573            return Ok(CompletionResponse {
23574                completions: vec![],
23575                display_options: CompletionDisplayOptions::default(),
23576                is_incomplete: true,
23577            });
23578        }
23579
23580        for (_scope, snippets) in scopes.into_iter() {
23581            // Sort snippets by word count to match longer snippet prefixes first.
23582            let mut sorted_snippet_candidates = snippets
23583                .iter()
23584                .enumerate()
23585                .flat_map(|(snippet_ix, snippet)| {
23586                    snippet
23587                        .prefix
23588                        .iter()
23589                        .enumerate()
23590                        .map(move |(prefix_ix, prefix)| {
23591                            let word_count =
23592                                snippet_candidate_suffixes(prefix, is_word_char).count();
23593                            ((snippet_ix, prefix_ix), prefix, word_count)
23594                        })
23595                })
23596                .collect_vec();
23597            sorted_snippet_candidates
23598                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23599
23600            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23601
23602            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23603                .take(
23604                    sorted_snippet_candidates
23605                        .first()
23606                        .map(|(_, _, word_count)| *word_count)
23607                        .unwrap_or_default(),
23608                )
23609                .collect_vec();
23610
23611            const MAX_RESULTS: usize = 100;
23612            // Each match also remembers how many characters from the buffer it consumed
23613            let mut matches: Vec<(StringMatch, usize)> = vec![];
23614
23615            let mut snippet_list_cutoff_index = 0;
23616            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23617                let word_count = buffer_index + 1;
23618                // Increase `snippet_list_cutoff_index` until we have all of the
23619                // snippets with sufficiently many words.
23620                while sorted_snippet_candidates
23621                    .get(snippet_list_cutoff_index)
23622                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23623                        *snippet_word_count >= word_count
23624                    })
23625                {
23626                    snippet_list_cutoff_index += 1;
23627                }
23628
23629                // Take only the candidates with at least `word_count` many words
23630                let snippet_candidates_at_word_len =
23631                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23632
23633                let candidates = snippet_candidates_at_word_len
23634                    .iter()
23635                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23636                    .enumerate() // index in `sorted_snippet_candidates`
23637                    // First char must match
23638                    .filter(|(_ix, prefix)| {
23639                        itertools::equal(
23640                            prefix
23641                                .chars()
23642                                .next()
23643                                .into_iter()
23644                                .flat_map(|c| c.to_lowercase()),
23645                            buffer_window
23646                                .chars()
23647                                .next()
23648                                .into_iter()
23649                                .flat_map(|c| c.to_lowercase()),
23650                        )
23651                    })
23652                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23653                    .collect::<Vec<StringMatchCandidate>>();
23654
23655                matches.extend(
23656                    fuzzy::match_strings(
23657                        &candidates,
23658                        &buffer_window,
23659                        buffer_window.chars().any(|c| c.is_uppercase()),
23660                        true,
23661                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23662                        &Default::default(),
23663                        executor.clone(),
23664                    )
23665                    .await
23666                    .into_iter()
23667                    .map(|string_match| (string_match, buffer_window.len())),
23668                );
23669
23670                if matches.len() >= MAX_RESULTS {
23671                    break;
23672                }
23673            }
23674
23675            let to_lsp = |point: &text::Anchor| {
23676                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23677                point_to_lsp(end)
23678            };
23679            let lsp_end = to_lsp(&buffer_anchor);
23680
23681            if matches.len() >= MAX_RESULTS {
23682                is_incomplete = true;
23683            }
23684
23685            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23686                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23687                    sorted_snippet_candidates[string_match.candidate_id];
23688                let snippet = &snippets[snippet_index];
23689                let start = buffer_offset - buffer_window_len;
23690                let start = snapshot.anchor_before(start);
23691                let range = start..buffer_anchor;
23692                let lsp_start = to_lsp(&start);
23693                let lsp_range = lsp::Range {
23694                    start: lsp_start,
23695                    end: lsp_end,
23696                };
23697                Completion {
23698                    replace_range: range,
23699                    new_text: snippet.body.clone(),
23700                    source: CompletionSource::Lsp {
23701                        insert_range: None,
23702                        server_id: LanguageServerId(usize::MAX),
23703                        resolved: true,
23704                        lsp_completion: Box::new(lsp::CompletionItem {
23705                            label: snippet.prefix.first().unwrap().clone(),
23706                            kind: Some(CompletionItemKind::SNIPPET),
23707                            label_details: snippet.description.as_ref().map(|description| {
23708                                lsp::CompletionItemLabelDetails {
23709                                    detail: Some(description.clone()),
23710                                    description: None,
23711                                }
23712                            }),
23713                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23714                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23715                                lsp::InsertReplaceEdit {
23716                                    new_text: snippet.body.clone(),
23717                                    insert: lsp_range,
23718                                    replace: lsp_range,
23719                                },
23720                            )),
23721                            filter_text: Some(snippet.body.clone()),
23722                            sort_text: Some(char::MAX.to_string()),
23723                            ..lsp::CompletionItem::default()
23724                        }),
23725                        lsp_defaults: None,
23726                    },
23727                    label: CodeLabel {
23728                        text: matching_prefix.clone(),
23729                        runs: Vec::new(),
23730                        filter_range: 0..matching_prefix.len(),
23731                    },
23732                    icon_path: None,
23733                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23734                        single_line: snippet.name.clone().into(),
23735                        plain_text: snippet
23736                            .description
23737                            .clone()
23738                            .map(|description| description.into()),
23739                    }),
23740                    insert_text_mode: None,
23741                    confirm: None,
23742                    match_start: Some(start),
23743                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23744                }
23745            }));
23746        }
23747
23748        Ok(CompletionResponse {
23749            completions,
23750            display_options: CompletionDisplayOptions::default(),
23751            is_incomplete,
23752        })
23753    })
23754}
23755
23756impl CompletionProvider for Entity<Project> {
23757    fn completions(
23758        &self,
23759        _excerpt_id: ExcerptId,
23760        buffer: &Entity<Buffer>,
23761        buffer_position: text::Anchor,
23762        options: CompletionContext,
23763        _window: &mut Window,
23764        cx: &mut Context<Editor>,
23765    ) -> Task<Result<Vec<CompletionResponse>>> {
23766        self.update(cx, |project, cx| {
23767            let task = project.completions(buffer, buffer_position, options, cx);
23768            cx.background_spawn(task)
23769        })
23770    }
23771
23772    fn resolve_completions(
23773        &self,
23774        buffer: Entity<Buffer>,
23775        completion_indices: Vec<usize>,
23776        completions: Rc<RefCell<Box<[Completion]>>>,
23777        cx: &mut Context<Editor>,
23778    ) -> Task<Result<bool>> {
23779        self.update(cx, |project, cx| {
23780            project.lsp_store().update(cx, |lsp_store, cx| {
23781                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23782            })
23783        })
23784    }
23785
23786    fn apply_additional_edits_for_completion(
23787        &self,
23788        buffer: Entity<Buffer>,
23789        completions: Rc<RefCell<Box<[Completion]>>>,
23790        completion_index: usize,
23791        push_to_history: bool,
23792        cx: &mut Context<Editor>,
23793    ) -> Task<Result<Option<language::Transaction>>> {
23794        self.update(cx, |project, cx| {
23795            project.lsp_store().update(cx, |lsp_store, cx| {
23796                lsp_store.apply_additional_edits_for_completion(
23797                    buffer,
23798                    completions,
23799                    completion_index,
23800                    push_to_history,
23801                    cx,
23802                )
23803            })
23804        })
23805    }
23806
23807    fn is_completion_trigger(
23808        &self,
23809        buffer: &Entity<Buffer>,
23810        position: language::Anchor,
23811        text: &str,
23812        trigger_in_words: bool,
23813        menu_is_open: bool,
23814        cx: &mut Context<Editor>,
23815    ) -> bool {
23816        let mut chars = text.chars();
23817        let char = if let Some(char) = chars.next() {
23818            char
23819        } else {
23820            return false;
23821        };
23822        if chars.next().is_some() {
23823            return false;
23824        }
23825
23826        let buffer = buffer.read(cx);
23827        let snapshot = buffer.snapshot();
23828        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23829            return false;
23830        }
23831        let classifier = snapshot
23832            .char_classifier_at(position)
23833            .scope_context(Some(CharScopeContext::Completion));
23834        if trigger_in_words && classifier.is_word(char) {
23835            return true;
23836        }
23837
23838        buffer.completion_triggers().contains(text)
23839    }
23840
23841    fn show_snippets(&self) -> bool {
23842        true
23843    }
23844}
23845
23846impl SemanticsProvider for Entity<Project> {
23847    fn hover(
23848        &self,
23849        buffer: &Entity<Buffer>,
23850        position: text::Anchor,
23851        cx: &mut App,
23852    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23853        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23854    }
23855
23856    fn document_highlights(
23857        &self,
23858        buffer: &Entity<Buffer>,
23859        position: text::Anchor,
23860        cx: &mut App,
23861    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23862        Some(self.update(cx, |project, cx| {
23863            project.document_highlights(buffer, position, cx)
23864        }))
23865    }
23866
23867    fn definitions(
23868        &self,
23869        buffer: &Entity<Buffer>,
23870        position: text::Anchor,
23871        kind: GotoDefinitionKind,
23872        cx: &mut App,
23873    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23874        Some(self.update(cx, |project, cx| match kind {
23875            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23876            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23877            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23878            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23879        }))
23880    }
23881
23882    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23883        self.update(cx, |project, cx| {
23884            if project
23885                .active_debug_session(cx)
23886                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23887            {
23888                return true;
23889            }
23890
23891            buffer.update(cx, |buffer, cx| {
23892                project.any_language_server_supports_inlay_hints(buffer, cx)
23893            })
23894        })
23895    }
23896
23897    fn inline_values(
23898        &self,
23899        buffer_handle: Entity<Buffer>,
23900        range: Range<text::Anchor>,
23901        cx: &mut App,
23902    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23903        self.update(cx, |project, cx| {
23904            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23905
23906            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23907        })
23908    }
23909
23910    fn applicable_inlay_chunks(
23911        &self,
23912        buffer: &Entity<Buffer>,
23913        ranges: &[Range<text::Anchor>],
23914        cx: &mut App,
23915    ) -> Vec<Range<BufferRow>> {
23916        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23917            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23918        })
23919    }
23920
23921    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23922        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23923            lsp_store.invalidate_inlay_hints(for_buffers)
23924        });
23925    }
23926
23927    fn inlay_hints(
23928        &self,
23929        invalidate: InvalidationStrategy,
23930        buffer: Entity<Buffer>,
23931        ranges: Vec<Range<text::Anchor>>,
23932        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23933        cx: &mut App,
23934    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23935        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23936            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23937        }))
23938    }
23939
23940    fn range_for_rename(
23941        &self,
23942        buffer: &Entity<Buffer>,
23943        position: text::Anchor,
23944        cx: &mut App,
23945    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23946        Some(self.update(cx, |project, cx| {
23947            let buffer = buffer.clone();
23948            let task = project.prepare_rename(buffer.clone(), position, cx);
23949            cx.spawn(async move |_, cx| {
23950                Ok(match task.await? {
23951                    PrepareRenameResponse::Success(range) => Some(range),
23952                    PrepareRenameResponse::InvalidPosition => None,
23953                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23954                        // Fallback on using TreeSitter info to determine identifier range
23955                        buffer.read_with(cx, |buffer, _| {
23956                            let snapshot = buffer.snapshot();
23957                            let (range, kind) = snapshot.surrounding_word(position, None);
23958                            if kind != Some(CharKind::Word) {
23959                                return None;
23960                            }
23961                            Some(
23962                                snapshot.anchor_before(range.start)
23963                                    ..snapshot.anchor_after(range.end),
23964                            )
23965                        })?
23966                    }
23967                })
23968            })
23969        }))
23970    }
23971
23972    fn perform_rename(
23973        &self,
23974        buffer: &Entity<Buffer>,
23975        position: text::Anchor,
23976        new_name: String,
23977        cx: &mut App,
23978    ) -> Option<Task<Result<ProjectTransaction>>> {
23979        Some(self.update(cx, |project, cx| {
23980            project.perform_rename(buffer.clone(), position, new_name, cx)
23981        }))
23982    }
23983}
23984
23985fn consume_contiguous_rows(
23986    contiguous_row_selections: &mut Vec<Selection<Point>>,
23987    selection: &Selection<Point>,
23988    display_map: &DisplaySnapshot,
23989    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23990) -> (MultiBufferRow, MultiBufferRow) {
23991    contiguous_row_selections.push(selection.clone());
23992    let start_row = starting_row(selection, display_map);
23993    let mut end_row = ending_row(selection, display_map);
23994
23995    while let Some(next_selection) = selections.peek() {
23996        if next_selection.start.row <= end_row.0 {
23997            end_row = ending_row(next_selection, display_map);
23998            contiguous_row_selections.push(selections.next().unwrap().clone());
23999        } else {
24000            break;
24001        }
24002    }
24003    (start_row, end_row)
24004}
24005
24006fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24007    if selection.start.column > 0 {
24008        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24009    } else {
24010        MultiBufferRow(selection.start.row)
24011    }
24012}
24013
24014fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24015    if next_selection.end.column > 0 || next_selection.is_empty() {
24016        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24017    } else {
24018        MultiBufferRow(next_selection.end.row)
24019    }
24020}
24021
24022impl EditorSnapshot {
24023    pub fn remote_selections_in_range<'a>(
24024        &'a self,
24025        range: &'a Range<Anchor>,
24026        collaboration_hub: &dyn CollaborationHub,
24027        cx: &'a App,
24028    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24029        let participant_names = collaboration_hub.user_names(cx);
24030        let participant_indices = collaboration_hub.user_participant_indices(cx);
24031        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24032        let collaborators_by_replica_id = collaborators_by_peer_id
24033            .values()
24034            .map(|collaborator| (collaborator.replica_id, collaborator))
24035            .collect::<HashMap<_, _>>();
24036        self.buffer_snapshot()
24037            .selections_in_range(range, false)
24038            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24039                if replica_id == ReplicaId::AGENT {
24040                    Some(RemoteSelection {
24041                        replica_id,
24042                        selection,
24043                        cursor_shape,
24044                        line_mode,
24045                        collaborator_id: CollaboratorId::Agent,
24046                        user_name: Some("Agent".into()),
24047                        color: cx.theme().players().agent(),
24048                    })
24049                } else {
24050                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24051                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24052                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24053                    Some(RemoteSelection {
24054                        replica_id,
24055                        selection,
24056                        cursor_shape,
24057                        line_mode,
24058                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24059                        user_name,
24060                        color: if let Some(index) = participant_index {
24061                            cx.theme().players().color_for_participant(index.0)
24062                        } else {
24063                            cx.theme().players().absent()
24064                        },
24065                    })
24066                }
24067            })
24068    }
24069
24070    pub fn hunks_for_ranges(
24071        &self,
24072        ranges: impl IntoIterator<Item = Range<Point>>,
24073    ) -> Vec<MultiBufferDiffHunk> {
24074        let mut hunks = Vec::new();
24075        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24076            HashMap::default();
24077        for query_range in ranges {
24078            let query_rows =
24079                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24080            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24081                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24082            ) {
24083                // Include deleted hunks that are adjacent to the query range, because
24084                // otherwise they would be missed.
24085                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24086                if hunk.status().is_deleted() {
24087                    intersects_range |= hunk.row_range.start == query_rows.end;
24088                    intersects_range |= hunk.row_range.end == query_rows.start;
24089                }
24090                if intersects_range {
24091                    if !processed_buffer_rows
24092                        .entry(hunk.buffer_id)
24093                        .or_default()
24094                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24095                    {
24096                        continue;
24097                    }
24098                    hunks.push(hunk);
24099                }
24100            }
24101        }
24102
24103        hunks
24104    }
24105
24106    fn display_diff_hunks_for_rows<'a>(
24107        &'a self,
24108        display_rows: Range<DisplayRow>,
24109        folded_buffers: &'a HashSet<BufferId>,
24110    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24111        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24112        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24113
24114        self.buffer_snapshot()
24115            .diff_hunks_in_range(buffer_start..buffer_end)
24116            .filter_map(|hunk| {
24117                if folded_buffers.contains(&hunk.buffer_id) {
24118                    return None;
24119                }
24120
24121                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24122                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24123
24124                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24125                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24126
24127                let display_hunk = if hunk_display_start.column() != 0 {
24128                    DisplayDiffHunk::Folded {
24129                        display_row: hunk_display_start.row(),
24130                    }
24131                } else {
24132                    let mut end_row = hunk_display_end.row();
24133                    if hunk_display_end.column() > 0 {
24134                        end_row.0 += 1;
24135                    }
24136                    let is_created_file = hunk.is_created_file();
24137
24138                    DisplayDiffHunk::Unfolded {
24139                        status: hunk.status(),
24140                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24141                            ..hunk.diff_base_byte_range.end.0,
24142                        word_diffs: hunk.word_diffs,
24143                        display_row_range: hunk_display_start.row()..end_row,
24144                        multi_buffer_range: Anchor::range_in_buffer(
24145                            hunk.excerpt_id,
24146                            hunk.buffer_range,
24147                        ),
24148                        is_created_file,
24149                    }
24150                };
24151
24152                Some(display_hunk)
24153            })
24154    }
24155
24156    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24157        self.display_snapshot
24158            .buffer_snapshot()
24159            .language_at(position)
24160    }
24161
24162    pub fn is_focused(&self) -> bool {
24163        self.is_focused
24164    }
24165
24166    pub fn placeholder_text(&self) -> Option<String> {
24167        self.placeholder_display_snapshot
24168            .as_ref()
24169            .map(|display_map| display_map.text())
24170    }
24171
24172    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24173        self.scroll_anchor.scroll_position(&self.display_snapshot)
24174    }
24175
24176    fn gutter_dimensions(
24177        &self,
24178        font_id: FontId,
24179        font_size: Pixels,
24180        max_line_number_width: Pixels,
24181        cx: &App,
24182    ) -> Option<GutterDimensions> {
24183        if !self.show_gutter {
24184            return None;
24185        }
24186
24187        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24188        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24189
24190        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24191            matches!(
24192                ProjectSettings::get_global(cx).git.git_gutter,
24193                GitGutterSetting::TrackedFiles
24194            )
24195        });
24196        let gutter_settings = EditorSettings::get_global(cx).gutter;
24197        let show_line_numbers = self
24198            .show_line_numbers
24199            .unwrap_or(gutter_settings.line_numbers);
24200        let line_gutter_width = if show_line_numbers {
24201            // Avoid flicker-like gutter resizes when the line number gains another digit by
24202            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24203            let min_width_for_number_on_gutter =
24204                ch_advance * gutter_settings.min_line_number_digits as f32;
24205            max_line_number_width.max(min_width_for_number_on_gutter)
24206        } else {
24207            0.0.into()
24208        };
24209
24210        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24211        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24212
24213        let git_blame_entries_width =
24214            self.git_blame_gutter_max_author_length
24215                .map(|max_author_length| {
24216                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24217                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24218
24219                    /// The number of characters to dedicate to gaps and margins.
24220                    const SPACING_WIDTH: usize = 4;
24221
24222                    let max_char_count = max_author_length.min(renderer.max_author_length())
24223                        + ::git::SHORT_SHA_LENGTH
24224                        + MAX_RELATIVE_TIMESTAMP.len()
24225                        + SPACING_WIDTH;
24226
24227                    ch_advance * max_char_count
24228                });
24229
24230        let is_singleton = self.buffer_snapshot().is_singleton();
24231
24232        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24233        left_padding += if !is_singleton {
24234            ch_width * 4.0
24235        } else if show_runnables || show_breakpoints {
24236            ch_width * 3.0
24237        } else if show_git_gutter && show_line_numbers {
24238            ch_width * 2.0
24239        } else if show_git_gutter || show_line_numbers {
24240            ch_width
24241        } else {
24242            px(0.)
24243        };
24244
24245        let shows_folds = is_singleton && gutter_settings.folds;
24246
24247        let right_padding = if shows_folds && show_line_numbers {
24248            ch_width * 4.0
24249        } else if shows_folds || (!is_singleton && show_line_numbers) {
24250            ch_width * 3.0
24251        } else if show_line_numbers {
24252            ch_width
24253        } else {
24254            px(0.)
24255        };
24256
24257        Some(GutterDimensions {
24258            left_padding,
24259            right_padding,
24260            width: line_gutter_width + left_padding + right_padding,
24261            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24262            git_blame_entries_width,
24263        })
24264    }
24265
24266    pub fn render_crease_toggle(
24267        &self,
24268        buffer_row: MultiBufferRow,
24269        row_contains_cursor: bool,
24270        editor: Entity<Editor>,
24271        window: &mut Window,
24272        cx: &mut App,
24273    ) -> Option<AnyElement> {
24274        let folded = self.is_line_folded(buffer_row);
24275        let mut is_foldable = false;
24276
24277        if let Some(crease) = self
24278            .crease_snapshot
24279            .query_row(buffer_row, self.buffer_snapshot())
24280        {
24281            is_foldable = true;
24282            match crease {
24283                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24284                    if let Some(render_toggle) = render_toggle {
24285                        let toggle_callback =
24286                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24287                                if folded {
24288                                    editor.update(cx, |editor, cx| {
24289                                        editor.fold_at(buffer_row, window, cx)
24290                                    });
24291                                } else {
24292                                    editor.update(cx, |editor, cx| {
24293                                        editor.unfold_at(buffer_row, window, cx)
24294                                    });
24295                                }
24296                            });
24297                        return Some((render_toggle)(
24298                            buffer_row,
24299                            folded,
24300                            toggle_callback,
24301                            window,
24302                            cx,
24303                        ));
24304                    }
24305                }
24306            }
24307        }
24308
24309        is_foldable |= self.starts_indent(buffer_row);
24310
24311        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24312            Some(
24313                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24314                    .toggle_state(folded)
24315                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24316                        if folded {
24317                            this.unfold_at(buffer_row, window, cx);
24318                        } else {
24319                            this.fold_at(buffer_row, window, cx);
24320                        }
24321                    }))
24322                    .into_any_element(),
24323            )
24324        } else {
24325            None
24326        }
24327    }
24328
24329    pub fn render_crease_trailer(
24330        &self,
24331        buffer_row: MultiBufferRow,
24332        window: &mut Window,
24333        cx: &mut App,
24334    ) -> Option<AnyElement> {
24335        let folded = self.is_line_folded(buffer_row);
24336        if let Crease::Inline { render_trailer, .. } = self
24337            .crease_snapshot
24338            .query_row(buffer_row, self.buffer_snapshot())?
24339        {
24340            let render_trailer = render_trailer.as_ref()?;
24341            Some(render_trailer(buffer_row, folded, window, cx))
24342        } else {
24343            None
24344        }
24345    }
24346}
24347
24348impl Deref for EditorSnapshot {
24349    type Target = DisplaySnapshot;
24350
24351    fn deref(&self) -> &Self::Target {
24352        &self.display_snapshot
24353    }
24354}
24355
24356#[derive(Clone, Debug, PartialEq, Eq)]
24357pub enum EditorEvent {
24358    InputIgnored {
24359        text: Arc<str>,
24360    },
24361    InputHandled {
24362        utf16_range_to_replace: Option<Range<isize>>,
24363        text: Arc<str>,
24364    },
24365    ExcerptsAdded {
24366        buffer: Entity<Buffer>,
24367        predecessor: ExcerptId,
24368        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24369    },
24370    ExcerptsRemoved {
24371        ids: Vec<ExcerptId>,
24372        removed_buffer_ids: Vec<BufferId>,
24373    },
24374    BufferFoldToggled {
24375        ids: Vec<ExcerptId>,
24376        folded: bool,
24377    },
24378    ExcerptsEdited {
24379        ids: Vec<ExcerptId>,
24380    },
24381    ExcerptsExpanded {
24382        ids: Vec<ExcerptId>,
24383    },
24384    BufferEdited,
24385    Edited {
24386        transaction_id: clock::Lamport,
24387    },
24388    Reparsed(BufferId),
24389    Focused,
24390    FocusedIn,
24391    Blurred,
24392    DirtyChanged,
24393    Saved,
24394    TitleChanged,
24395    SelectionsChanged {
24396        local: bool,
24397    },
24398    ScrollPositionChanged {
24399        local: bool,
24400        autoscroll: bool,
24401    },
24402    TransactionUndone {
24403        transaction_id: clock::Lamport,
24404    },
24405    TransactionBegun {
24406        transaction_id: clock::Lamport,
24407    },
24408    CursorShapeChanged,
24409    BreadcrumbsChanged,
24410    PushedToNavHistory {
24411        anchor: Anchor,
24412        is_deactivate: bool,
24413    },
24414}
24415
24416impl EventEmitter<EditorEvent> for Editor {}
24417
24418impl Focusable for Editor {
24419    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24420        self.focus_handle.clone()
24421    }
24422}
24423
24424impl Render for Editor {
24425    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24426        let settings = ThemeSettings::get_global(cx);
24427
24428        let mut text_style = match self.mode {
24429            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24430                color: cx.theme().colors().editor_foreground,
24431                font_family: settings.ui_font.family.clone(),
24432                font_features: settings.ui_font.features.clone(),
24433                font_fallbacks: settings.ui_font.fallbacks.clone(),
24434                font_size: rems(0.875).into(),
24435                font_weight: settings.ui_font.weight,
24436                line_height: relative(settings.buffer_line_height.value()),
24437                ..Default::default()
24438            },
24439            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24440                color: cx.theme().colors().editor_foreground,
24441                font_family: settings.buffer_font.family.clone(),
24442                font_features: settings.buffer_font.features.clone(),
24443                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24444                font_size: settings.buffer_font_size(cx).into(),
24445                font_weight: settings.buffer_font.weight,
24446                line_height: relative(settings.buffer_line_height.value()),
24447                ..Default::default()
24448            },
24449        };
24450        if let Some(text_style_refinement) = &self.text_style_refinement {
24451            text_style.refine(text_style_refinement)
24452        }
24453
24454        let background = match self.mode {
24455            EditorMode::SingleLine => cx.theme().system().transparent,
24456            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24457            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24458            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24459        };
24460
24461        EditorElement::new(
24462            &cx.entity(),
24463            EditorStyle {
24464                background,
24465                border: cx.theme().colors().border,
24466                local_player: cx.theme().players().local(),
24467                text: text_style,
24468                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24469                syntax: cx.theme().syntax().clone(),
24470                status: cx.theme().status().clone(),
24471                inlay_hints_style: make_inlay_hints_style(cx),
24472                edit_prediction_styles: make_suggestion_styles(cx),
24473                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24474                show_underlines: self.diagnostics_enabled(),
24475            },
24476        )
24477    }
24478}
24479
24480impl EntityInputHandler for Editor {
24481    fn text_for_range(
24482        &mut self,
24483        range_utf16: Range<usize>,
24484        adjusted_range: &mut Option<Range<usize>>,
24485        _: &mut Window,
24486        cx: &mut Context<Self>,
24487    ) -> Option<String> {
24488        let snapshot = self.buffer.read(cx).read(cx);
24489        let start = snapshot.clip_offset_utf16(
24490            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24491            Bias::Left,
24492        );
24493        let end = snapshot.clip_offset_utf16(
24494            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24495            Bias::Right,
24496        );
24497        if (start.0.0..end.0.0) != range_utf16 {
24498            adjusted_range.replace(start.0.0..end.0.0);
24499        }
24500        Some(snapshot.text_for_range(start..end).collect())
24501    }
24502
24503    fn selected_text_range(
24504        &mut self,
24505        ignore_disabled_input: bool,
24506        _: &mut Window,
24507        cx: &mut Context<Self>,
24508    ) -> Option<UTF16Selection> {
24509        // Prevent the IME menu from appearing when holding down an alphabetic key
24510        // while input is disabled.
24511        if !ignore_disabled_input && !self.input_enabled {
24512            return None;
24513        }
24514
24515        let selection = self
24516            .selections
24517            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24518        let range = selection.range();
24519
24520        Some(UTF16Selection {
24521            range: range.start.0.0..range.end.0.0,
24522            reversed: selection.reversed,
24523        })
24524    }
24525
24526    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24527        let snapshot = self.buffer.read(cx).read(cx);
24528        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24529        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24530    }
24531
24532    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24533        self.clear_highlights::<InputComposition>(cx);
24534        self.ime_transaction.take();
24535    }
24536
24537    fn replace_text_in_range(
24538        &mut self,
24539        range_utf16: Option<Range<usize>>,
24540        text: &str,
24541        window: &mut Window,
24542        cx: &mut Context<Self>,
24543    ) {
24544        if !self.input_enabled {
24545            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24546            return;
24547        }
24548
24549        self.transact(window, cx, |this, window, cx| {
24550            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24551                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24552                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24553                Some(this.selection_replacement_ranges(range_utf16, cx))
24554            } else {
24555                this.marked_text_ranges(cx)
24556            };
24557
24558            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24559                let newest_selection_id = this.selections.newest_anchor().id;
24560                this.selections
24561                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24562                    .iter()
24563                    .zip(ranges_to_replace.iter())
24564                    .find_map(|(selection, range)| {
24565                        if selection.id == newest_selection_id {
24566                            Some(
24567                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24568                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24569                            )
24570                        } else {
24571                            None
24572                        }
24573                    })
24574            });
24575
24576            cx.emit(EditorEvent::InputHandled {
24577                utf16_range_to_replace: range_to_replace,
24578                text: text.into(),
24579            });
24580
24581            if let Some(new_selected_ranges) = new_selected_ranges {
24582                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24583                    selections.select_ranges(new_selected_ranges)
24584                });
24585                this.backspace(&Default::default(), window, cx);
24586            }
24587
24588            this.handle_input(text, window, cx);
24589        });
24590
24591        if let Some(transaction) = self.ime_transaction {
24592            self.buffer.update(cx, |buffer, cx| {
24593                buffer.group_until_transaction(transaction, cx);
24594            });
24595        }
24596
24597        self.unmark_text(window, cx);
24598    }
24599
24600    fn replace_and_mark_text_in_range(
24601        &mut self,
24602        range_utf16: Option<Range<usize>>,
24603        text: &str,
24604        new_selected_range_utf16: Option<Range<usize>>,
24605        window: &mut Window,
24606        cx: &mut Context<Self>,
24607    ) {
24608        if !self.input_enabled {
24609            return;
24610        }
24611
24612        let transaction = self.transact(window, cx, |this, window, cx| {
24613            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24614                let snapshot = this.buffer.read(cx).read(cx);
24615                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24616                    for marked_range in &mut marked_ranges {
24617                        marked_range.end = marked_range.start + relative_range_utf16.end;
24618                        marked_range.start += relative_range_utf16.start;
24619                        marked_range.start =
24620                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24621                        marked_range.end =
24622                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24623                    }
24624                }
24625                Some(marked_ranges)
24626            } else if let Some(range_utf16) = range_utf16 {
24627                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24628                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24629                Some(this.selection_replacement_ranges(range_utf16, cx))
24630            } else {
24631                None
24632            };
24633
24634            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24635                let newest_selection_id = this.selections.newest_anchor().id;
24636                this.selections
24637                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24638                    .iter()
24639                    .zip(ranges_to_replace.iter())
24640                    .find_map(|(selection, range)| {
24641                        if selection.id == newest_selection_id {
24642                            Some(
24643                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24644                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24645                            )
24646                        } else {
24647                            None
24648                        }
24649                    })
24650            });
24651
24652            cx.emit(EditorEvent::InputHandled {
24653                utf16_range_to_replace: range_to_replace,
24654                text: text.into(),
24655            });
24656
24657            if let Some(ranges) = ranges_to_replace {
24658                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24659                    s.select_ranges(ranges)
24660                });
24661            }
24662
24663            let marked_ranges = {
24664                let snapshot = this.buffer.read(cx).read(cx);
24665                this.selections
24666                    .disjoint_anchors_arc()
24667                    .iter()
24668                    .map(|selection| {
24669                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24670                    })
24671                    .collect::<Vec<_>>()
24672            };
24673
24674            if text.is_empty() {
24675                this.unmark_text(window, cx);
24676            } else {
24677                this.highlight_text::<InputComposition>(
24678                    marked_ranges.clone(),
24679                    HighlightStyle {
24680                        underline: Some(UnderlineStyle {
24681                            thickness: px(1.),
24682                            color: None,
24683                            wavy: false,
24684                        }),
24685                        ..Default::default()
24686                    },
24687                    cx,
24688                );
24689            }
24690
24691            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24692            let use_autoclose = this.use_autoclose;
24693            let use_auto_surround = this.use_auto_surround;
24694            this.set_use_autoclose(false);
24695            this.set_use_auto_surround(false);
24696            this.handle_input(text, window, cx);
24697            this.set_use_autoclose(use_autoclose);
24698            this.set_use_auto_surround(use_auto_surround);
24699
24700            if let Some(new_selected_range) = new_selected_range_utf16 {
24701                let snapshot = this.buffer.read(cx).read(cx);
24702                let new_selected_ranges = marked_ranges
24703                    .into_iter()
24704                    .map(|marked_range| {
24705                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24706                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24707                            insertion_start.0 + new_selected_range.start,
24708                        ));
24709                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24710                            insertion_start.0 + new_selected_range.end,
24711                        ));
24712                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24713                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24714                    })
24715                    .collect::<Vec<_>>();
24716
24717                drop(snapshot);
24718                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24719                    selections.select_ranges(new_selected_ranges)
24720                });
24721            }
24722        });
24723
24724        self.ime_transaction = self.ime_transaction.or(transaction);
24725        if let Some(transaction) = self.ime_transaction {
24726            self.buffer.update(cx, |buffer, cx| {
24727                buffer.group_until_transaction(transaction, cx);
24728            });
24729        }
24730
24731        if self.text_highlights::<InputComposition>(cx).is_none() {
24732            self.ime_transaction.take();
24733        }
24734    }
24735
24736    fn bounds_for_range(
24737        &mut self,
24738        range_utf16: Range<usize>,
24739        element_bounds: gpui::Bounds<Pixels>,
24740        window: &mut Window,
24741        cx: &mut Context<Self>,
24742    ) -> Option<gpui::Bounds<Pixels>> {
24743        let text_layout_details = self.text_layout_details(window);
24744        let CharacterDimensions {
24745            em_width,
24746            em_advance,
24747            line_height,
24748        } = self.character_dimensions(window);
24749
24750        let snapshot = self.snapshot(window, cx);
24751        let scroll_position = snapshot.scroll_position();
24752        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24753
24754        let start =
24755            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24756        let x = Pixels::from(
24757            ScrollOffset::from(
24758                snapshot.x_for_display_point(start, &text_layout_details)
24759                    + self.gutter_dimensions.full_width(),
24760            ) - scroll_left,
24761        );
24762        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24763
24764        Some(Bounds {
24765            origin: element_bounds.origin + point(x, y),
24766            size: size(em_width, line_height),
24767        })
24768    }
24769
24770    fn character_index_for_point(
24771        &mut self,
24772        point: gpui::Point<Pixels>,
24773        _window: &mut Window,
24774        _cx: &mut Context<Self>,
24775    ) -> Option<usize> {
24776        let position_map = self.last_position_map.as_ref()?;
24777        if !position_map.text_hitbox.contains(&point) {
24778            return None;
24779        }
24780        let display_point = position_map.point_for_position(point).previous_valid;
24781        let anchor = position_map
24782            .snapshot
24783            .display_point_to_anchor(display_point, Bias::Left);
24784        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24785        Some(utf16_offset.0.0)
24786    }
24787
24788    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24789        self.input_enabled
24790    }
24791}
24792
24793trait SelectionExt {
24794    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24795    fn spanned_rows(
24796        &self,
24797        include_end_if_at_line_start: bool,
24798        map: &DisplaySnapshot,
24799    ) -> Range<MultiBufferRow>;
24800}
24801
24802impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24803    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24804        let start = self
24805            .start
24806            .to_point(map.buffer_snapshot())
24807            .to_display_point(map);
24808        let end = self
24809            .end
24810            .to_point(map.buffer_snapshot())
24811            .to_display_point(map);
24812        if self.reversed {
24813            end..start
24814        } else {
24815            start..end
24816        }
24817    }
24818
24819    fn spanned_rows(
24820        &self,
24821        include_end_if_at_line_start: bool,
24822        map: &DisplaySnapshot,
24823    ) -> Range<MultiBufferRow> {
24824        let start = self.start.to_point(map.buffer_snapshot());
24825        let mut end = self.end.to_point(map.buffer_snapshot());
24826        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24827            end.row -= 1;
24828        }
24829
24830        let buffer_start = map.prev_line_boundary(start).0;
24831        let buffer_end = map.next_line_boundary(end).0;
24832        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24833    }
24834}
24835
24836impl<T: InvalidationRegion> InvalidationStack<T> {
24837    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24838    where
24839        S: Clone + ToOffset,
24840    {
24841        while let Some(region) = self.last() {
24842            let all_selections_inside_invalidation_ranges =
24843                if selections.len() == region.ranges().len() {
24844                    selections
24845                        .iter()
24846                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24847                        .all(|(selection, invalidation_range)| {
24848                            let head = selection.head().to_offset(buffer);
24849                            invalidation_range.start <= head && invalidation_range.end >= head
24850                        })
24851                } else {
24852                    false
24853                };
24854
24855            if all_selections_inside_invalidation_ranges {
24856                break;
24857            } else {
24858                self.pop();
24859            }
24860        }
24861    }
24862}
24863
24864impl<T> Default for InvalidationStack<T> {
24865    fn default() -> Self {
24866        Self(Default::default())
24867    }
24868}
24869
24870impl<T> Deref for InvalidationStack<T> {
24871    type Target = Vec<T>;
24872
24873    fn deref(&self) -> &Self::Target {
24874        &self.0
24875    }
24876}
24877
24878impl<T> DerefMut for InvalidationStack<T> {
24879    fn deref_mut(&mut self) -> &mut Self::Target {
24880        &mut self.0
24881    }
24882}
24883
24884impl InvalidationRegion for SnippetState {
24885    fn ranges(&self) -> &[Range<Anchor>] {
24886        &self.ranges[self.active_index]
24887    }
24888}
24889
24890fn edit_prediction_edit_text(
24891    current_snapshot: &BufferSnapshot,
24892    edits: &[(Range<Anchor>, impl AsRef<str>)],
24893    edit_preview: &EditPreview,
24894    include_deletions: bool,
24895    cx: &App,
24896) -> HighlightedText {
24897    let edits = edits
24898        .iter()
24899        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24900        .collect::<Vec<_>>();
24901
24902    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24903}
24904
24905fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24906    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24907    // Just show the raw edit text with basic styling
24908    let mut text = String::new();
24909    let mut highlights = Vec::new();
24910
24911    let insertion_highlight_style = HighlightStyle {
24912        color: Some(cx.theme().colors().text),
24913        ..Default::default()
24914    };
24915
24916    for (_, edit_text) in edits {
24917        let start_offset = text.len();
24918        text.push_str(edit_text);
24919        let end_offset = text.len();
24920
24921        if start_offset < end_offset {
24922            highlights.push((start_offset..end_offset, insertion_highlight_style));
24923        }
24924    }
24925
24926    HighlightedText {
24927        text: text.into(),
24928        highlights,
24929    }
24930}
24931
24932pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24933    match severity {
24934        lsp::DiagnosticSeverity::ERROR => colors.error,
24935        lsp::DiagnosticSeverity::WARNING => colors.warning,
24936        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24937        lsp::DiagnosticSeverity::HINT => colors.info,
24938        _ => colors.ignored,
24939    }
24940}
24941
24942pub fn styled_runs_for_code_label<'a>(
24943    label: &'a CodeLabel,
24944    syntax_theme: &'a theme::SyntaxTheme,
24945    local_player: &'a theme::PlayerColor,
24946) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24947    let fade_out = HighlightStyle {
24948        fade_out: Some(0.35),
24949        ..Default::default()
24950    };
24951
24952    let mut prev_end = label.filter_range.end;
24953    label
24954        .runs
24955        .iter()
24956        .enumerate()
24957        .flat_map(move |(ix, (range, highlight_id))| {
24958            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
24959                HighlightStyle {
24960                    color: Some(local_player.cursor),
24961                    ..Default::default()
24962                }
24963            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
24964                HighlightStyle {
24965                    background_color: Some(local_player.selection),
24966                    ..Default::default()
24967                }
24968            } else if let Some(style) = highlight_id.style(syntax_theme) {
24969                style
24970            } else {
24971                return Default::default();
24972            };
24973            let muted_style = style.highlight(fade_out);
24974
24975            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24976            if range.start >= label.filter_range.end {
24977                if range.start > prev_end {
24978                    runs.push((prev_end..range.start, fade_out));
24979                }
24980                runs.push((range.clone(), muted_style));
24981            } else if range.end <= label.filter_range.end {
24982                runs.push((range.clone(), style));
24983            } else {
24984                runs.push((range.start..label.filter_range.end, style));
24985                runs.push((label.filter_range.end..range.end, muted_style));
24986            }
24987            prev_end = cmp::max(prev_end, range.end);
24988
24989            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24990                runs.push((prev_end..label.text.len(), fade_out));
24991            }
24992
24993            runs
24994        })
24995}
24996
24997pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24998    let mut prev_index = 0;
24999    let mut prev_codepoint: Option<char> = None;
25000    text.char_indices()
25001        .chain([(text.len(), '\0')])
25002        .filter_map(move |(index, codepoint)| {
25003            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25004            let is_boundary = index == text.len()
25005                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25006                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25007            if is_boundary {
25008                let chunk = &text[prev_index..index];
25009                prev_index = index;
25010                Some(chunk)
25011            } else {
25012                None
25013            }
25014        })
25015}
25016
25017/// Given a string of text immediately before the cursor, iterates over possible
25018/// strings a snippet could match to. More precisely: returns an iterator over
25019/// suffixes of `text` created by splitting at word boundaries (before & after
25020/// every non-word character).
25021///
25022/// Shorter suffixes are returned first.
25023pub(crate) fn snippet_candidate_suffixes(
25024    text: &str,
25025    is_word_char: impl Fn(char) -> bool,
25026) -> impl std::iter::Iterator<Item = &str> {
25027    let mut prev_index = text.len();
25028    let mut prev_codepoint = None;
25029    text.char_indices()
25030        .rev()
25031        .chain([(0, '\0')])
25032        .filter_map(move |(index, codepoint)| {
25033            let prev_index = std::mem::replace(&mut prev_index, index);
25034            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25035            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25036                None
25037            } else {
25038                let chunk = &text[prev_index..]; // go to end of string
25039                Some(chunk)
25040            }
25041        })
25042}
25043
25044pub trait RangeToAnchorExt: Sized {
25045    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25046
25047    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25048        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25049        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25050    }
25051}
25052
25053impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25054    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25055        let start_offset = self.start.to_offset(snapshot);
25056        let end_offset = self.end.to_offset(snapshot);
25057        if start_offset == end_offset {
25058            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25059        } else {
25060            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25061        }
25062    }
25063}
25064
25065pub trait RowExt {
25066    fn as_f64(&self) -> f64;
25067
25068    fn next_row(&self) -> Self;
25069
25070    fn previous_row(&self) -> Self;
25071
25072    fn minus(&self, other: Self) -> u32;
25073}
25074
25075impl RowExt for DisplayRow {
25076    fn as_f64(&self) -> f64 {
25077        self.0 as _
25078    }
25079
25080    fn next_row(&self) -> Self {
25081        Self(self.0 + 1)
25082    }
25083
25084    fn previous_row(&self) -> Self {
25085        Self(self.0.saturating_sub(1))
25086    }
25087
25088    fn minus(&self, other: Self) -> u32 {
25089        self.0 - other.0
25090    }
25091}
25092
25093impl RowExt for MultiBufferRow {
25094    fn as_f64(&self) -> f64 {
25095        self.0 as _
25096    }
25097
25098    fn next_row(&self) -> Self {
25099        Self(self.0 + 1)
25100    }
25101
25102    fn previous_row(&self) -> Self {
25103        Self(self.0.saturating_sub(1))
25104    }
25105
25106    fn minus(&self, other: Self) -> u32 {
25107        self.0 - other.0
25108    }
25109}
25110
25111trait RowRangeExt {
25112    type Row;
25113
25114    fn len(&self) -> usize;
25115
25116    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25117}
25118
25119impl RowRangeExt for Range<MultiBufferRow> {
25120    type Row = MultiBufferRow;
25121
25122    fn len(&self) -> usize {
25123        (self.end.0 - self.start.0) as usize
25124    }
25125
25126    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25127        (self.start.0..self.end.0).map(MultiBufferRow)
25128    }
25129}
25130
25131impl RowRangeExt for Range<DisplayRow> {
25132    type Row = DisplayRow;
25133
25134    fn len(&self) -> usize {
25135        (self.end.0 - self.start.0) as usize
25136    }
25137
25138    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25139        (self.start.0..self.end.0).map(DisplayRow)
25140    }
25141}
25142
25143/// If select range has more than one line, we
25144/// just point the cursor to range.start.
25145fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25146    if range.start.row == range.end.row {
25147        range
25148    } else {
25149        range.start..range.start
25150    }
25151}
25152pub struct KillRing(ClipboardItem);
25153impl Global for KillRing {}
25154
25155const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25156
25157enum BreakpointPromptEditAction {
25158    Log,
25159    Condition,
25160    HitCondition,
25161}
25162
25163struct BreakpointPromptEditor {
25164    pub(crate) prompt: Entity<Editor>,
25165    editor: WeakEntity<Editor>,
25166    breakpoint_anchor: Anchor,
25167    breakpoint: Breakpoint,
25168    edit_action: BreakpointPromptEditAction,
25169    block_ids: HashSet<CustomBlockId>,
25170    editor_margins: Arc<Mutex<EditorMargins>>,
25171    _subscriptions: Vec<Subscription>,
25172}
25173
25174impl BreakpointPromptEditor {
25175    const MAX_LINES: u8 = 4;
25176
25177    fn new(
25178        editor: WeakEntity<Editor>,
25179        breakpoint_anchor: Anchor,
25180        breakpoint: Breakpoint,
25181        edit_action: BreakpointPromptEditAction,
25182        window: &mut Window,
25183        cx: &mut Context<Self>,
25184    ) -> Self {
25185        let base_text = match edit_action {
25186            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25187            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25188            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25189        }
25190        .map(|msg| msg.to_string())
25191        .unwrap_or_default();
25192
25193        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25194        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25195
25196        let prompt = cx.new(|cx| {
25197            let mut prompt = Editor::new(
25198                EditorMode::AutoHeight {
25199                    min_lines: 1,
25200                    max_lines: Some(Self::MAX_LINES as usize),
25201                },
25202                buffer,
25203                None,
25204                window,
25205                cx,
25206            );
25207            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25208            prompt.set_show_cursor_when_unfocused(false, cx);
25209            prompt.set_placeholder_text(
25210                match edit_action {
25211                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25212                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25213                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25214                },
25215                window,
25216                cx,
25217            );
25218
25219            prompt
25220        });
25221
25222        Self {
25223            prompt,
25224            editor,
25225            breakpoint_anchor,
25226            breakpoint,
25227            edit_action,
25228            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25229            block_ids: Default::default(),
25230            _subscriptions: vec![],
25231        }
25232    }
25233
25234    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25235        self.block_ids.extend(block_ids)
25236    }
25237
25238    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25239        if let Some(editor) = self.editor.upgrade() {
25240            let message = self
25241                .prompt
25242                .read(cx)
25243                .buffer
25244                .read(cx)
25245                .as_singleton()
25246                .expect("A multi buffer in breakpoint prompt isn't possible")
25247                .read(cx)
25248                .as_rope()
25249                .to_string();
25250
25251            editor.update(cx, |editor, cx| {
25252                editor.edit_breakpoint_at_anchor(
25253                    self.breakpoint_anchor,
25254                    self.breakpoint.clone(),
25255                    match self.edit_action {
25256                        BreakpointPromptEditAction::Log => {
25257                            BreakpointEditAction::EditLogMessage(message.into())
25258                        }
25259                        BreakpointPromptEditAction::Condition => {
25260                            BreakpointEditAction::EditCondition(message.into())
25261                        }
25262                        BreakpointPromptEditAction::HitCondition => {
25263                            BreakpointEditAction::EditHitCondition(message.into())
25264                        }
25265                    },
25266                    cx,
25267                );
25268
25269                editor.remove_blocks(self.block_ids.clone(), None, cx);
25270                cx.focus_self(window);
25271            });
25272        }
25273    }
25274
25275    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25276        self.editor
25277            .update(cx, |editor, cx| {
25278                editor.remove_blocks(self.block_ids.clone(), None, cx);
25279                window.focus(&editor.focus_handle);
25280            })
25281            .log_err();
25282    }
25283
25284    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25285        let settings = ThemeSettings::get_global(cx);
25286        let text_style = TextStyle {
25287            color: if self.prompt.read(cx).read_only(cx) {
25288                cx.theme().colors().text_disabled
25289            } else {
25290                cx.theme().colors().text
25291            },
25292            font_family: settings.buffer_font.family.clone(),
25293            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25294            font_size: settings.buffer_font_size(cx).into(),
25295            font_weight: settings.buffer_font.weight,
25296            line_height: relative(settings.buffer_line_height.value()),
25297            ..Default::default()
25298        };
25299        EditorElement::new(
25300            &self.prompt,
25301            EditorStyle {
25302                background: cx.theme().colors().editor_background,
25303                local_player: cx.theme().players().local(),
25304                text: text_style,
25305                ..Default::default()
25306            },
25307        )
25308    }
25309}
25310
25311impl Render for BreakpointPromptEditor {
25312    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25313        let editor_margins = *self.editor_margins.lock();
25314        let gutter_dimensions = editor_margins.gutter;
25315        h_flex()
25316            .key_context("Editor")
25317            .bg(cx.theme().colors().editor_background)
25318            .border_y_1()
25319            .border_color(cx.theme().status().info_border)
25320            .size_full()
25321            .py(window.line_height() / 2.5)
25322            .on_action(cx.listener(Self::confirm))
25323            .on_action(cx.listener(Self::cancel))
25324            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25325            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25326    }
25327}
25328
25329impl Focusable for BreakpointPromptEditor {
25330    fn focus_handle(&self, cx: &App) -> FocusHandle {
25331        self.prompt.focus_handle(cx)
25332    }
25333}
25334
25335fn all_edits_insertions_or_deletions(
25336    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25337    snapshot: &MultiBufferSnapshot,
25338) -> bool {
25339    let mut all_insertions = true;
25340    let mut all_deletions = true;
25341
25342    for (range, new_text) in edits.iter() {
25343        let range_is_empty = range.to_offset(snapshot).is_empty();
25344        let text_is_empty = new_text.is_empty();
25345
25346        if range_is_empty != text_is_empty {
25347            if range_is_empty {
25348                all_deletions = false;
25349            } else {
25350                all_insertions = false;
25351            }
25352        } else {
25353            return false;
25354        }
25355
25356        if !all_insertions && !all_deletions {
25357            return false;
25358        }
25359    }
25360    all_insertions || all_deletions
25361}
25362
25363struct MissingEditPredictionKeybindingTooltip;
25364
25365impl Render for MissingEditPredictionKeybindingTooltip {
25366    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25367        ui::tooltip_container(cx, |container, cx| {
25368            container
25369                .flex_shrink_0()
25370                .max_w_80()
25371                .min_h(rems_from_px(124.))
25372                .justify_between()
25373                .child(
25374                    v_flex()
25375                        .flex_1()
25376                        .text_ui_sm(cx)
25377                        .child(Label::new("Conflict with Accept Keybinding"))
25378                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25379                )
25380                .child(
25381                    h_flex()
25382                        .pb_1()
25383                        .gap_1()
25384                        .items_end()
25385                        .w_full()
25386                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25387                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25388                        }))
25389                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25390                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25391                        })),
25392                )
25393        })
25394    }
25395}
25396
25397#[derive(Debug, Clone, Copy, PartialEq)]
25398pub struct LineHighlight {
25399    pub background: Background,
25400    pub border: Option<gpui::Hsla>,
25401    pub include_gutter: bool,
25402    pub type_id: Option<TypeId>,
25403}
25404
25405struct LineManipulationResult {
25406    pub new_text: String,
25407    pub line_count_before: usize,
25408    pub line_count_after: usize,
25409}
25410
25411fn render_diff_hunk_controls(
25412    row: u32,
25413    status: &DiffHunkStatus,
25414    hunk_range: Range<Anchor>,
25415    is_created_file: bool,
25416    line_height: Pixels,
25417    editor: &Entity<Editor>,
25418    _window: &mut Window,
25419    cx: &mut App,
25420) -> AnyElement {
25421    h_flex()
25422        .h(line_height)
25423        .mr_1()
25424        .gap_1()
25425        .px_0p5()
25426        .pb_1()
25427        .border_x_1()
25428        .border_b_1()
25429        .border_color(cx.theme().colors().border_variant)
25430        .rounded_b_lg()
25431        .bg(cx.theme().colors().editor_background)
25432        .gap_1()
25433        .block_mouse_except_scroll()
25434        .shadow_md()
25435        .child(if status.has_secondary_hunk() {
25436            Button::new(("stage", row as u64), "Stage")
25437                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25438                .tooltip({
25439                    let focus_handle = editor.focus_handle(cx);
25440                    move |_window, cx| {
25441                        Tooltip::for_action_in(
25442                            "Stage Hunk",
25443                            &::git::ToggleStaged,
25444                            &focus_handle,
25445                            cx,
25446                        )
25447                    }
25448                })
25449                .on_click({
25450                    let editor = editor.clone();
25451                    move |_event, _window, cx| {
25452                        editor.update(cx, |editor, cx| {
25453                            editor.stage_or_unstage_diff_hunks(
25454                                true,
25455                                vec![hunk_range.start..hunk_range.start],
25456                                cx,
25457                            );
25458                        });
25459                    }
25460                })
25461        } else {
25462            Button::new(("unstage", row as u64), "Unstage")
25463                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25464                .tooltip({
25465                    let focus_handle = editor.focus_handle(cx);
25466                    move |_window, cx| {
25467                        Tooltip::for_action_in(
25468                            "Unstage Hunk",
25469                            &::git::ToggleStaged,
25470                            &focus_handle,
25471                            cx,
25472                        )
25473                    }
25474                })
25475                .on_click({
25476                    let editor = editor.clone();
25477                    move |_event, _window, cx| {
25478                        editor.update(cx, |editor, cx| {
25479                            editor.stage_or_unstage_diff_hunks(
25480                                false,
25481                                vec![hunk_range.start..hunk_range.start],
25482                                cx,
25483                            );
25484                        });
25485                    }
25486                })
25487        })
25488        .child(
25489            Button::new(("restore", row as u64), "Restore")
25490                .tooltip({
25491                    let focus_handle = editor.focus_handle(cx);
25492                    move |_window, cx| {
25493                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25494                    }
25495                })
25496                .on_click({
25497                    let editor = editor.clone();
25498                    move |_event, window, cx| {
25499                        editor.update(cx, |editor, cx| {
25500                            let snapshot = editor.snapshot(window, cx);
25501                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25502                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25503                        });
25504                    }
25505                })
25506                .disabled(is_created_file),
25507        )
25508        .when(
25509            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25510            |el| {
25511                el.child(
25512                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25513                        .shape(IconButtonShape::Square)
25514                        .icon_size(IconSize::Small)
25515                        // .disabled(!has_multiple_hunks)
25516                        .tooltip({
25517                            let focus_handle = editor.focus_handle(cx);
25518                            move |_window, cx| {
25519                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25520                            }
25521                        })
25522                        .on_click({
25523                            let editor = editor.clone();
25524                            move |_event, window, cx| {
25525                                editor.update(cx, |editor, cx| {
25526                                    let snapshot = editor.snapshot(window, cx);
25527                                    let position =
25528                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25529                                    editor.go_to_hunk_before_or_after_position(
25530                                        &snapshot,
25531                                        position,
25532                                        Direction::Next,
25533                                        window,
25534                                        cx,
25535                                    );
25536                                    editor.expand_selected_diff_hunks(cx);
25537                                });
25538                            }
25539                        }),
25540                )
25541                .child(
25542                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25543                        .shape(IconButtonShape::Square)
25544                        .icon_size(IconSize::Small)
25545                        // .disabled(!has_multiple_hunks)
25546                        .tooltip({
25547                            let focus_handle = editor.focus_handle(cx);
25548                            move |_window, cx| {
25549                                Tooltip::for_action_in(
25550                                    "Previous Hunk",
25551                                    &GoToPreviousHunk,
25552                                    &focus_handle,
25553                                    cx,
25554                                )
25555                            }
25556                        })
25557                        .on_click({
25558                            let editor = editor.clone();
25559                            move |_event, window, cx| {
25560                                editor.update(cx, |editor, cx| {
25561                                    let snapshot = editor.snapshot(window, cx);
25562                                    let point =
25563                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25564                                    editor.go_to_hunk_before_or_after_position(
25565                                        &snapshot,
25566                                        point,
25567                                        Direction::Prev,
25568                                        window,
25569                                        cx,
25570                                    );
25571                                    editor.expand_selected_diff_hunks(cx);
25572                                });
25573                            }
25574                        }),
25575                )
25576            },
25577        )
25578        .into_any_element()
25579}
25580
25581pub fn multibuffer_context_lines(cx: &App) -> u32 {
25582    EditorSettings::try_get(cx)
25583        .map(|settings| settings.excerpt_context_lines)
25584        .unwrap_or(2)
25585        .min(32)
25586}